The concept is to encapsulate all the information needed to call a method (usually of another object) at a later time.
A Command only provides a method execute() to trigger its logic. Its design is simplistic and yet powerful.
With Composition, Commands can be designed to model Macros (i.e. chain of commands).
With Memento, Commands could survive crashes and reload previous states from a storage.
When combined with event processing, Commands become Routed Commands.
The closest class (rather interface) in the Java language is Callable<T>. The only difference is that Callable.call() returns a value, but it can be called synchronously or asynchronously just like a Command.
I'll present here some less known patterns and their usefulness in a Command Pattern context.
Retry Pattern
The Command Pattern is well suited to be used with retry strategies, as long as the Command.execute() is idempotent (i.e. multiple calls would yield the same result as just one call).
A Retry Command could itself encapsulate all the retry logic to call another Command.
If the Command fails and throws an exception, the RetryCommand could decide based on the exception and other variables if a retry is suited to the situation.
![]() | |
|
The Retry logic is as follows:
int oExecutions = 0;
while(true) {
try {
oExecutions++;
mCommand.execute();
break;
} catch (Throwable t) {
if (!mRetryStrategy.shouldRetry(mCommand, oExecutions - 1, t)) throw t;
mRetryStrategy.pauseBeforeNextRetry(mCommand, oExecutions - 1, t);
}
}
The RetryCommand will try to execute the concrete command mCommand. If an exception is thrown (like an IOException), it will be caught. The Retry Strategy will then decide whether or not a retry makes sense based on the command, the number of retries so far (retry = executions - 1) and the exception itself.
If a retry should not happen, the exception is re-thrown.
Otherwise, the Retry Strategy will pause (or not) before the next execution.
Circuit Breaker Pattern
Sometimes, it is pointless to keep trying executing some code that is bound to fail.
One example is when the network connection is down, sending HTTP requests one after another won't help.
The Circuit Breaker pattern allows logic to be "open" and prevent threads from executing code that is bound to fail. The Circuit Breaker is thus said to protect execution of code in such cases. These cases could be:
- Throttling from end server
- Remote service unavailable
- Operations timeout
- etc.
When designed as a Command, the Circuit Breaker can protect calls to a concrete Command.
![]() | |
|
The logic is as follows:
if (mCircuitBreaker.isClosed()) {
try {
mCommand.execute();
} catch (Throwable t) {
mCircuitBreaker.trip(t);
throw t;
}
} else {
// Circuit breaker is open
// circuit breaker open strategy...
}
When a Circuit Breaker is open, further calls to Command.execute() will be prevented.
The strategy behind this prevention can be any of:
- Manual intervention: user action is needed to reset the Circuit Breaker and close it
- Time based: Circuit Breaker could reset itself after a certain amount of time
- Test methods: Circuit Breaker could let a single thread run a test method (or the Command.execute()) once in a while. When successful, the state of the Circuit Breaker would be reset. In this case, the concrete Command must be idempotent.
Supervisor Command Pattern
A Supervisor Command will monitor the execution of a concrete command and abort that very same command if it's taking too long to execute. It's more of an algorithm than a pattern as the pattern simply follows the Proxy Pattern and adds some time-sensitive logic to its execution.
The activity of a supervisor is as follows.
![]() | |
|
Fail-fast, Retry & Protect (FRP)
By combining a Circuit Breaker, a Retry and a Supervisor we can yield the following properties
- Retrying execution when temporary failure is detected
- Protect execution when more permanent failure is detected
- Fail fast when execution is taking more time than it really should
Usage
Basic usage of FRP is in web services clients. When dealing with a remote service, all sorts of things can happen. The Retry Command will retry sending requests to survive hiccups and Circuit Breaker will prevent socket connection, network resolution and timeout to happen when tripped.
Care should be taken regarding exceptions. Depending on the implementation of the Circuit Break when it's in open state, it might throw a lot of exceptions: if n is the number of thread going through the CB while open, n exceptions will be thrown. So if we have 1000 threads, that's 1000 exceptions (ouch!).
Command Pattern Variant: Command<T>
This is a variant of the Command Pattern. The design of the original Command dictates no results in execute(). While this variant still encapsulates all the logic of executing a method, its execute() method can return a result.
It can still be used as a regular Command by returning Void and/or just disregarding any result returned. We can put those Command<Void> in queues or such for later execution, like one could do with the original Command Pattern.
The idea behind Command<T> is to provide a more flexible pattern so one could use the same pattern for different purposes without having a Command interface and another CommandWithResult interface in the same application.
The possibility of a result for execute() provides some added benefits as I'll discuss later on.
Results: Async vs Async
When a Client wants to get results out of asynchronous execution of a method, there are 2 options:
- "push" (aka Hollywood's "don't call me I'll call you") approach where results are passed to a callback method when ready. The Client has thus no control over when the results will be available. Implementing a timeout is also very problematic.
- "pull" approach where the Client explicitly wait for results to become available. A timeout could be specified too to give up and move on if results take too long to come.
Command<T> == Callable<T>
With the original Command Pattern where execute() is void, if a client needed to be able to get results out of the execution of a Command, one would need to encapsulate a callback method and use it inside execute() when results are available.
This approach restricts the Client to follow the "push" approach of asynchronous results.
It's possible to provide a more flexible pattern where the Client can choose to use either "push" or "pull".
AsyncCommand<T>
The AsyncCommand provides a way to execute a Command<T> asynchronously and pick an asynchronous results approach best suited to the situation.
The result of execute() for this command is a IAsyncResult<T>. Upon return of an IAsyncResult<T>, a client can either set a callback ("push" approach), or call get() to retreive results when available ("pull" approach).
This is only possible because the Command<T> returns a result from its execute() method.
This is a sample of how to use the "push"/Callaback approach, given a concrete Command returning an Integer.
ExecutorService oExecutorService = Executors.newFixedThreadPool(3);
ICommand<Integer> oImpl = new ICommand<Integer>() {
private Random mRandom = new Random();
@Override
public Integer execute() throws Exception {
Thread.sleep(mRandom.nextInt(30) * 100);
return mRandom.nextInt();
}
};
AsyncCommand<Integer> oAsyncCmd = new AsyncCommand<Integer>(oExecutorService, oImpl);
Callback<Integer> oCallback = new Callback<Integer>() {
@Override
public void callback(Integer pResult) {
System.out.println(Thread.currentThread().getName() + " : callback(" + pResult + ").");
}
};
IAsyncResult<Integer> oAsyncResult = oAsyncCmd.execute();
oResultHolder.setCallback(oCallback);
System.out.println(Thread.currentThread().getName() + ": could do something here...");
oAsyncResult.get(); // Called here only to make sure the callback has been called. Could put thread to sleep too.
System.out.println(Thread.currentThread().getName() + ": done waiting.");
The following is a sample showing usage of "pull"/Future approach, given the same concrete Command returning an Integer.
ExecutorService oExecutorService = Executors.newFixedThreadPool(3);
ICommand<Integer> oImpl = new ICommand<Integer>() {
private Random mRandom = new Random();
@Override
public Integer execute() throws Exception {
Thread.sleep(mRandom.nextInt(30) * 100);
return mRandom.nextInt();
}
};
AsyncCommand<Integer> oAsyncCmd = new AsyncCommand<Integer>(oExecutorService, oImpl);
IAsyncResult<Integer> oAsyncResult = oAsyncCmd.execute();
System.out.println(Thread.currentThread().getName() + ": could do something here...");
Integer oFinalResult = oAsyncResult.get();
System.out.println(Thread.currentThread().getName() + ": done waiting: " + oFinalResult);
Conclusion
The Command<T> Pattern provides flexibility over the original Command Pattern. It can be used as a regular Command and the Retry and Circuit Breaker Patterns still apply here. The AsyncCommand allows a developer to choose the best approach to asynchronous results for her needs. And all that using the same Command<T> interface.
References
[1] Prefer Using Futures or Callbacks to Communicate Asynchronous Results, Dr. Dobbs
[2] Prefer Futures to Baked-In "Async APIs", Dr. Dobbs
[3] Circuit Breaker Pattern, MSDN
[4] Source code, Github
[5] Understanding Routed Events and Commands In WPF, MSDN




No comments:
Post a Comment