Lagom: Asynchronous Operations in Command Handlers - scala

In Lagom, what do you do when a command handler must perform some asynchronous operations? For example:
override def behavior = Actions().onCommand[MyCommand, Done] {
case (cmd, ctx, state) =>
// some complex code that performs asynchronous operations
// (for example, querying other persistent entities or the read-side
// by making calls that return Future[...] and composing those),
// as summarized in a placeholder below:
val events: Future[Seq[Event]] = ???
events map {
xs => ctx.thenPersistAll(xs: _*) { () => ctx.reply(Done) }
}
}
The problem with the code like that is that the compiler expects the command handler to return Persist, not Future[Persist].
Is this done on purpose, to make sure that the events are persisted in the correct order (that is, the events generated by a prior command must be saved before the events generated by a later command)? But can't that be handled by proper management of the event offsets, so that the journal always orders them correctly, regardless of when they are actually saved?
And what does one do in situations like this, when the command handling is complex enough to require making asynchronous calls from the command handler?

There is a similar question on the mailing list with an answer from James.
https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!topic/lagom-framework/Z6lynjNTqgE
In short, your entity in a CQRS application is a consistency boundary and should only depend on data that it's immediately available inside it, not outside (no call to external services).
What you are probably looking for a what it's called Command Enrichment. You receive an request, collect some data from external services and build a command containing everything you need to send to your Entity.
You certainly should not query the read-side to make business decisions inside your write-side entity. You also should not make business decisions on data coming from other entities.
Your entity should be able to make all the decision because it is the consistency boundary of your model.

What I've been doing in these cases is to pass the PersistentEntityRef to the asynchronous operation, so that it can issue commands to the entity and its those command-handlers (not the one that spawned the async computation) that then persist the events.
Just bear in mind that none of this is atomic, so you have to think about what happens if the asynchronous operation fails midway through issuing the commands or if some commands succeed and some fail, etc. Presumably you'll want some retry mechanism for systemic failures. If you build your command-handlers to be idempotent, it will help you deal with the duplicates.

Related

Do we perfom queries to the event store? When and how?

I am new to event sourcing, but as fas as I have understood when we have a command use case, we instantiate an aggregate in memory, apply events to it from the event store so as to be in the correct state, make the proper changes and then store those changes back to the event store. We also have a read model store that will eventually be updated by these changes.
In my case I have a CreateUserUseCase (which is a command use case) and I want to first check if the user already exists and if the username is already taken. For example something like this:
const userAlreadyExists = await this.userRepo.exists(email);
if (userAlreadyExists) {
return new EmailAlreadyExistsError(email);
}
const alreadyCreatedUserByUserName = await this.userRepo
.getUserByUserName(username);
if (alreadyCreatedUserByUserName) {
return new UsernameTakenError(username);
}
const user = new User(username, password, email);
await this.userRepo.save(user);
So, for the save method I would use the event store and append the uncommitted events to it. What about the exists and getUserByUserName methods though? On the one hand I want to make a specific query so I could use my read model store to get the data that I need, but on the other hand this makes a contradiction with CQRS. So what do we do in these cases? Do we, in some way, perform queries to the event store? And in what way do we do this?
Thank you in advance!
CQRS shouldn't be interpreted as "don't query the write model" (because the process of determining state from the write model for the purpose of command processing entails a query, this restriction is untenable). Instead, interpret it as "it's perfectly acceptable to have a different data model for a query than the one you use for handling intentions to update". This formulation implies that if the write model is a good fit for a given query, it's OK to execute the query against the write model.
Event sourcing in turn is arguably (especially in conjunction with certain usage styles) the ultimate in data models that optimize for write vs. read and accordingly the event-sourced model makes nearly all queries outside of a fairly small set so inefficient that some form of CQRS is needed.
What query facilities an event store includes are typically limited, but the one query anything that's a suitable event store will have (because it's needed for replaying the events) is a compound query that amounts to "give me the latest snapshot for that entity and either (if the snapshot exists) the first n events after that snapshot or (if no snapshot) the first n events for that entity". The result of that query is dispositive (modulo things like retention etc.) to the question of "has this entity published events"?

HTTP GET for 'background' job creation and acquiring

I'm designing API for jobs scheduler. There is one scheduler with some set of resources and DB tables for them. Also there are multiple 'workers' that request 'jobs' from scheduler. Worker can't create job it must only request it. Job must be calculated on the server side. Also job is a dynamic entity and calculated using multiple DB tables and time. There is no 'job' table.
In general this system is very similar to task queue. But without queue. I need a method for worker to request next task. That task should be calculated and assigned for this agent.
Is it OK to use GET verb to retrieve and 'lock' job for the specific worker?
In terms of resources this query does not modify anything. Only internal DB state is updated. For client it looks like fetching records one by one. It doesn't know about internal modifications.
In pure REST style I probably should define a job table and CRUD api for it. Then I would need to create some auxilary service to POST jobs to that table. Then each agent would list jobs using GET and then lock it using PATCH. That approach requires multiple potential retries due to race-conditions. (Job can be already locked by another agent). Also it looks a little bit complicated if I need to assign job to specific agent based on server side logic. In that case I need to implement some check logic on client side to iterate through jobs based on different responces.
This approach looks complicated.
Is it OK to use GET verb to retrieve and 'lock' job for the specific worker?
Maybe? But probably not.
The important thing to understand about GET is that it is safe
The purpose of distinguishing between safe and unsafe methods is to
allow automated retrieval processes (spiders) and cache performance
optimization (pre-fetching) to work without fear of causing harm. In
addition, it allows a user agent to apply appropriate constraints on
the automated use of unsafe methods when processing potentially
untrusted content.
If aggressive cache performance optimization would make a mess in your system, then GET is not the http method you want triggering that behavior.
If you were designing your client interactions around resources, then you would probably have something like a list of jobs assigned to a worker. Reading the current representation of that resource doesn't require that a server change it, so GET is completely appropriate. And of course the server could update that resource for its own reasons at any time.
Requests to modify that resource should not be safe. For instance, if the client is going to signal that some job was completed, that should be done via an unsafe method (POST/PUT/PATCH/DELETE/...)
I don't have such resource. It's an ephymeric resource which is spread across the tables. There is no DB table for that and there is no ID column to update that job. That's another question why I don't have such table but it's current requirement and limitation.
Fair enough, though the main lesson still stands.
Another way of thinking about it is to think about failure. The network is unreliable. In a distributed environment, the client cannot distinguish a lost request from a lost response. All it knows is that it didn't receive an acknowledgement for the request.
When you use GET, you are implicitly telling the client that it is safe (there's that word again) to resend the request. Not only that, but you are also implicitly telling any intermediate components that it is safe to repeat the request.
If there are no adverse effects to handling multiple copies of the same request, the GET is fine. But if processing multiple copies of the same request is expensive, then you should probably be using POST instead.
It's not required that the GET handler be safe -- the standard only describes the semantics of the messages; it doesn't constraint the implementation at all. But any loss of property incurred is properly understood to be the responsibility of the server.

Querying a list of Actors in Azure Service Fabric

I currently have a ReliableActor for every user in the system. This actor is appropriately named User, and for the sake of this question has a Location property. What would be the recommended approach for querying Users by Location?
My current thought is to create a ReliableService that contains a ReliableDictionary. The data in the dictionary would be a projection of the User data. If I did that, then I would need to:
Query the dictionary. After GA, this seems like the recommended approach.
Keep the dictionary in sync. Perhaps through Pub/Sub or IActorEvents.
Another alternative would be to have a persistent store outside Service Fabric, such as a database. This feels wrong, as it goes against some of the ideals of using the Service Fabric. If I did, I would assume something similar to the above but using a Stateless service?
Thank you very much.
I'm personally exploring the use of Actors as the main datastore (ie: source of truth) for my entities. As Actors are added, updated or deleted, I use MassTransit to publish events. I then have Reliable Statefull Services subscribed to these events. The services receive the events and update their internal IReliableDictionary's. The services can then be queried to find the entities required by the client. Each service only keeps the entity data that it requires to perform it's queries.
I'm also exploring the use of EventStore to publish the events as well. That way, if in the future I decide I need to query the entities in a new way, I could create a new service and replay all the events to it.
These Pub/Sub methods do mean the query services are only eventually consistent, but in a distributed system, this seems to be the norm.
While the standard recommendation is definitely as Vaclav's response, if querying is the exception then Actors could still be appropriate. For me whether they're suitable or not is defined by the normal way of accessing them, if it's by key (presumably for a user record it would be) then Actors work well.
It is possible to iterate over Actors, but it's quite a heavy task, so like I say is only appropriate if it's the exceptional case. The following code will build up a set of Actor references, you then iterate over this set to fetch the actors and then can use Linq or similar on the collection that you've built up.
ContinuationToken continuationToken = null;
var actorServiceProxy = ActorServiceProxy.Create("fabric:/MyActorApp/MyActorService", partitionKey);
var queriedActorCount = 0;
do
{
var queryResult = actorServiceProxy.GetActorsAsync(continuationToken, cancellationToken).GetAwaiter().GetResult();
queriedActorCount += queryResult.Items.Count();
continuationToken = queryResult.ContinuationToken;
} while (continuationToken != null);
TLDR: It's not always advisable to query over actors, but it can be achieved if required. Code above will get you started.
if you find yourself needing to query across a data set by some data property, like User.Location, then Reliable Collections are the right answer. Reliable Actors are not meant to be queried over this way.
In your case, a user could simply be a row in a Reliable Dictionary.

Transactional batch processing with OData

Working with Web API OData, I have $batch processing working, however, the persistence to the database is not Transactional. If I include multiple requests in a Changeset in my request, and one of those items fails, the other still completes, because each separate call to the controller has it's own DbContext.
for example, if I submit a Batch with two change sets:
Batch 1
- ChangeSet 1
- - Patch valid object
- - Patch invalid object
- End Changeset 1
- ChangeSet 2
- - Insert Valid Object
- End ChangeSet 2
End Batch
I would expect that the first valid patch would be rolled back, as the change set could not be completed in its entirety, however, since each call gets its own DbContext, the first Patch is committed, the second is not, and the insert is committed.
Is there a standard way to support transactions through a $batch request with OData?
The theory: let's make sure we're talking about the same thing.
In practice: addressing the problem as far as I can (no definitive answer) could.
In practice, really (update): a canonical way of implementing the backend-specific parts.
Wait, does it solve my problem?: let's not forget that the implementation (3) is bound by the specification (1).
Alternatively: the usual "do you really need it?" (no definitive answer).
The theory
For the record, here is what the OData spec has to say about it (emphasis mine):
All operations in a change set represent a single change unit so a
service MUST successfully process and apply all the requests in the
change set or else apply none of them. It is up to the service
implementation to define rollback semantics to undo any requests
within a change set that may have been applied before another request
in that same change set failed and thereby apply this all-or-nothing
requirement. The service MAY execute the requests within a change set
in any order and MAY return the responses to the individual requests
in any order. (...)
http://docs.oasis-open.org/odata/odata/v4.0/cos01/part1-protocol/odata-v4.0-cos01-part1-protocol.html#_Toc372793753
This is V4, which barely updates V3 regarding Batch Requests, so the same considerations apply for V3 services AFAIK.
To understand this, you need a tiny bit of background:
Batch requests are sets of ordered requests and change sets.
Change Sets themselves are atomic units of work consisting of sets of unordered requests, though these requests can only be Data Modification requests (POST, PUT, PATCH, DELETE, but not GET) or Action Invocation requests.
You might raise an eyebrow at the fact that requests within change sets are unordered, and quite frankly I don't have proper rationale to offer. The examples in the spec clearly show requests referencing each other, which would imply that an order in which to process them must be deduced. In reality, my guess is that change sets must really be thought of as single requests themselves (hence the atomic requirement) that are parsed together and are possibly collapsed into a single backend operation (depending on the backend of course). In most SQL databases, we can reasonably start a transaction and apply each subrequest in a certain order defined by their interdependencies, but for some other backends, it may be required that these subrequests be mangled and made sense of together before sending any change to the platters. This would explain why they aren't required to be applied in order (the very notion might not make sense to some backends).
An implication of that interpretation is that all your change sets must be logically consistent on their own; for example you can't have a PUT and a PATCH that touch the same properties on the same change set. This would be ambiguous. It's thus the responsibility of the client to merge operations as efficiently as possible before sending the requests to the server. This should always be possible.
(I'd love someone to confirm this.) I'm now fairly confident that this is the correct interpretation.
While this may seem like an obvious good practice, it's not generally how people think of batch processing. I stress again that all of this applies to requests within change sets, not requests and change sets within batch requests (which are ordered and work pretty much as you'd expect, minus their non-atomic/non-transactional nature).
In practice
To come back to your question, which is specific to ASP.NET Web API, it seems they claim full support of OData batch requests. More information here. It also seems true that, as you say, a new controller instance is created for each subrequest (well, I take your word for it), which in turn brings a new context and breaks the atomicity requirement. So, who's right?
Well, as you rightly point out too, if you're going to have SaveChanges calls in your handlers, no amount of framework hackery will help much. It looks like you're supposed to handle these subrequests yourself with the considerations I outlined above (looking out for inconsistent change sets). Quite obviously, you'd need to (1) detect that you're processing a subrequest that is part of a changeset (so that you can conditionally commit) and (2) keep state between invocations.
Update: See next section for how to do (2) while keeping controllers oblivious to the functionality (no need for (1)). The next two paragraphs may still be of interest if you want more context on the problems that are solved by the HttpMessageHandler solution.
I don't know if you can detect whether you're in a changeset or not (1) with the current APIs they provide. I don't know if you can force ASP.NET to keep the controller alive for (2) either. What you could do for the latter however (if you can't keep it alive) is to keep a reference to the context elsewhere (for example in some kind of session state Request.Properties) and reuse it conditionally (update: or unconditionally if you manage the transaction at a higher-level, see below). I realize this is probably not as helpful as you might have hoped, but at least now you should have the right questions to direct to the developers/documentation writers of your implementation.
Dangerously rambling: Instead of conditionally calling SaveChanges, you could conditionally create and terminate a TransactionScope for every changeset. This doesn't remove the need for (1) or (2), just another way of doing things. It sort of follows that the framework could technically implement this automatically (as long as the same controller instance can be reused), but without knowing the internals enough I wouldn't revisit my statement that the framework doesn't have enough to go with to do everything itself just yet. After all, the semantics of TransactionScope might be too specific, irrelevant or even undesired for certain backends.
Update: This is indeed what the proper way of doing things look like. The next section shows a sample implementation that uses the Entity Framework explicit transaction API instead of TransactionScope, but this has the same end-result. Although I feel there are ways to make a generic Entity Framework implementation, currently ASP.NET doesn't provide any EF-specific functionality so you're required to implement this yourself. If you ever extract your code to make it reusable, please do share it outside of the ASP.NET project if you can (or convince the ASP.NET team that they should include it in their tree).
In practice, really (update)
See snow_FFFFFF's helpful answer, which references a sample project.
To put it in context of this answer, it shows how to use an HttpMessageHandler to implement requirement #2 which I outlined above (keeping state between invocations of the controllers within a single request). This works by hooking at a higher-level than controllers, and splitting the request in multiple "subrequests", all the while keeping state oblivious to the controllers (the transactions) and even exposing state to the controllers (the Entity Framework context, in this case via HttpRequestMessage.Properties). The controllers happily process each subrequest without knowing if they are normal requests, part of a batch request, or even part of a changeset. All they need to do is use the Entity Framework context in the properties of the request instead of using their own.
Note that you actually have a lot of built-in support to achieve this. This implementation builds on top of the DefaultODataBatchHandler, which builds on top of the ODataBatchHandler code, which builds on top of the HttpBatchHandler code, which is an HttpMessageHandler. The relevant requests are explicitly routed to that handler using Routes.MapODataServiceRoute.
How does this implementation map to the theory? Quite well, actually. You can see that each subrequest is either sent to be processed as-is by the relevant controller if it is an "operation" (normal request), or handled by more specific code if it is a changeset. At this level, they are processed in order, but not atomically.
The changeset handling code however does indeed wrap each of its own subrequests in a transaction (one transaction for each changeset). While the code could at this point try to figure out the order in which to execute statements in the transaction by looking at the Content-ID headers of each subrequest to build a dependency graph, this implementation takes the more straightforward approach of requiring the client to order these subrequests in the right order itself, which is fair enough.
Wait, does it solve my problem?
If you can wrap all your operations in a single changeset, then yes, the request will be transactional. If you can't, then you must modify this implementation so that it wraps the entire batch in a single transaction. While the specification supposedly doesn't preclude this, there are obvious performance considerations to take into account. You could also add a non-standard HTTP header to flag whether you want the batch request to be transactional or not, and have your implementation act accordingly.
In any case, this wouldn't be standard, and you couldn't count on it if you ever wanted to use other OData servers in an interoperable manner. To fix this, you need to argue for optional atomic batch requests to the OData committee at OASIS.
Alternatively
If you can't find a way to branch code when processing a changeset, or you can't convince the developers to provide you with a way to do so, or you can't keep changeset-specific state in any satisfactory way, then it looks like you must [you may alternatively want to] expose a brand new HTTP resource with semantics specific to the operation you need to perform.
You probably know this, and this is likely what you're trying to avoid, but this involves using DTOs (Data Transfer Objects) to populate with the data in the requests. You then interpret these DTOs to manipulate your entities within a single handler controller action and hence with full control over the atomicity of the resulting operations.
Note that some people actually prefer this approach (more process-oriented, less data-oriented), though it can be very difficult to model. There's no right answer, it always depends on the domain and use-cases, and it's easy to fall into traps that would make your API not very RESTful. It's the art of API design. Unrelated: The same remarks can be said about data modeling, which some people actually find harder. YMMV.
Summary
There's a few approaches to explore, some information to retrieve from the developers a canonical implementation technique to use, an opportunity to create a generic Entity Framework implementation, and a non-generic alternative.
It'd be nice if you could update this thread as you gather answers elsewhere (well, if you feel motivated enough) and with what you eventually decide to do, as it seems like something many people would love to have some kind of definitive guidance for.
Good luck ;).
The following link shows the Web API OData implementation that is required to process the changeset in transactions. You are correct that the default batch handler does not do this for you:
http://aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/OData/v3/ODataEFBatchSample/
UPDATE
The original link seems to have gone away - the following link includes similar logic (and for v4) for transactional processing:
https://damienbod.com/2014/08/14/web-api-odata-v4-batching-part-10/
I just learned about the TransactionScope class.
A few points I'd like to make before moving on:
The original question posited that each controller called received
its own DbContext. This isn't true. The DBContext lifetime is scoped to the entire request. Review Dependency lifetime in ASP.NET Core for
further details.
I suspect that the original poster is experiencing issues because each sub-request in the batch is invoking its assigned controller method,
and each method is calling DbContext.SaveChanges() individually - causing that unit of work to be committed.
My understanding of the
question comes from the basis of performing database transactions,
i.e. (pseudo-code for SQL expected):
BEGIN TRAN
DO SOMETHING
DO MORE THINGS
DO EVEN MORE THINGS
IF FAILURES OCCURRED ROLLBACK EVERYTHING. OTHERWISE, COMMIT EVERYTHING.
This is a reasonable request that I would expect OData to be able to perform with a single POST operation to [base URL]/odata/$batch.
Batch Execution Order Concerns
For our purposes, we may or may not necessarily care what order work is done against the DbContext. We definitely care though that the work being performed is being done as part of a batch. We want it to all succeed or all be rolled back in the database(s) being updated.
If you are using old school Web API (in other words, prior to ASP.Net Core), then your batch handler class is likely the DefaultHttpBatchHandler class. According to Microsoft's documentation here Introducing batch support in Web API and Web API OData, batch transactions using the DefaultHttpBatchHandler in OData are sequential by default. It has an ExecutionOrder property that can be set to change this behavior so that operations are performed concurrently.
If you are using ASP.Net Core, it appears we have two options:
If your batch operation is using the "old school" payload format, it
appears that batch operations are performed sequentially by default
(assuming I am interpreting the source code correctly).
ASP.Net Core provides a new option though. A new
DefaultODataBatchHandler has replaced the old DefaultHttpBatchHandler
class. Support for ExecutionOrder has been dropped in favor of adopting a
model where metadata in the payload communicates whether what batch
operations should happen in order and/or can be executed concurrently. To
utilize this feature, the request payload Content-Type is changed to
application/json and the payload itself is in JSON format (see below). Flow
control is established within the payload by adding dependency and group
directives to control execution order so that batch requests can be split
into multiple groups of individual requests that can be executed
asynchronously and in parallel where no dependencies exist, or in order where
dependencies do exist. We can take advantage of this fact and simply create
"Id", "atomicityGroup", and "DependsOn" tags in out payload to ensure
operations are performed in the appropriate order.
Transaction Control
As stated previously, your code is likely using either the DefaultHttpBatchHandler class or the DefaultODataBatchHandler class. In either case, these classes aren't sealed and we can easily derive from them to wrap the work being done in a TransactionScope. By default, if no unhandled exceptions occurred within the scope, the transaction is committed when it is disposed. Otherwise, it is rolled back:
/// <summary>
/// An OData Batch Handler derived from <see cref="DefaultODataBatchHandler"/> that wraps the work being done
/// in a <see cref="TransactionScope"/> so that if any errors occur, the entire unit of work is rolled back.
/// </summary>
public class TransactionedODataBatchHandler : DefaultODataBatchHandler
{
public override async Task ProcessBatchAsync(HttpContext context, RequestDelegate nextHandler)
{
using (TransactionScope scope = new TransactionScope( TransactionScopeAsyncFlowOption.Enabled))
{
await base.ProcessBatchAsync(context, nextHandler);
}
}
}
Just replace your default class with an instance of this one and you are good to go!
routeBuilder.MapODataServiceRoute("ODataRoutes", "odata",
modelBuilder.GetEdmModel(app.ApplicationServices),
new TransactionedODataBatchHandler());
Controlling Execution Order in the ASP.Net Core POST to Batch Payload
The payload for the ASP.Net Core batch handler uses "Id", "atomicityGroup", and "DependsOn" tags to control execution order of the sub-requests. We also gain a benefit in that the boundary parameter on the Content-Type header is not necessary as it was in prior versions:
HEADER
Content-Type: application/json
BODY
{
"requests": [
{
"method": "POST",
"id": "PIG1",
"url": "http://localhost:50548/odata/DoSomeWork",
"headers": {
"content-type": "application/json; odata.metadata=minimal; odata.streaming=true",
"odata-version": "4.0"
},
"body": { "message": "Went to market and had roast beef" }
},
{
"method": "POST",
"id": "PIG2",
"dependsOn": [ "PIG1" ],
"url": "http://localhost:50548/odata/DoSomeWork",
"headers": {
"content-type": "application/json; odata.metadata=minimal; odata.streaming=true",
"odata-version": "4.0"
},
"body": { "message": "Stayed home, stared longingly at the roast beef, and remained famished" }
},
{
"method": "POST",
"id": "PIG3",
"dependsOn": [ "PIG2" ],
"url": "http://localhost:50548/odata/DoSomeWork",
"headers": {
"content-type": "application/json; odata.metadata=minimal; odata.streaming=true",
"odata-version": "4.0"
},
"body": { "message": "Did not play nice with the others and did his own thing" }
},
{
"method": "POST",
"id": "TEnd",
"dependsOn": [ "PIG1", "PIG2", "PIG3" ],
"url": "http://localhost:50548/odata/HuffAndPuff",
"headers": {
"content-type": "application/json; odata.metadata=minimal; odata.streaming=true",
"odata-version": "4.0"
}
}
]
}
And that's pretty much it. With the batch operations being wrapped in a TransactionScope, if anything fails, it all gets rolled back.
There should only be one DbContext for the OData batch request. Both WCF Data Services and HTTP Web API support OData batch scenario and handle it in a transactional manner. You can check this example: http://blogs.msdn.com/b/webdev/archive/2013/11/01/introducing-batch-support-in-web-api-and-web-api-odata.aspx
I used the same from V3 of the Odata Samples, I saw that my transaction.rollback was called but the data did not rollback. something is lacking but I can't work out what. this may be an issue with having each Odata call using save changes and do they actually see the transaction as in scope. we may need a guru from the Entity Framework team to help solve this one.
Although very detailed, Mitselpliks answer didn't work right out of the box for me, as the transaction got rolled back after each request. To commit the transaction and apply it to the database, it is necessary to call scope.Complete() before disposing/leaving the using scope.
The next issue was that, although everything now ran in a transaction, Exceptions/failures of a single request didn't cause the request or transaction to fail, the status code of the batch response was still a 200 and all other changes were still applied.
As there was no direct way to read the status code of individual requests of the batch request directly from HttpContext, I had to also overload the ExecuteRequestMessageAsync Method and check the results there. So my final code, which causes transactions to be applied when everything is successful and else to rollback everyhing, looks like this:
public class TransactionODataBatchHandler : DefaultODataBatchHandler
{
protected bool Failed { get; set; }
public override async Task ProcessBatchAsync(HttpContext context, RequestDelegate nextHandler)
{
using (var scope = new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted },
TransactionScopeAsyncFlowOption.Enabled))
{
Failed = false;
await base.ProcessBatchAsync(context, nextHandler);
if (!Failed)
{
scope.Complete();
}
}
}
public override async Task<IList<ODataBatchResponseItem>> ExecuteRequestMessagesAsync(IEnumerable<ODataBatchRequestItem> requests, RequestDelegate handler)
{
var responses = await base.ExecuteRequestMessagesAsync(requests, handler);
Failed = responses.Cast<OperationResponseItem>().Any(r => !r.Context.Response.IsSuccessStatusCode());
return responses;
}
}

How do you ensure consistent client reads in an eventual consistent system?

I'm digging into CQRS and I am looking for articles on how to solve client reads in an eventual consistent system. Consider for example a web shop where users can add items to their cart. How can you ensure that the client displays items in the cart if the actual processing of the command "AddItemToCart" is done async? I understand the principles of dispatching commands async and updating the read model async based on domain events, but I fail to see how this is handled from the clients perspective.
There are a few different ways of doing it;
Wait at user till consistent
Just poll the server until you get the read model updated. This is similar to what Ben showed.
Ensure consistency through 2PC
You have a queue that supports DTC; and your commands are put there first. They are then; executed, events sent, read model updated; all inside a single transaction. You have not actually gained anything with this method though, so don't do it this way.
Fool the client
Place the read models in local storage at the client and update them when the corresponding event is sent -- but you were expecting this event anyway, so you had already updated the javascript view of the shopping cart.
I'd recommend you have a look at the Microsoft Patterns & Practices team's guidance on CQRS. Although this is still work-in-progress they have given one solution to the issue you've raised.
Their approach for commands requiring feedback is to submit the command asynchronously, redirect to another controller action and then poll the read model for the expected change or a time-out occurs. This is using the Post-Redirect-Get pattern which works better with the browser's forward and back navigation buttons, and gives the infrastructure more time to process the command before the MVC controller starts polling.
Example code from the RegistrationController using ASP.NET MVC 4 asynchronous controllers.
[HttpGet]
[OutputCache(Duration = 0, NoStore = true)]
public Task<ActionResult> SpecifyRegistrantAndPaymentDetails(Guid orderId, int orderVersion)
{
return this.WaitUntilOrderIsPriced(orderId, orderVersion)
.ContinueWith<ActionResult>(
...
);
}
...
private Task<PricedOrder> WaitUntilOrderIsPriced(Guid orderId, int lastOrderVersion)
{
return
TimerTaskFactory.StartNew<PricedOrder>(
() => this.orderDao.FindPricedOrder(orderId),
order => order != null && order.OrderVersion > lastOrderVersion,
PricedOrderPollPeriodInMilliseconds,
DateTime.Now.AddSeconds(PricedOrderWaitTimeoutInSeconds));
}
I'd probably use AJAX polling instead of having a blocked web request at the server.
Post-Redirect-Get
You're hoping that the save command executes on time before Get is called. What if the command takes 10 seconds to complete in the back end but Get is called in 1 second?
Local Storage
With storing the result of the command on the client while the command goes off to execute, you're assuming that the command will go through without errors. What if the back-end runs into an error while processing the command? Then what you have locally isn't consistent.
Polling
Polling seems to be the option that is actually in line with eventual consistency; you're not faking or assuming. Your polling mechanism can be an asynchronous as a part of your page, e.g. shopping cart page component polls until it gets an update without refreshing the page.
Callbacks
You could introduce something like web hooks to make a call back to the client if the client is capable of receiving such. By providing a correlation Id once the command is accepted by the back-end, once the command has finished processing, the back-end can notify the front end of the command's status along with the correlation Id on whether the command went through successfully or not. There is no need for any kind of polling with this approach.