In This Section
Overview
An AEPEngine handles processing of each inbound message it receives in an atomic fashion - the acknowledgement of message receipt, application changes to state and outbound messages constitute an atomic unit of work. Each such atomic unique of work is considered an AEP transaction. Transactions are, for the most part handled, transparently from an application's standpoint. Application developers simply write message handlers with the assurance the processing done therein will be atomic. This section discuss some of the ways that applications can influence or interact with AEP transactions.
Adaptive Batching
By default an AEPEngine handles processing of each inbound message it receives as a single transaction. It is possible to configure an AEPEngine to attempt to batch up the processing of several inbound messages into a single transaction via a feature called adaptive batching. This feature can improve throughput at the cost of increased latency of outbound messages (the outbound messages for the first message processed in a batch won't be sent until the last message in the batch has been stabilized. The batching behavior is adaptive in nature because the engine commits a batch automatically when either a configured adapative batch ceiling is reached or the engine detects there are no more messages immediately available to process.
Adaptive batching can be enabled by configuring the engine's adaptiveCommitBatchCeiling as follows:
The adaptiveCommitBatchCeiling for app is set to 0 by default which disables adaptive batching. When the platform is optimized for throughput via the nv.optimizefor=throughput runtime property, the adaptive batch ceiling is set to 64 unless otherwise explicitly configured by the application.
Partial Rollback and Savepoints
The AepEngine allows work done in a message handler to be rolled back to a given savepoint which will undo state changes and outbound sends initiated by the application. In the course of processing an application can create savepoints, and then later rollback to them and continue processing. The following example illustrates these concepts:
Breaking down the above example we see:
- The application creates a savepoint at the beginning of its handler
- It then updates the count of orders received for a customer and possibly sends out a promotional message.
- Later, if the handler determines that there isn't enough inventory to satisfy the order it rolls back to the initial savepoint which:
- Resets the customer's ordersReceivedCount to its previous value
- Cancels the possible promotional message for the customer.
- After the rollback the handler then sends an order rejected message and increments a rejection count for the customer.
- The net result of processing is thus an incremented orderRejectedCount for the customer and an order rejected message.
The sections below discuss savepoints and rollback in more depth.
Creating Savepoints
Applications can create savepoints at any point in a message handler by calling AepEngine.createTransactionSavepoint()
. The returned savepoint number can then later be reused to rollback to the state at that time.
Getting the current savepoint
The current savepoint for an AepEngine can be retrieve via the AepEngine.getTransactionSavepoint()
method.
Rolling Back to a Savepoint
This AepEngine.rollbackToTransactionSavepoint()
rolls back state changes to AEP managed state and any outbound message since the given savepoint (including work in savepoints created after the specified savepoint). The rollback operation leaves the provided savepoint marker in place. For example, if the application calls rollback with a savepoint value of 1, a subsequent call to getTransactionSavepoint() will return 1. New work done after the rollback can thus be rolled back to the same point. Any savepoints after the provided savepoint are discarded. If rollback is called with a savepoint value of 1 when getTransactionSavepoint()
is at 2, savepoint 2 is discarded.
It is worth noting that savepoint rollbacks do not rollback the actual processing of a message from the engine's standpoint, just the effects of its processing. If a handler rolls back all processing work (e.g. rollbackToTransactionSavepoint(0), the engine will still consider the message as successfully processed and acknowledge it.
In addition to the restrictions outlined below an attempt to rollback to a savepoint less than 0 or greater than the current savepoint will result in an IllegalStateException.
Rollback Errors
An EAepRollbackError
thrown from this method indicates that therd was an internal or runtime error performing the rollback. In this case, application event handlers must allow the error to be thrown back for the platform to handle as the application state may be in a corrupt state. If the AepEngine can recover by rolling back the entire transaction, the error will be handled according to the AppExceptionHandlingPolicy
, otherwise the engine will stop with the EAepRollbackError.
Outbound Message Considerations
Outbound messages that are rolled back cannot be reused - the transfer of ownership to the AepEngine is preserved. Additionally, it should be noted that rollback does not rollback changes made to outbound messages' fields. When the engine is configured to dispose on send the engine may dispose of such messages during rollback, so applications should not rely on messages tranfered to the engine being valid post rollback.
State and Embedded Entity Considerations
Objects that were created since the savepoint that is rolled back may be discarded and cleared by the engine during rollback. Therefore applications should not attempt to reuse any state objects created since the savepoint that was rolled back.
Adaptive Batching Considerations
When the engine is configured for adapative batching, multiple inbound messages are grouped into a single store transaction. Savepoints don't span multiple inbound messages. Instead processing effect of previous messages are fenced off from subsequent savepoints. Effectively, under the covers the engine creates an internal savepoint for fully processed inbound messages and resets the application visible savepoint to 0 for subequent messages.
Multiple event handlers
If there are multiple event handlers for a given event, savepoints do span those handlers meaning that a subsequent handler for an event can rollback work done by a previous handler. Applications may create a savepoint via createTransactionSavepoint()
at the beginning of message processing to avoid rolling back work done by another handler. This allows applications that chain multiple event handlers together to perform processing a mechanism by which later processors in the chain can completely rollback work.
Restrictions
Transaction savepoints operations (create, get, rollback) are only supported when:
- the engine is configured with savepoints enabled
AepEngineDescriptor#getEnableTransactionSavepoints()
== true - the engine is backed by a store (e.g.
as the AepEngine relies on the store's transaction machinery to perform rollback. This restriction may be relaxed in a future release.getStore()
!= null - Only application message handlers called from the engine's message processing thread may work with savepoints.
isDispatchThread()
&& # - the engine is not configured for parallel cluster replication
AepEngineDescriptor.getReplicateInParallel()
== false
If any of the above criteria is not met an IllegalStateException
is thrown. In addition to the above restrictions an application must not use the following savepoint operations in the underlying store:
IStoreBinding.createSavepoint()
IStoreBinding.rollback(int)
IStoreBinding.rollback()
IStoreBinding.getLastSavepoint()
HA considerations
Savepoint operations can only be performed in a message handler. When using StateReplication this means that savepoint creation and rollbacks can only be done on a Primary instance.
Usage of savepoints when operating with an HAPolicy
of EventSourcing is currently classified as an expiremental feature. Because application state is not managed by the platform for EventSourcing, only an applications outbound messages are rolled back by this method.
When using EventSourcing, message handlers are invoked on a Backup instance or an instance recovering from a transaction log. It is crucial that a backup or recovering instance's behavior or it will lead to divergence in the application's outbound messages. This means that application logic on a backup must create the same savepoints as a primary and rollback based on the same criteria. For this reason it is often preferable for an EventSourcing app that encounters an error to simply throw an exception from its event handler and let the inbound message's fate be governed by the AppExceptionHandlingPolicy
.
See Also
Aep Engine Trace - for details on enabling AEP transaction trace.