Forwarding and effects in Python
A command can only act on one component at a time—the component that received the command. For certain use cases, you might want a different component to handle the command. Rather than sending an immediate reply to a command, the receiving component can forward the command to another component. In cases where you want other components to be aware that a component processed a command, you can emit an effect.
Handle forwarding and emit effects by wrapping the return value into a reply. The reply holds a regular return message or a forward to another component. Both can carry effects that notify other components.
The forwarding or effect can target any component within the service—whether it is an instance of the same or different type of component.
Transactional limitations
It’s important to note that forwarded commands, and commands emitted as side effects, are non-atomic—there is no guarantee that any one sent transactions will succeeded. If the service, or the data store, fails, while a forwarded command is executing, the triggering command responds with an error (so the client can retry), but there is no automatic rollback. If partial updates will cause problems, do not use forwarding and effects to update multiple entities at once. In this case emit an event that is (eventually) processed by all subscribers.
|
Forwarding control to another component
To forward a command return a forward reply that includes the call to invoke, and the message to invoke it with. The command is not forwarded until any state actions requested by the command handler are successfully completed. It is the responsibility of the component receiving the forward to return a reply that matches the type of the original command. Forwards can be chained arbitrarily long.
TODO: add more complete examples.
Forwarding a command
TODO: update to use replies.forward instead of context.forward, with examples
The CommandContext
can call the method forward
to forward the command to another entity service call.
Emitting effects on another component
An entity may also emit one or more effects. An effect is something whose result has no impact on the result of the current command—if it fails, the current command still succeeds. The result of the effect is therefore ignored. Effects are only performed after the successful completion of any state actions requested by the command handler.
There is no guarantee that an effect will be executed successfully. If a failure occurs after the command is fully handled, effects might not be executed. Effects are not retried in case of failures.
Effects may be declared as synchronous or asynchronous. Asynchronous commands run in a "fire and forget" fashion. The code flow of the caller (the command handler of the entity which emitted the asynchronous command) continues while the command is being asynchronously processed. Meanwhile, synchronous commands run sequentially, that is, the commands are processed in order, one at a time. The final result of the command handler, either a reply or a forward, is not sent until all synchronous commands are completed.
Emitting an effect
TODO: update to use Reply.addEffect instead of context.effect, with examples
The CommandContext
for each entity type implements EffectContext
, which is able to emit an effect after processing the command by invoking the method effect