@Override public Object resolveParameterValue(Message message) { return message instanceof TrackedEventMessage && ((TrackedEventMessage) message).trackingToken() instanceof ReplayToken ? ReplayStatus.REPLAY : ReplayStatus.REGULAR; }
@Override public TrackingToken createTokenAt(Instant dateTime) { return events.values() .stream() .filter(event -> event.getTimestamp().equals(dateTime) || event.getTimestamp().isAfter(dateTime)) .min(Comparator.comparingLong(e -> ((GlobalSequenceTrackingToken) e.trackingToken()) .getGlobalIndex())) .map(TrackedEventMessage::trackingToken) .map(tt -> (GlobalSequenceTrackingToken) tt) .map(tt -> new GlobalSequenceTrackingToken(tt.getGlobalIndex() - 1)) .orElse(null); }
private List<TrackedEventMessage<?>> readEvents(int eventCount) { List<TrackedEventMessage<?>> result = new ArrayList<>(); TrackingToken lastToken = null; while (result.size() < eventCount) { List<? extends TrackedEventMessage<?>> batch = testSubject.readEvents(lastToken, false).collect(Collectors.toList()); for (TrackedEventMessage<?> message : batch) { result.add(message); if (logger.isDebugEnabled()) { logger.debug(message.getPayload() + " / " + ((DomainEventMessage<?>) message).getSequenceNumber() + " => " + message.trackingToken().toString()); } lastToken = message.trackingToken(); } } return result; } }
@Test @SuppressWarnings("OptionalGetWithoutIsPresent") public void testLoadTrackedEvents() throws InterruptedException { testSubject.appendEvents(createEvents(4)); assertEquals(4, testSubject.readEvents(null, false).count()); // give the clock some time to make sure the last message is really last Thread.sleep(10); DomainEventMessage<?> eventMessage = createEvent("otherAggregate", 0); testSubject.appendEvents(eventMessage); assertEquals(5, testSubject.readEvents(null, false).count()); assertEquals(eventMessage.getIdentifier(), testSubject.readEvents(null, false).reduce((a, b) -> b).get().getIdentifier()); }
private EventConsumer(Node lastNode) { this(lastNode.event.trackingToken()); this.lastNode = lastNode; }
@Override public TrackingToken createTokenAt(Instant dateTime) { return events.values() .stream() .filter(event -> event.getTimestamp().equals(dateTime) || event.getTimestamp().isAfter(dateTime)) .min(Comparator.comparingLong(e -> ((GlobalSequenceTrackingToken) e.trackingToken()) .getGlobalIndex())) .map(TrackedEventMessage::trackingToken) .map(tt -> (GlobalSequenceTrackingToken) tt) .map(tt -> new GlobalSequenceTrackingToken(tt.getGlobalIndex() - 1)) .orElse(null); }
private Node findNode(TrackingToken trackingToken) { Node node = oldest; while (node != null && !node.event.trackingToken().equals(trackingToken)) { node = node.next; } return node; }
@Override public TrackingToken createTokenAt(Instant dateTime) { return events.values() .stream() .filter(event -> event.getTimestamp().equals(dateTime) || event.getTimestamp().isAfter(dateTime)) .min(Comparator.comparingLong(e -> ((GlobalSequenceTrackingToken) e.trackingToken()) .getGlobalIndex())) .map(TrackedEventMessage::trackingToken) .map(tt -> (GlobalSequenceTrackingToken) tt) .map(tt -> new GlobalSequenceTrackingToken(tt.getGlobalIndex() - 1)) .orElse(null); }
private TrackingToken lastToken() { if (newest == null) { List<TrackingToken> tokens = tailingConsumers.stream().map(EventConsumer::lastToken).collect(toList()); return tokens.isEmpty() || tokens.contains(null) ? null : tokens.get(0); } else { return newest.event.trackingToken(); } }
@Override public TrackedEventMessage<?> nextAvailable() throws InterruptedException { TrackedEventMessage<?> trackedEventMessage = alterToken(delegate.nextAvailable()); this.lastToken = trackedEventMessage.trackingToken() instanceof ReplayToken ? (ReplayToken) trackedEventMessage.trackingToken() : null; return trackedEventMessage; }
/** * 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()); }
@Override public TrackingToken resolveParameterValue(Message<?> message) { return unwrap(((TrackedEventMessage) message).trackingToken()); }
@Override public boolean tryAdvance(Consumer<? super TrackedEventMessage<?>> action) { if (active == null && historicSpliterator.tryAdvance((Consumer<TrackedEventMessage<?>>) message -> { lastToken = message.trackingToken(); action.accept(message); })) { return true; } else if (active == null) { active = nextProvider.apply(lastToken); } return active.tryAdvance(action); } }
private TrackedEventMessage<?> peekGlobalStream(int timeout, TimeUnit timeUnit) throws InterruptedException { Node nextNode; if ((nextNode = nextNode()) == null && timeout > 0) { consumerLock.lock(); try { consumableEventsCondition.await(timeout, timeUnit); nextNode = nextNode(); } finally { consumerLock.unlock(); } } if (nextNode != null) { if (tailingConsumers.contains(this)) { lastNode = nextNode; } lastToken = nextNode.event.trackingToken(); return nextNode.event; } else { return null; } }
@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); } } }
lastToken = nextEvent.trackingToken(); return nextEvent; } else if (allowSwitchToTailingConsumer) { if (consumableEventsCondition.await(timeout, timeUnit) && privateIterator.hasNext()) { TrackedEventMessage<?> nextEvent = privateIterator.next(); lastToken = nextEvent.trackingToken(); return nextEvent;
@Test @SuppressWarnings("OptionalGetWithoutIsPresent") public void testLoadPartialStreamOfTrackedEvents() { List<DomainEventMessage<?>> events = createEvents(4); testSubject.appendEvents(events); TrackingToken token = testSubject.readEvents(null, false).findFirst().get().trackingToken(); assertEquals(3, testSubject.readEvents(token, false).count()); assertEquals(events.subList(1, events.size()).stream().map(EventMessage::getIdentifier).collect(toList()), testSubject.readEvents(token, false).map(EventMessage::getIdentifier).collect(toList())); }
for (int i = 0; i < batchSize * 10 && batch.size() < batchSize && eventStream.hasNextAvailable(); i++) { final TrackedEventMessage<?> trackedEventMessage = eventStream.nextAvailable(); lastToken = trackedEventMessage.trackingToken(); if (canHandle(trackedEventMessage, segment)) { batch.add(trackedEventMessage); && eventStream.peek().filter(event -> finalLastToken.equals(event.trackingToken())).isPresent()) { final TrackedEventMessage<?> trackedEventMessage = eventStream.nextAvailable(); if (canHandle(trackedEventMessage, segment)) {
List<TrackingToken> replayRun = new CopyOnWriteArrayList<>(); doAnswer(i -> { firstRun.add(i.<TrackedEventMessage>getArgument(0).trackingToken()); return null; }).when(eventHandlerInvoker).handle(any(), any()); replayRun.add(i.<TrackedEventMessage>getArgument(0).trackingToken()); return null; }).when(eventHandlerInvoker).handle(any(), any());
@Test public void testUpdateActiveSegmentsWhenBatchIsEmpty() throws Exception { StreamableMessageSource<TrackedEventMessage<?>> stubSource = mock(StreamableMessageSource.class); testSubject = TrackingEventProcessor.builder() .name("test") .eventHandlerInvoker(eventHandlerInvoker) .messageSource(stubSource) .tokenStore(tokenStore) .transactionManager(NoTransactionManager.INSTANCE).build(); when(stubSource.openStream(any())).thenReturn(new StubTrackingEventStream(0, 1, 2, 5)); doReturn(true, false).when(eventHandlerInvoker).canHandle(any(), any()); List<TrackingToken> trackingTokens = new CopyOnWriteArrayList<>(); doAnswer(i -> { trackingTokens.add(i.<TrackedEventMessage>getArgument(0).trackingToken()); return null; }).when(eventHandlerInvoker).handle(any(), any()); testSubject.start(); // give it a bit of time to start Thread.sleep(200); EventTrackerStatus eventTrackerStatus = testSubject.processingStatus().get(0); assertTrue(eventTrackerStatus.isCaughtUp()); GapAwareTrackingToken expectedToken = GapAwareTrackingToken.newInstance(5, asList(3L, 4L)); TrackingToken lastToken = eventTrackerStatus.getTrackingToken(); assertTrue(lastToken.covers(expectedToken)); }