Class Replay

java.lang.Object
com.babelqueue.Replay

public final class Replay extends Object
Replay-Bypass — a side-effect guard for DLQ replay (ADR-0027).

A deliberate replay off the dead-letter queue (Redrive) re-runs the handler, and the handler's external side-effects re-fire: a second charge, a duplicate email. Idempotent.wrap stops an accidental duplicate; it does not stop the intended reprocess from re-firing effects that already happened. This closes that gap.

The marker that says "this is a replay, skip the external effects" rides out of band as the HEADER_REPLAY_BYPASS transport header — never in the frozen envelope (GR-1). Redrive.redrive(com.babelqueue.Redrive.Transport, java.lang.String, com.babelqueue.Redrive.Options) stamps it when its options set bypass and the transport is a Redrive.HeaderPublisher; a consume adapter, having reserved the message with its headers, surfaces the flag for the duration of the handler via process(java.util.Map<java.lang.String, java.lang.String>, com.babelqueue.Replay.Effect):


 Redrive.Reserved msg = transport.pop(queue);
 Envelope env = EnvelopeCodec.decode(msg.body());
 Replay.process(msg.headers(), () -> handler.handle(env)); // handler can now query isReplay()
 

A handler wraps its external, non-idempotent side in bypassExternalEffects(com.babelqueue.Replay.Effect) so a replay re-runs the idempotent core but skips effects that already fired. The Java core is codec-only, so this is the core/runtime API + in-memory testing; a concrete broker transport carries the header once it implements Redrive.HeaderPublisher (a follow-up).

  • Field Details

  • Method Details

    • isReplay

      public static boolean isReplay()
      Reports whether the message currently being handled was redriven with the replay-bypass marker — i.e. a deliberate replay whose external side-effects should be skipped. Meaningful only inside a process(java.util.Map<java.lang.String, java.lang.String>, com.babelqueue.Replay.Effect) scope the consumer established from the message's headers.
      Returns:
      whether the current handling is a bypassed replay
    • process

      public static void process(Map<String,String> headers, Replay.Effect body) throws Exception
      Runs body with the replay flag derived from a reserved message's transport headers (the presence of HEADER_REPLAY_BYPASS), restoring the prior flag afterwards. A consume adapter wraps each handler invocation in this.
      Parameters:
      headers - the reserved message's out-of-band headers (may be null/empty)
      body - the handler invocation to run within the replay scope
      Throws:
      Exception - whatever body throws
    • bypassExternalEffects

      public static void bypassExternalEffects(Replay.Effect effect) throws Exception
      Runs effect unless the current message is a replay, in which case it is skipped. Wrap the external, non-idempotent side of a handler — sending an email, charging a card, calling a third party — so a replay re-runs the idempotent core but does not re-fire effects that already happened.
      Parameters:
      effect - the external side-effect to run only when this is not a replay
      Throws:
      Exception - whatever effect throws