/* * Copyright (C) 2006-2016 DLR, Germany * * All rights reserved * * http://www.rcenvironment.de/ */ package de.rcenvironment.core.component.workflow.execution.internal; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import de.rcenvironment.core.component.workflow.execution.api.WorkflowExecutionContext; import de.rcenvironment.core.utils.common.StringUtils; import de.rcenvironment.core.utils.incubator.DebugSettings; import de.rcenvironment.toolkit.modules.concurrency.api.TaskDescription; /** * Checks in periodically if heartbeat of workflow-related components were received and announce any lost. * * @author Doreen Seider */ public class ComponentLostWatcher implements Runnable { /** * After 140 seconds without heartbeat from component, the workflow will fail. */ public static final int DEFAULT_MAX_HEA7RTBEAT_INTERVAL_MSEC = 140 * 1000; protected static int maxHeartbeatIntervalMsec = DEFAULT_MAX_HEA7RTBEAT_INTERVAL_MSEC; private static final Log LOG = LogFactory.getLog(WorkflowExecutionControllerImpl.class); private static final boolean VERBOSE_LOGGING = DebugSettings.getVerboseLoggingEnabled(ComponentLostWatcher.class); private final Map<String, Long> componentHeartbeatTimestamps = Collections.synchronizedMap(new HashMap<String, Long>()); private final ComponentStatesChangedEntirelyVerifier compStatesEntirelyChangedVerifier; private final String logMessage; public ComponentLostWatcher(ComponentStatesChangedEntirelyVerifier compStatesEntirelyChangedVerifier, WorkflowExecutionContext wfExeCtx) { this.compStatesEntirelyChangedVerifier = compStatesEntirelyChangedVerifier; logMessage = StringUtils.format("Checking component heartbeats for workflow '%s' (%s)", wfExeCtx.getInstanceName(), wfExeCtx.getExecutionIdentifier()); } /** * Announce a new component heartbeat. * * @param compExecutionId execution identifier of component the heartbeat belongs to */ public void announceComponentHeartbeat(String compExecutionId) { componentHeartbeatTimestamps.put(compExecutionId, System.currentTimeMillis()); } @Override @TaskDescription("Check heartbeats of components") public void run() { if (VERBOSE_LOGGING) { LOG.debug(logMessage); } long currentTimestamp = System.currentTimeMillis(); Set<String> compExeIdsLost = new HashSet<>(); synchronized (componentHeartbeatTimestamps) { for (String compExeId : componentHeartbeatTimestamps.keySet()) { if (currentTimestamp - componentHeartbeatTimestamps.get(compExeId) > maxHeartbeatIntervalMsec && !compStatesEntirelyChangedVerifier.isComponentInFinalState(compExeId)) { compExeIdsLost.add(compExeId); } } } if (!compExeIdsLost.isEmpty()) { compStatesEntirelyChangedVerifier.announceLostComponents(compExeIdsLost); } } }