New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Review PersistentEntity API for reply and afterPersist #919
Comments
I like it! |
As a first observation,
seems better than
|
@guizmaii we probably want the same for the
|
I like these suggestions. A few questions:
|
For sure. I didn't thought about it initially but that's certainly a good idea.
The
I think the API should enforce it. A
Yes, why not. I would prefer to declare two
Exception in Not sure about exception in
Not sure, the fact that it could influence
The only valid case would be a re-try with new events generated. |
If the reply type is anything other than |
This would be an improvement. I like having the updated state (after applying the event handlers) in the reply method, because I often find myself having to repeat the same transformation of the event handler in the afterPersist. I agree that afterPersist should be a best-effort call. We perform side effects for which this is not enough using topics and the message broker. This change would break code using the current api. What would the migration path look like? |
@olivierdeckers, I think the best thing to do in this case is to provide an alternative API living next to the current. That alternative API would be marked as experimental and we would like to, guess what, experiment with it and have feedback from the community. Once we decide about it's shape we can make it the default one and deprecate the old. |
We have published a first stab for a new Lagom Persistence API. This is only a sandbox that we are using to design the API and get the types on the right place. It's only Scala for the moment and it even don't use Akka yet. Feedback is more than welcome. |
I really like the explicit handling of entity creation. How would deletion be handled? By an event-handler that sets the state to None or an explicit API as well? |
@mihbor I have discussed this topic a couple of times. The most common argument against it is that an I have seen a system that did something on those lines. The This is the equivalent of a hard delete in a CRUD app. After hard deleting something, you can recreated it using the same ID. The drawback of it in a Event Sourced app is that you keep the history. Two incarnations of for the same ID won't have distinct histories, but they will share one and single history. For that reason, an not the fact that |
For clarity, I'm not saying that I'm totally against a delete. It's just something that we should be careful. If we ever add it we need to have a very good case for it and a good companion article / blog explaining what that really means to 'delete' an And uninformed users will probably be trapped and believe that such a method would delete the events. |
Sure, I get it. Perhaps I should have elaborated a bit more. What I meant was that, now that there is going to be explicit handling for an initial "non-existence" of entities, what will be the best way to handle a (deletion) event to transition the entity state to be equivalent to that of a non-existent entity for the purpose of handling further commands. Currently I just set the state to null and set the behaviour to the same one as when the initialBehavior method is called with an empty snapshot. NB. just having written the above question does make me think having an explicit deletion would make it clearer rather than more confusing, but that's just my personal opinion. |
When the
If an event handler returns We could fix that by adding special
That will bring your model back to I have to say that I'm not comfortable with the idea of using The alternative would be:
|
Yes, I'd too prefer to avoid the null in the new API. |
This becomes obsolete with the upcoming Akka Persistence Typed API Thanks for all the thoughts and feedback. |
This issue is a starting point for a broader discussion we would like to initiate about the current state of
PersistentEntity
API.This was initially triggered by PR #901. The main problem reported there is that it's very cumbersome to write command handlers that reply with the entity state while emitting many or none events.
For illustration:
(examples in Java syntax)
In its current form, the API offers no easy way to deal with the fact that events may not be emitted.
The
ctx.thenPersistAll
method receive an empty lists of events, but theafterPersist
method is not called if there are zero events persisted. Which make sense, because it's calledafterPersist
.The mechanism is based on a
Context
that is passed to the user. TheContext
brings to user space (without exposing it) theactor.sender()
. In the case ofreply
, behind the scene thereply
callssender() ! someMessage
.Note that we are basically piggybacking the
afterPersist
method to call indirectly theactor.sender()
method.Fluent API Proposal
We could achieve exactly the same without relying on a context and without mixing side-effect function (
afterPersist
) withreply
functions.For instance...
The above example replies by returning the
version
of model. Thestate
is the model after applying the generated events. IfgeneratedEvents
return a empty list,state
is not updated.Note that this API removes completely the need for a
Context
. We just register a functionState -> A
that is called to transform the current state and generate the data that will be sent back to the sender.Another variation could be:
In that case, the user receives the current updated
state
and the generated events.A similar fluent API can be implement for
afterPersist
.afterPersist
callback is only called ifevents.nonEmpty
and it returnsvoid
orUnit
(scala).PersistOne / PersistAll asymmetry
The
afterPersist
callbacks forPersistOne
andPersistAll
are not symmetric.PersistOne
hasEvent -> void
andPersistAll
has() -> void
.The reason for that comes from akka-persistence itself where the
handler
forpersistAll
has the same shape (Event -> void
) as the handler forpersist
. This is probably for historical reasons, but as a consequence the Lagom API exposed it asEvent -> void
and() -> void
.Some users have complained on Gitter about it. There is a easy workaround which is to have the generated events in scope when defining the command handler. However, we can easily improve the user experience by offering a symmetric API.
The text was updated successfully, but these errors were encountered: