Arjen Smits recently submitted a patch for Agatha which makes it possible to send One-Way (aka Fire And Forget) requests to an Agatha service layer. As you know, Agatha is a Request/Response framework where each Request sent to the service layer will receive a corresponding Response. A One-Way request doesn’t have a response however. It can be very useful when you just need the service layer to do something where the client that sent the request doesn’t need a response, and thus, shouldn’t have to wait for it.
The biggest benefit here is that client can simply send a One-Way request to the service layer, and instead of waiting for the service layer to process it, the call to the service layer will return immediately. You could achieve similar behavior by using the asynchronous service proxy and supplying an empty delegate to be called after the response was received. The downside of that is obviously that the communication channel between the client and the server would remain in use throughout the handling of the request, only to return a response later on that will be ignored anyway. Sending a One-Way request avoids this kind of waste.
Let’s see how we can use One-Way requests with Agatha.
First of all, you will need to create a Request class which inherits from Agatha’s OneWayRequest class:
public abstract class OneWayRequest : Request
{
}
Normally you’d also create a corresponding Response type for your Request type, but for Requests that inherit from OneWayRequest that’s useless. You’ll also need to create a Request Handler which inherits from Agatha’s OneWayRequestHandler class:
public abstract class OneWayRequestHandler<TRequest> : OneWayRequestHandler, IOneWayRequestHandler<TRequest> where TRequest : OneWayRequest
{
public override void Handle(OneWayRequest request)
{
var typedRequest = (TRequest) request;
BeforeHandle(typedRequest);
Handle(typedRequest);
AfterHandle(typedRequest);
}
public virtual void BeforeHandle(TRequest request) { }
public virtual void AfterHandle(TRequest request) { }
public abstract void Handle(TRequest request);
}
This is very similar to a regular RequestHandler, except that there’s no way for you to return a response. Simply inherit from this class, implement the Handle(TRequest) method to perform whatever it is that you need to do and that’s it as far as the service layer is concerned. If you want to, you can (as always) override the BeforeHandle and AfterHandle methods to add some extra stuff. If you don’t want to inherit from this OneWayRequestHandler class, you can just as well create a class which implements Agatha’s IOneWayRequestHandler<TRequest> interface. Your One Way Request Handlers will be picked up and registered by Agatha automatically, just as it does with regular Request Handlers.
As for sending One Way Requests to your service layer, you can do that with both the synchronous IRequestDispatcher and the IAsyncRequestDispatcher. The IRequestDispatcher interface now looks like this:
public interface IRequestDispatcher : IDisposable
{
IEnumerable<Response> Responses { get; }
void Add(Request request);
void Add(params Request[] requestsToAdd);
void Add(string key, Request request);
void Send(params OneWayRequest[] oneWayRequests);
bool HasResponse<TResponse>() where TResponse : Response;
TResponse Get<TResponse>() where TResponse : Response;
TResponse Get<TResponse>(string key) where TResponse : Response;
TResponse Get<TResponse>(Request request) where TResponse : Response;
void Clear();
}
Sending OneWayRequests can be done through the Send method, which will immediately send the given OneWayRequests to the service layer and the call will return as soon as the requests have been transmitted. This means that this call will block for a short time until the requests have actually been sent. It will return before the requests are actually processed by the service layer however.
The IAsyncRequestDispatcher now looks like this:
public interface IAsyncRequestDispatcher : IDisposable
{
void Add(Request request);
void Add(params Request[] requestsToAdd);
void Add(string key, Request request);
void Add(params OneWayRequest[] oneWayRequests);
void ProcessOneWayRequests();
void ProcessRequests(Action<ReceivedResponses> receivedResponsesDelegate, Action<ExceptionInfo> exceptionOccurredDelegate);
void ProcessRequests(Action<ReceivedResponses> receivedResponsesDelegate, Action<ExceptionInfo, ExceptionType> exceptionAndTypeOccurredDelegate);
}
You can add your OneWayRequest through the correct Add method, and then have them processed by the server by calling the ProcessOneWayRequests method. This call will not block and will return immediately. That means that it won’t wait until the requests have actually been sent to the server like it does with the IRequestDispatcher.