/** * Indicates whether the given {@code trackingToken} represents a position that is part of a replay. * * @param trackingToken The token to verify * @return {@code true} if the token indicates a replay */ public static boolean isReplay(TrackingToken trackingToken) { return trackingToken instanceof ReplayToken && ((ReplayToken) trackingToken).isReplay(); }
/** * Creates a new TrackingToken that represents the given {@code startPosition} of a stream, in reset state, * when appropriate. * * @param tokenAtReset The token present when the reset was triggered * @param startPosition The position where the token should be reset to * @return A token that represents a reset to the tail of the stream */ public static TrackingToken createReplayToken(TrackingToken tokenAtReset, TrackingToken startPosition) { if (tokenAtReset == null) { return null; } if (tokenAtReset instanceof ReplayToken) { return createReplayToken(((ReplayToken) tokenAtReset).tokenAtReset, startPosition); } if (startPosition != null && startPosition.covers(tokenAtReset)) { return startPosition; } return new ReplayToken(tokenAtReset, startPosition); }
@Override public TrackingToken upperBound(TrackingToken other) { return advancedTo(other); }
/** * Creates a new TrackingToken that represents the tail position of a stream, in reset state, when appropriate. * * @param tokenAtReset The token present when the reset was triggered * @return A token that represents a reset to the tail of the stream */ public static TrackingToken createReplayToken(TrackingToken tokenAtReset) { return createReplayToken(tokenAtReset, null); }
@Override public TrackingToken lowerBound(TrackingToken other) { if (other instanceof ReplayToken) { return new ReplayToken(this, ((ReplayToken) other).currentToken); } return new ReplayToken(this, other); }
@Override public TrackingToken getTrackingToken() { if (trackingToken instanceof ReplayToken) { return ((ReplayToken) trackingToken).unwrap(); } return trackingToken; } }
/** * Resets tokens to the given {@code startPosition}. This effectively causes a replay of events since that position. * <p> * Note that the new token must represent a position that is <em>before</em> the current position of the processor. * <p> * Before attempting to reset the tokens, the caller must stop this processor, as well as any instances of the * same logical processor that may be running in the cluster. Failure to do so will cause the reset to fail, * as a processor can only reset the tokens if it is able to claim them all. * * @param startPosition The token representing the position to reset the processor to. */ public void resetTokens(TrackingToken startPosition) { Assert.state(supportsReset(), () -> "The handlers assigned to this Processor do not support a reset"); Assert.state(!isRunning() && activeProcessorThreads() == 0, () -> "TrackingProcessor must be shut down before triggering a reset"); transactionManager.executeInTransaction(() -> { int[] segments = tokenStore.fetchSegments(getName()); TrackingToken[] tokens = new TrackingToken[segments.length]; for (int i = 0; i < segments.length; i++) { tokens[i] = tokenStore.fetchToken(getName(), segments[i]); } // we now have all tokens, hurray eventHandlerInvoker().performReset(); for (int i = 0; i < tokens.length; i++) { tokenStore.storeToken(ReplayToken.createReplayToken(tokens[i], startPosition), getName(), segments[i]); } }); }
/** * Advance this token to the given {@code newToken}. * * @param newToken The token representing the position to advance to * @return a token representing the new position */ public TrackingToken advancedTo(TrackingToken newToken) { if (this.tokenAtReset == null || (newToken.covers(this.tokenAtReset) && !tokenAtReset.covers(newToken))) { // we're done replaying return newToken; } else if (tokenAtReset.covers(newToken)) { // we're still well behind return new ReplayToken(tokenAtReset, newToken); } else { // we're getting an event that we didn't have before, but we haven't finished replaying either return new ReplayToken(tokenAtReset.upperBound(newToken), newToken); } }
private BlockingStream<TrackedEventMessage<?>> doOpenStream(TrackingToken trackingToken) { if (trackingToken instanceof ReplayToken) { return new ReplayingMessageStream((ReplayToken) trackingToken, messageSource.openStream(((ReplayToken) trackingToken).unwrap())); } return messageSource.openStream(trackingToken); }
/** * Indicates whether the given message is "redelivered", as a result of a previous reset. If {@code true}, this * means this message has been delivered to this processor before its token was reset. * * @param message The message to inspect * @return {@code true} if the message is a replay */ public static boolean isReplay(Message<?> message) { return message instanceof TrackedEventMessage && isReplay(((TrackedEventMessage) message).trackingToken()); }
/** * Creates a new TrackingToken that represents the given {@code startPosition} of a stream, in reset state, * when appropriate. * * @param tokenAtReset The token present when the reset was triggered * @param startPosition The position where the token should be reset to * @return A token that represents a reset to the tail of the stream */ public static TrackingToken createReplayToken(TrackingToken tokenAtReset, TrackingToken startPosition) { if (tokenAtReset == null) { return null; } if (tokenAtReset instanceof ReplayToken) { return createReplayToken(((ReplayToken) tokenAtReset).tokenAtReset, startPosition); } if (startPosition != null && startPosition.covers(tokenAtReset)) { return startPosition; } return new ReplayToken(tokenAtReset, startPosition); }
/** * Creates a new TrackingToken that represents the tail position of a stream, in reset state, when appropriate. * * @param tokenAtReset The token present when the reset was triggered * @return A token that represents a reset to the tail of the stream */ public static TrackingToken createReplayToken(TrackingToken tokenAtReset) { return createReplayToken(tokenAtReset, null); }
@Override public TrackingToken lowerBound(TrackingToken other) { if (other instanceof ReplayToken) { return new ReplayToken(this, ((ReplayToken) other).currentToken); } return new ReplayToken(this, other); }
@Override public TrackingToken getTrackingToken() { if (trackingToken instanceof ReplayToken) { return ((ReplayToken) trackingToken).unwrap(); } return trackingToken; } }
@SuppressWarnings("unchecked") public <T> TrackedEventMessage<T> alterToken(TrackedEventMessage<T> message) { if (lastToken == null) { return message; } if (message instanceof DomainEventMessage) { return new GenericTrackedDomainEventMessage<>(lastToken.advancedTo(message.trackingToken()), (DomainEventMessage<T>) message); } else { return new GenericTrackedEventMessage<>(lastToken.advancedTo(message.trackingToken()), message); } } }
@Override public Object handle(Message<?> message, T target) throws Exception { if (ReplayToken.isReplay(message)) { return null; } return super.handle(message, target); } }
/** * Creates a new TrackingToken that represents the given {@code startPosition} of a stream, in reset state, * when appropriate. * * @param tokenAtReset The token present when the reset was triggered * @param startPosition The position where the token should be reset to * @return A token that represents a reset to the tail of the stream */ public static TrackingToken createReplayToken(TrackingToken tokenAtReset, TrackingToken startPosition) { if (tokenAtReset == null) { return null; } if (tokenAtReset instanceof ReplayToken) { return createReplayToken(((ReplayToken) tokenAtReset).tokenAtReset, startPosition); } if (startPosition != null && startPosition.covers(tokenAtReset)) { return startPosition; } return new ReplayToken(tokenAtReset, startPosition); }
/** * Creates a new TrackingToken that represents the tail position of a stream, in reset state, when appropriate. * * @param tokenAtReset The token present when the reset was triggered * @return A token that represents a reset to the tail of the stream */ public static TrackingToken createReplayToken(TrackingToken tokenAtReset) { return createReplayToken(tokenAtReset, null); }
@Override public TrackingToken lowerBound(TrackingToken other) { if (other instanceof ReplayToken) { return new ReplayToken(this, ((ReplayToken) other).currentToken); } return new ReplayToken(this, other); }
@Override public TrackingToken getTrackingToken() { if (trackingToken instanceof ReplayToken) { return ((ReplayToken) trackingToken).unwrap(); } return trackingToken; } }