/*
* Copyright 2016-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package com.facebook.buck.cli;
import java.time.Duration;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
/** A background task in the buck daemon that kills the daemon after it's been idle for a while. */
@ThreadSafe
final class IdleKiller {
interface CommandExecutionScope extends AutoCloseable {
@Override
void close();
}
private final ScheduledExecutorService scheduledExecutorService;
private final Duration idleKillDelay;
private final Runnable killTask;
private @Nullable ScheduledFuture<?> idleKillTask;
private int activeCommands;
IdleKiller(
ScheduledExecutorService scheduledExecutorService,
Duration idleKillDelay,
Runnable killTask) {
this.scheduledExecutorService = scheduledExecutorService;
this.idleKillDelay = idleKillDelay;
this.killTask = killTask;
}
synchronized CommandExecutionScope newCommandExecutionScope() {
activeCommands++;
clearIdleKillTask(); // Cancel any pending kill tasks as we are no longer idle.
return () -> {
synchronized (IdleKiller.this) {
activeCommands--;
if (activeCommands == 0) { // Schedule a kill task since we are once again idle.
setIdleKillTask();
}
}
};
}
/** Clear any existing kill tasks. */
private void clearIdleKillTask() {
if (idleKillTask != null) {
idleKillTask.cancel(false);
idleKillTask = null;
}
}
/** Clear any existing kill tasks and set up a new kill task to fire after idle delay. */
private void setIdleKillTask() {
clearIdleKillTask();
idleKillTask =
scheduledExecutorService.schedule(
killTask, idleKillDelay.toMillis(), TimeUnit.MILLISECONDS);
}
}