/*
* Copyright to the original author or authors.
*
* 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 org.rioproject.monitor.service.managers;
import org.rioproject.admin.ServiceActivityProvider;
import org.rioproject.impl.util.ThrowableUtil;
import org.rioproject.monitor.service.channel.ServiceChannel;
import org.rioproject.monitor.service.channel.ServiceChannelEvent;
import org.rioproject.monitor.service.util.LoggingUtil;
import org.rioproject.opstring.ServiceElement;
import org.rioproject.util.TimeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Monitors idle services.
*
* @author Dennis Reedy
*/
public class IdleServiceManager {
private final Map<ServiceActivityProvider, Long> activityMap = new ConcurrentHashMap<ServiceActivityProvider, Long>();
private final Long maxIdleTime;
private final ServiceElement serviceElement;
private final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
private static final Logger logger = LoggerFactory.getLogger(IdleServiceManager.class);
public IdleServiceManager(final Long maxIdleTime, final ServiceElement serviceElement) {
this.maxIdleTime = maxIdleTime;
this.serviceElement = serviceElement;
long delay = TimeUtil.computeLeaseRenewalTime(maxIdleTime);
if(logger.isDebugEnabled()) {
logger.debug("Service [{}] idle time: {}, computed delay time for checking idle status: {}.",
LoggingUtil.getLoggingName(serviceElement), TimeUtil.format(maxIdleTime), TimeUtil.format(delay));
}
scheduledExecutorService.scheduleWithFixedDelay(new IdleChecker(delay), delay, delay, TimeUnit.MILLISECONDS);
}
public void addService(final ServiceActivityProvider service) {
activityMap.put(service, 0L);
}
public void removeService(final ServiceActivityProvider service) {
activityMap.remove(service);
}
public void terminate() {
scheduledExecutorService.shutdownNow();
}
private class IdleChecker implements Runnable {
final long delay;
IdleChecker(long delay) {
this.delay = delay;
}
public void run() {
try {
long now = System.currentTimeMillis();
List<ServiceActivityProvider> idleServices = new ArrayList<ServiceActivityProvider>();
for (Map.Entry<ServiceActivityProvider, Long> entry : activityMap.entrySet()) {
try {
if (!entry.getKey().isActive()) {
Long value = entry.getValue();
if (value == 0) {
value = System.currentTimeMillis();
}
if ((now - value) > maxIdleTime) {
idleServices.add(entry.getKey());
} else {
activityMap.put(entry.getKey(), value);
}
} else {
activityMap.put(entry.getKey(), 0L);
}
} catch (IOException e) {
logger.warn("Unable to get activity from service", e);
if (!ThrowableUtil.isRetryable(e)) {
idleServices.add(entry.getKey());
}
}
}
int count = Math.max(serviceElement.getPlanned(), activityMap.size());
if (idleServices.size() == count) {
logger.info("Service [{}] has {} / {} idle instances. Notify for undeploy.",
LoggingUtil.getLoggingName(serviceElement),
idleServices.size(),
count);
ServiceChannel.getInstance().broadcast(new ServiceChannelEvent(this,
serviceElement,
ServiceChannelEvent.Type.IDLE));
for (ServiceActivityProvider remove : idleServices) {
removeService(remove);
}
} else {
logger.info("Service [{}] has {} / {} idle instances. Next check in {}.",
LoggingUtil.getLoggingName(serviceElement),
idleServices.size(),
serviceElement.getPlanned(),
TimeUtil.format(delay));
}
} catch (Exception e) {
logger.warn("Caught while determining service [{}] idle", LoggingUtil.getLoggingName(serviceElement), e);
}
}
}
}