Interface ReplayCache

All Known Implementing Classes:
InMemoryReplayCache

public interface ReplayCache
SPI for detecting reuse ("replay") of a one-time-use identifier.

A consumer wires a ReplayCache to narrow a token/identifier that would otherwise be usable any number of times within its lifetime down to single-use: the second and every subsequent submission of the same identifier is reported as a replay. The SPI is deliberately generic — it deals only in a String identifier and a long absolute expiry, with no dependency on any particular protocol or transport.

Atomic check-and-record (no TOCTOU). checkAndRecord(String, long) both checks whether an identifier has been seen before and records it as seen, as one indivisible operation. A separate "seen" followed by a separate "record" would leave a race window in which two near-simultaneous submissions of the same identifier could both observe "not yet seen" and both proceed; implementations must guarantee that of any two concurrent calls with the same identifier, at most one returns true.

Fail-mode is a consumer decision. When the backing store cannot answer — for example a remote store is unreachable — an implementation may either throw or return an outcome. The consumer decides how a thrown failure is resolved by passing a ReplayCache.FailMode to checkAndRecord(String, long, FailMode, Consumer):

An implementation that wants to enforce its own outcome on store failure (rather than defer to the consumer's ReplayCache.FailMode) can catch its own failures internally and return true/false from checkAndRecord(String, long) instead of throwing.

The built-in default is per-process only. The zero-config built-in implementation (InMemoryReplayCache) is backed by process-local memory, so it only enforces single-use within one process. Cross-node single-use requires a consumer-supplied ReplayCache backed by a store shared across every node.

See Also:
Since:
10.0.0
  • Method Details

    • checkAndRecord

      boolean checkAndRecord(String id, long expiresAtMs)
      Atomically checks whether the specified identifier has been observed before and records it as seen if not.

      Implementations own their own timeout. A call that blocks indefinitely (for example a remote store with no client-side deadline) blocks the caller with it. An implementation backed by a network store must bound its own call so a slow/unreachable backend surfaces promptly as a throw (which the caller resolves per its chosen ReplayCache.FailMode) or a return, never an unbounded stall.

      Parameters:
      id - The identifier to check. Never null.
      expiresAtMs - The identifier's own absolute expiry, in epoch milliseconds. An implementation may use this to self-evict a record once it can no longer matter.
      Returns:
      true if this is the first time the identifier has been observed (the caller should proceed); false if it has been observed before (the caller should reject the submission as a replay).
    • checkAndRecord

      default boolean checkAndRecord(String id, long expiresAtMs, ReplayCache.FailMode failMode)
      Invokes checkAndRecord(String, long) applying the specified fail-mode policy on a thrown failure.

      Equivalent to checkAndRecord(id, expiresAtMs, failMode, null).

      Parameters:
      id - The identifier to check. Never null.
      expiresAtMs - The identifier's own absolute expiry, in epoch milliseconds.
      failMode - The policy to apply if checkAndRecord(String, long) throws. Must not be null.
      Returns:
      true if the caller should proceed; false if the submission should be rejected.
    • checkAndRecord

      default boolean checkAndRecord(String id, long expiresAtMs, ReplayCache.FailMode failMode, Consumer<Exception> onFailure)
      Invokes checkAndRecord(String, long) applying the specified fail-mode policy on a thrown failure.

      If checkAndRecord(String, long) throws, the exception is passed to onFailure (when non-null) and then resolved to true for ReplayCache.FailMode.FAIL_OPEN or false for ReplayCache.FailMode.FAIL_CLOSED.

      Parameters:
      id - The identifier to check. Never null.
      expiresAtMs - The identifier's own absolute expiry, in epoch milliseconds.
      failMode - The policy to apply if checkAndRecord(String, long) throws. Must not be null.
      onFailure - A handler invoked with the thrown exception before the policy is applied. Can be null.
      Returns:
      true if the caller should proceed; false if the submission should be rejected.