I’m considering an API which has a bulk update; if any of the updates fail, the request should fail, if they all succeed, request is OK.
I think a read-side is the most reactive way to do this. However, the issue with the read-side is there could be lag… so if the read-side believes all of the updates could happen but some number fail, there’s no real rollback mechanism
If I model my FooEntity slightly differently, the rollback is no longer needed: instead of each Foo being an entity, the service has an entity which holds Foo objects within its state.
This feels much less reactive, but seems to solve the pervasive issue of Aggregates are Hard in Reactive Systems™. Are there other considerations?
FooEntity & FooBatchUpdateSagaEntity
Entity instance per Foo instance (Foo instance actions done directy on FooEntity).
Batch update action done via FooBatchUpdateSagaEntity, instanced per batch request, responsible for sending update comands to FooEntity. In case of fail doing rollback on successfully updated Foos.
Pros: scalable, FooEntity behavior simpler, (batch and single actions decoupled)
Cons: asynchron (no batch status in response for batch update request), generaly more complexed because of addition Saga entity
FoosEntity
One entity instance with list of Foo instances
Pros: “synchron” (batch status in response for batch update request), generally less complexed
Cons: not scalable, FooEntity behavior more complexed because of list maintaining (batch and single actions coupled)
I beleive scalability is a biggest issue.
I always took a save side and used design #2 and always sacrificed response having update status.
But again each of this design options have there use case depending on the use case requirements. Also, in some use cases, mentioned design cons are not necessary cons.