UnitOfWorkis an important concept in the Axon Framework. Although, in most cases you are unlikely to interact with it directly. The processing of a message is seen as a single unit. The purpose of the unit of work is to coordinate actions performed during the processing of a message (command, event or query). Components can register actions to be performed during each of the stages of a
UnitOfWork, such as
UnitOfWork. It is mainly used by the building blocks that the Axon Framework provides. If you do need access to it, for whatever reason, there are a few ways to obtain it. A handler receives the unit of work through a parameter in the handle method. If you use annotation support, you may add a parameter of type
UnitOfWorkto your annotated method. In other locations, you can retrieve the unit of work bound to the current thread by calling
CurrentUnitOfWork.get(). Note that this method will throw an exception if there is no
UnitOfWorkbound to the current thread. Use
CurrentUnitOfWork.isStarted()to find out if one is available.
unitOfWork.getOrComputeResource()and the lifecycle callback methods, such as
onCleanup()allow you to register resources and declare actions to be taken during the processing of this unit of work.
NoteNote that the Unit of Work is merely a buffer of changes, not a replacement for transactions. Although all staged changes are only committed when the Unit of Work is committed, its commit is not atomic. That means that when a commit fails, some changes might have been persisted, while others have not been. Best practices dictate that a command should never contain more than one action. If you stick to that practice, a unit of work will contain a single action, making it safe to use as-is. If you have more actions in your unit of work, then you could consider attaching a transaction to the unit of work's commit. Use
unitOfWork.onCommit(..)to register actions that need to be taken when the unit of work is being committed.
UnitOfWorkto roll back all changes. As a result, scheduled side effects are cancelled.
RollbackConfigurationType.NEVER- will always commit the
RollbackConfigurationType.ANY_THROWABLE- will always roll back when an exception occurs
RollbackConfigurationType.UNCHECKED_EXCEPTIONS- will roll back on errors and runtime exceptions
RollbackConfigurationType.RUNTIME_EXCEPTION- will roll back on runtime exceptions (but not on errors)
DefaultUnitOfWorkwill provide you with the functionality you need. It expects processing to happen within a single thread. To execute a task in the context of a unit of work, simply call
UnitOfWork.executeWithResult(Callable)on a new
DefaultUnitOfWork. The unit of work will be started and committed when the task completes, or rolled back if the task fails. You can also choose to manually start, commit or rollback the unit of work if you need more control.
NoteThe Unit of Work revolves around messages. It is always started with a message to be processed. As a result of a Unit-of-Work's execution (
ResultMessagewill be returned and the actual execution result will be the payload of that
ResultMessage. If problems arose during message processing, we get an exceptional
exceptionResult()will get us the actual
Throwableindicating what went wrong.
UnitOfWorkknows several phases. Each time it progresses to another phase, the listeners are notified.
CurrentUnitOfWork.set(UnitOfWork)). Subsequently, the message is typically handled by a message handler in this phase.
onPrepareCommitlisteners are invoked. If a Unit of Work is bound to a transaction, the
onCommitlisteners are invoked to commit any supporting transactions. When the commit succeeds, the
afterCommitlisteners are invoked. If a commit or any step before fails, the
onRollbacklisteners are invoked. The message handler result is contained in the
ExecutionResultof the unit of work, if available.
QueryBusimplementations and all asynchronously processing
EventProcessors, allow you to configure a
TransactionManager. This transaction manager will then be used to create the transactions to bind to the unit of work that is used to manage the process of a message.
EntityManager, these resources can be attached to the
unitOfWork.getResources()method allows you to access the resources attached to the current unit of work. Several helper methods are available on the unit of work directly, to make working with resources easier.
unitOfWork.root(). If a unit of work is the root, it will simply return itself.