/******************************************************************************* * Copyright (c) 2012 VMWare, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VMWare, Inc. - initial API and implementation *******************************************************************************/ package org.grails.ide.eclipse.runtime.shared.longrunning; /** * If this class is instantiated, it will start a thread monitoring the 'heartBeat'. Clients implementing * a process typically subclass this and call the heartBeat method on a regular basis when they are * 'alive'. * <p> * If the heartBeat isn't called for some time, then the HeartBeatMonitor thread will call System.exit * automatically. * * @since 2.6 * @author Kris De Volder */ public class SafeProcess { /** * Time recorded each time the 'heartBeat' method is called. */ private long lastHeartBeat; /** * A process that is 'alive' (being used on a fairly regular basis) should be calling * this method once every so often. */ public synchronized void heartBeat() { lastHeartBeat = System.currentTimeMillis(); } private boolean hasRecentHeartBeat() { return System.currentTimeMillis()-getLastHeartBeat() < MAX_IDLE_TIME; } private synchronized long getLastHeartBeat() { return lastHeartBeat; } /** * Thread monitoring the process' heartBeat. If there's no heartbeat will call System.exit */ public class HeartBeatMonitor extends Thread { /** * Extra time added to 'sleep' time to avoid waking thread 'just before death'. */ final long MARGIN_FOR_ERROR = 500; public HeartBeatMonitor() { setDaemon(true); } @Override public void run() { while (true) { sleep(); if (!hasRecentHeartBeat()) { System.exit(-99); } } } /** * Try to sleep as long as possible (i.e. until the earliest time this * process could be considered 'dead'. */ private void sleep() { long waitFor = MAX_IDLE_TIME - (System.currentTimeMillis() - getLastHeartBeat()); if (waitFor > 0) { try { sleep(waitFor+MARGIN_FOR_ERROR); } catch (InterruptedException e) { //Ignore } } } } private static final int MINUTES = 60 * 1000; /** * As a safety precaution to avoid runaway rogue processes, GrailsProcess will terminate if * it hasn't been asked to execute any commands for this amount of time. */ public static final long MAX_IDLE_TIME = 20 * MINUTES; }