Interface TransactionOutbox.ParameterizedScheduleBuilder

Enclosing interface:
TransactionOutbox

public static interface TransactionOutbox.ParameterizedScheduleBuilder
  • Method Details

    • uniqueRequestId

      TransactionOutbox.ParameterizedScheduleBuilder uniqueRequestId(String uniqueRequestId)
      Specifies a unique id for the request. This defaults to null, but if non-null, will cause the request to be retained in the database after completion for the specified TransactionOutbox.TransactionOutboxBuilder.retentionThreshold(Duration), during which time any duplicate requests to schedule the same request id will throw AlreadyScheduledException. This allows tasks to be scheduled idempotently even if the request itself is not idempotent (e.g. from a message queue listener, which can usually only work reliably on an "at least once" basis).
      Parameters:
      uniqueRequestId - The unique request id. May be null, but if non-null may be a maximum of 250 characters in length. It is advised that if these ids are client-supplied, they be prepended with some sort of context identifier to ensure global uniqueness.
      Returns:
      Builder.
    • ordered

      Specifies that the request should be applied in a strictly-ordered fashion within the specified topic.

      This is useful for a number of applications, such as feeding messages into an ordered pipeline such as a FIFO queue or Kafka topic, or for reliable data replication, such as when feeding a data warehouse or distributed cache.

      Note that using this option has a number of consequences:

      • Requests are not processed immediately when submitting a request, as normal, and are processed by TransactionOutbox.flush() only. As a result there will be increased delay between the source transaction being committed and the request being processed.
      • If a request fails, no further requests will be processed in that topic until a subsequent retry allows the failing request to succeed, to preserve ordered processing. This means it is possible for topics to become entirely frozen in the event that a request fails repeatedly. For this reason, it is essential to use a TransactionOutboxListener to watch for failing requests and investigate quickly. Note that other topics will be unaffected.
      • For the same reason, TransactionOutbox.TransactionOutboxBuilder.blockAfterAttempts is ignored for all requests that use this option. The only safe way to recover from a failing request is to make the request succeed.
      • A single topic can only be processed in single-threaded fashion, so if your requests use a small number of topics, scalability will be affected since the degree of parallelism will be reduced.
      • Throughput is significantly reduced and database load increased more generally, even with larger numbers of topics, since records are only processed one-at-a-time rather than in batches, which is less optimised.
      • In general, databases are not well optimised for this sort of thing. Don't expect miracles. If you need more throughput, you probably need to think twice about your architecture. Consider the event sourcing pattern, for example, where the message queue is the primary data store rather than a secondary, and remove the need for an outbox entirely.
      Parameters:
      topic - a free-text string up to 250 characters.
      Returns:
      Builder.
    • delayForAtLeast

      Instructs the scheduler to delay processing the task until after the specified duration. This can be used for simple job scheduling or to introduce an asynchronous delay into chains of tasks.

      Note that any delay is not precise and accuracy is primarily determined by the frequency at which TransactionOutbox.flush(Executor) or TransactionOutbox.flush() are called. Do not use this for time-sensitive tasks, particularly if the duration exceeds TransactionOutbox.TransactionOutboxBuilder.attemptFrequency(Duration) (see more on this below).

      A note on implementation: tasks (when ordered(String) is not used) are normally submitted for processing on the local JVM immediately after transaction commit. By default, when a delay is introduced, the work is instead submitted to a ScheduledExecutorService for processing after the specified delay. However, if the delay is long enough that the work would likely get picked up by a TransactionOutbox.flush() on this JVM or another, this is pointless and wasteful. Unfortunately, we don't know exactly how frequently TransactionOutbox.flush() will be called! To mitigate this, Any task submitted with a delay in excess of TransactionOutbox.TransactionOutboxBuilder.attemptFrequency(Duration) will be assumed to get picked up by a future flush.

      Parameters:
      duration - The minimum delay duration.
      Returns:
      Builder.
    • schedule

      <T> T schedule(Class<T> clazz)
      Equivalent to TransactionOutbox.schedule(Class), but applying additional parameters to the request as configured using TransactionOutbox.with().

      Usage example:

      transactionOutbox.with()
       .uniqueRequestId("my-request")
       .schedule(MyService.class)
       .runMyMethod("with", "some", "arguments");
      Type Parameters:
      T - The type to proxy.
      Parameters:
      clazz - The class to proxy.
      Returns:
      The proxy of T.