Last active
February 16, 2016 01:46
-
-
Save vladdu/b8af7709e26206b1832b to your computer and use it in GitHub Desktop.
Guava RestartableService
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class CooldownRestartPolicy extends ServiceRestartPolicy { | |
/** | |
* If restarting sooner than this, it's probably an unrecoverable error. | |
*/ | |
public static final int RESTART_INTERVAL = 5000; | |
private long last; | |
private long interval = RESTART_INTERVAL; | |
public CooldownRestartPolicy() { | |
this(RESTART_INTERVAL); | |
} | |
public CooldownRestartPolicy(final long interval) { | |
this.interval = interval; | |
last = System.currentTimeMillis(); | |
} | |
@Override | |
public void notifyRestart() { | |
last = System.currentTimeMillis(); | |
} | |
@Override | |
public boolean shouldRestart() { | |
return System.currentTimeMillis() - last > interval; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public abstract class ServiceRestartPolicy { | |
/** | |
* Policy might want to keep track of when the latest restarts have | |
* happened. | |
*/ | |
public void notifyRestart() { | |
} | |
abstract public boolean shouldRestart(); | |
} | |
import java.util.Map; | |
import java.util.Map.Entry; | |
import java.util.concurrent.Executor; | |
import java.util.concurrent.TimeUnit; | |
import java.util.concurrent.TimeoutException; | |
import org.erlide.util.services.Provider; | |
import com.google.common.collect.Maps; | |
import com.google.common.util.concurrent.MoreExecutors; | |
import com.google.common.util.concurrent.Service; | |
public class RestartableService implements Service { | |
private Service delegate; | |
private final ServiceRestartPolicy policy; | |
private final Provider<Service> factory; | |
private final Map<Listener, Executor> listeners; | |
public RestartableService(final Provider<Service> factory, | |
final ServiceRestartPolicy policy) { | |
this.factory = factory; | |
this.policy = policy; | |
listeners = Maps.newHashMap(); | |
} | |
private final class RestartListener extends Listener { | |
@Override | |
public void failed(final State from, final Throwable failure) { | |
if (policy.shouldRestart()) { | |
startAsync(); | |
} else { | |
for (final Entry<Listener, Executor> l : listeners.entrySet()) { | |
l.getKey().failed(from, failure); | |
} | |
} | |
} | |
@Override | |
public void starting() { | |
for (final Entry<Listener, Executor> l : listeners.entrySet()) { | |
l.getKey().starting(); | |
} | |
} | |
@Override | |
public void running() { | |
for (final Entry<Listener, Executor> l : listeners.entrySet()) { | |
l.getKey().running(); | |
} | |
} | |
@Override | |
public void stopping(final Service.State from) { | |
for (final Entry<Listener, Executor> l : listeners.entrySet()) { | |
l.getKey().stopping(from); | |
} | |
} | |
@Override | |
public void terminated(final State from) { | |
for (final Entry<Listener, Executor> l : listeners.entrySet()) { | |
l.getKey().terminated(from); | |
} | |
} | |
} | |
/** | |
* Used for testing only. | |
* | |
* @return delegate | |
*/ | |
public Service getDelegate() { | |
return delegate; | |
} | |
@Override | |
public Service startAsync() { | |
delegate = factory.get(); | |
delegate.addListener(new RestartListener(), MoreExecutors.sameThreadExecutor()); | |
delegate.startAsync(); | |
policy.notifyRestart(); | |
return this; | |
} | |
@Override | |
public boolean isRunning() { | |
return delegate.isRunning(); | |
} | |
@Override | |
public State state() { | |
return delegate.state(); | |
} | |
@Override | |
public Service stopAsync() { | |
delegate.stopAsync(); | |
return this; | |
} | |
@Override | |
public void awaitRunning() { | |
delegate.awaitRunning(); | |
} | |
@Override | |
public void awaitRunning(final long timeout, final TimeUnit unit) | |
throws TimeoutException { | |
delegate.awaitRunning(timeout, unit); | |
} | |
@Override | |
public void awaitTerminated() { | |
delegate.awaitTerminated(); | |
} | |
@Override | |
public void awaitTerminated(final long timeout, final TimeUnit unit) | |
throws TimeoutException { | |
delegate.awaitTerminated(timeout, unit); | |
} | |
@Override | |
public Throwable failureCause() { | |
return delegate.failureCause(); | |
} | |
@Override | |
public void addListener(final Listener listener, final Executor executor) { | |
synchronized (listeners) { | |
listeners.put(listener, executor); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public abstract class ServiceRestartPolicy { | |
/** | |
* Policy might want to keep track of when the latest restarts have | |
* happened. | |
*/ | |
public void notifyRestart() { | |
} | |
abstract public boolean shouldRestart(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://gist.github.com/vladdu/b8af7709e26206b1832b#file-restartableservice-java-L145
Is there any reason why you don't just add this listener to the delegate instance?
https://gist.github.com/vladdu/b8af7709e26206b1832b#file-restartableservice-java-L27
Also, why do you not run the listener callback on the executor passed?
https://gist.github.com/vladdu/b8af7709e26206b1832b#file-restartableservice-java-L46