Class MultiTenantTrackingToken

java.lang.Object
io.axoniq.framework.messaging.multitenancy.eventstreaming.MultiTenantTrackingToken
All Implemented Interfaces:
TrackingToken

@Internal public class MultiTenantTrackingToken extends Object implements TrackingToken
A TrackingToken holding one position per tenant, positioning the merged read stream that feeds event processors across all tenants.

It reuses a MultiSourceTrackingToken for the per-tenant positions, their aggregation, and their serialization, and adds only what that token deliberately refuses: tolerance for a changing set of tenants. The set of tenants grows and shrinks as tenants are added and removed, so when a processor compares a stored token (written for an earlier set of tenants) with a live token (for the current set), the two carry different tenants. This token tolerates that: its lowerBound(org.axonframework.messaging.eventhandling.processing.streaming.token.TrackingToken), upperBound(org.axonframework.messaging.eventhandling.processing.streaming.token.TrackingToken), covers(org.axonframework.messaging.eventhandling.processing.streaming.token.TrackingToken), and samePositionAs(org.axonframework.messaging.eventhandling.processing.streaming.token.TrackingToken) operate over the union of both tokens' tenants, treating a tenant present in only one of them as being at its beginning in the other. A tenant added since the stored token was written therefore streams from its beginning. Confining the tolerance here keeps the shared MultiSourceTrackingToken's strict guardrail intact.

The fully qualified class name is written into every multi-tenant processor's token store when the token is serialized. Renaming or moving this class therefore breaks existing token stores, so it can only be done together with a token migration.

Since:
5.3.0
Author:
Laura Devriendt
  • Constructor Details

    • MultiTenantTrackingToken

      public MultiTenantTrackingToken(Map<String,@Nullable TrackingToken> tenantTokens)
      Constructs a token holding the given tenantTokens, keyed by tenant id.
      Parameters:
      tenantTokens - the position per tenant, keyed by tenant id
  • Method Details

    • empty

      public static MultiTenantTrackingToken empty()
      Returns an empty token, holding no tenant positions.
      Returns:
      an empty MultiTenantTrackingToken
    • from

      public static MultiTenantTrackingToken from(@Nullable TrackingToken token)
      Adapts the given token to a MultiTenantTrackingToken: an empty token when null, or the token itself when it already is one.
      Parameters:
      token - the token to adapt
      Returns:
      the token as a MultiTenantTrackingToken
      Throws:
      IllegalArgumentException - if the token is a different, incompatible type
    • advancedTo

      public MultiTenantTrackingToken advancedTo(String tenantId, TrackingToken newToken)
      Returns a copy of this token with the given tenantId advanced to newToken.
      Parameters:
      tenantId - the tenant whose position is advanced
      newToken - the new position for the tenant
      Returns:
      a token holding the advanced position for the tenant
    • tokenForTenant

      public @Nullable TrackingToken tokenForTenant(String tenantId)
      Returns the position of the given tenantId, or null when this token holds no position for it.
      Parameters:
      tenantId - the tenant to return the position of
      Returns:
      the tenant's position, or null when absent
    • lowerBound

      public TrackingToken lowerBound(TrackingToken other)
      Description copied from interface: TrackingToken
      Returns a token that represents the lower bound between this and the other token. Effectively, the returned token will cause events not received by both this and the other token to be redelivered.
      Specified by:
      lowerBound in interface TrackingToken
      Parameters:
      other - The token to compare to this one
      Returns:
      The token representing the lower bound of the two
    • upperBound

      public TrackingToken upperBound(TrackingToken other)
      Description copied from interface: TrackingToken
      Returns the token that represents the furthest possible position in a stream that either this token or the given other represents. Effectively, this means this token will only deliver events that neither this, nor the other have been received.
      Specified by:
      upperBound in interface TrackingToken
      Parameters:
      other - The token to compare this token to
      Returns:
      a token that represents the furthest position of this or the other stream
    • covers

      public boolean covers(TrackingToken other)
      Description copied from interface: TrackingToken
      Indicates whether this token covers the other token completely. That means that this token represents a position in a stream that has received all the events that a stream represented by the other token has received.

      Note that this operation is only safe when comparing tokens obtained from events from the same StreamableEventSource.

      Specified by:
      covers in interface TrackingToken
      Parameters:
      other - The token to compare to this one
      Returns:
      true if this token covers the other, otherwise false
    • samePositionAs

      public boolean samePositionAs(TrackingToken other)
      Description copied from interface: TrackingToken
      Indicates whether this token is at the exact same spot in the event stream as the other token.

      This method is particularly useful when comparing tokens from different points in time, such as during replay detection, where token implementations may naturally differ.

      By default, this method checks bidirectional coverage: this.covers(other) && other.covers(this), which ensures both tokens are at the same position.

      Specified by:
      samePositionAs in interface TrackingToken
      Parameters:
      other - The token to validate against this token.
      Returns:
      true if this token is at the same location as the other token, otherwise false. Returns false if other is null.
      See Also:
    • position

      public OptionalLong position()
      Description copied from interface: TrackingToken
      Return the estimated relative position this token represents. In case no estimation can be given an OptionalLong.empty() will be returned.
      Specified by:
      position in interface TrackingToken
      Returns:
      the estimated relative position of this token
    • equals

      public boolean equals(Object other)
      Overrides:
      equals in class Object
    • hashCode

      public int hashCode()
      Overrides:
      hashCode in class Object
    • toString

      public String toString()
      Overrides:
      toString in class Object