Class AbstractDeadlineManager

java.lang.Object
org.axonframework.deadline.AbstractDeadlineManager
All Implemented Interfaces:
DeadlineManager
Direct Known Subclasses:
DbSchedulerDeadlineManager, JobRunrDeadlineManager, QuartzDeadlineManager, SimpleDeadlineManager

public abstract class AbstractDeadlineManager extends Object implements DeadlineManager
Abstract implementation of the DeadlineManager to be implemented by concrete solutions for the DeadlineManager. Provides functionality to perform a call to the DeadlineManager when the ProcessingContext of the current invocation prepares its commit. This runOnPrepareCommitOrNow(Consumer) functionality is required, as the DeadlineManager schedules a Message which needs to happen in order with the other messages published throughout the system.

Axon Framework 4 found that moment through the ambient unit of work. Axon Framework 5 has none, so a call is deferred when it is made while a ContextAwareScope is current, which is the case while a Saga handler method runs, or when it is made through a DeadlineManager handler parameter, which is bound to the ProcessingContext of the handler. A call made anywhere else runs immediately.

Since:
3.3
Author:
Steven van Beelen
  • Constructor Details

    • AbstractDeadlineManager

      protected AbstractDeadlineManager()
      Instantiate an AbstractDeadlineManager, registering the LegacySupportAxoniqAddon with the license entitlement system.
  • Method Details

    • runOnPrepareCommitOrNow

      protected void runOnPrepareCommitOrNow(Consumer<@Nullable ProcessingContext> deadlineCall)
      Run a given deadlineCall immediately, or defer it to a phase of a ProcessingContext. A call made through a context-bound view of this manager is deferred to the context the view was made for. Any other call is deferred to the context carried by the current ContextAwareScope, if one is active. That phase runs after the Saga write and before the context commits. This is required as the DeadlineManager schedules messages which we want to happen in order with other messages being handled.

      The view's context wins over the scope's, as it is the innermost one: a command a Saga handler sends can run on the Saga's thread, in a context of its own, while the Saga's scope is still current. Axon Framework 4 deferred such a call to the command's unit of work, so a failing command scheduled nothing even when the Saga survived its failure. Within the Saga handler itself, the view and the scope carry the same context.

      Deferred calls run in the order they were made, also across Sagas sharing the same ProcessingContext, as they did in the prepare-commit phase of an Axon Framework 4 unit of work. They never run when the context rolls back before reaching that phase.

      The call is handed the ProcessingContext it was deferred to, or null when it runs immediately. Concrete deadline managers pass it on to processDispatchInterceptors(DeadlineMessage, ProcessingContext), so that the dispatch interceptors of a deferred deadline see the context it was deferred to. The call cannot look that context up itself: by the time a deferred call runs, the scope or the view that provided it is no longer current.

      Parameters:
      deadlineCall - the call to be executed now, or when the ProcessingContext it is deferred to prepares its commit, receiving that context or null
      Throws:
      IllegalStateException - if the calls deferred to that ProcessingContext already ran, as nothing would run the given deadlineCall anymore
    • registerDispatchInterceptor

      public Registration registerDispatchInterceptor(MessageDispatchInterceptor<? super DeadlineMessage> dispatchInterceptor)
      Registers the given dispatchInterceptor, which is applied to every DeadlineMessage before it is scheduled.

      Concrete deadline managers apply the registered interceptors through processDispatchInterceptors(DeadlineMessage, ProcessingContext), inside the deferred call when the call is deferred.

      Parameters:
      dispatchInterceptor - the interceptor to apply to deadline messages before they are scheduled
      Returns:
      a Registration that removes the given dispatchInterceptor again when cancelled
    • registerHandlerInterceptor

      public Registration registerHandlerInterceptor(MessageHandlerInterceptor<? super DeadlineMessage> handlerInterceptor)
      Registers the given handlerInterceptor, which is applied around the handling of every DeadlineMessage when its deadline fires.

      Concrete deadline managers apply the registered interceptors, obtained through handlerInterceptors(), when they deliver a fired deadline to its scope.

      Parameters:
      handlerInterceptor - the interceptor to apply around the handling of fired deadline messages
      Returns:
      a Registration that removes the given handlerInterceptor again when cancelled
    • dispatchInterceptors

      protected List<MessageDispatchInterceptor<? super DeadlineMessage>> dispatchInterceptors()
      Provides a list of registered dispatch interceptors. Do note that this list is not modifiable, and that changes in the internal structure for dispatch interceptors will be reflected in this list.
      Returns:
      a list of dispatch interceptors
    • handlerInterceptors

      protected List<MessageHandlerInterceptor<? super DeadlineMessage>> handlerInterceptors()
      Provides a list of registered handler interceptors. Do note that this list is not modifiable, and that changes in the internal structure for handler interceptors will be reflected in this list.
      Returns:
      a list of handler interceptors
    • processDispatchInterceptors

      protected DeadlineMessage processDispatchInterceptors(DeadlineMessage message, @Nullable ProcessingContext context)
      Applies registered MessageDispatchInterceptors to the given message, handing them the given context.

      Before the interceptors run, the correlation data the context carries, as put there by a CorrelationDataInterceptor around the handler that made the deadline call, is added to the message's metadata. Metadata the message already holds under the same key is kept. A deadline thereby carries the correlation data of the message whose handling scheduled it, with the precedence of Axon Framework 4, which created a message with the correlation data of the current unit of work beneath its own metadata. This deliberately differs from a message dispatched through a bus, on which the CorrelationDataInterceptor lets the correlation data replace the message's own metadata under the same key.

      The context is the one of the scope a deadline call was made in, as handed out by runOnPrepareCommitOrNow(Consumer), or null for a call that runs immediately, outside any ProcessingContext. A failing interceptor fails this call with the interceptor's own exception, and an interceptor that ends the chain without a message fails it with an IllegalStateException, instead of scheduling a null message.

      Parameters:
      message - the deadline message to be intercepted
      context - the context the deadline call runs for, or null if it runs outside one
      Returns:
      the intercepted message, never null
      Throws:
      IllegalStateException - if an interceptor ended the chain without a message
    • asDeadlineMessage

      protected DeadlineMessage asDeadlineMessage(String deadlineName, @Nullable Object messageOrPayload, Instant expiryTime)
      Returns the given deadlineName and messageOrPayload as a DeadlineMessage which expires at the given expiryTime. If the messageOrPayload parameter is of type Message, a new DeadlineMessage instance will be created using the payload and metadata of the given message. Otherwise, the given messageOrPayload is wrapped into a GenericDeadlineMessage as its payload.
      Parameters:
      deadlineName - the name for this DeadlineMessage
      messageOrPayload - a Message or payload to wrap as a DeadlineMessage
      expiryTime - the timestamp at which the deadline expires
      Returns:
      a DeadlineMessage using the deadlineName as its deadline name and containing the given messageOrPayload as the payload