when(eventBus.openStream(null)).thenReturn(trackingEventStreamOf(events.iterator())); testSubject = TrackingEventProcessor.builder() .name("test") .eventHandlerInvoker(eventHandlerInvoker) .messageSource(eventBus) .tokenStore(tokenStore) .transactionManager(NoTransactionManager.INSTANCE) .build();
TrackingEventProcessor.Builder eventProcessorBuilder = TrackingEventProcessor.builder() .name("test") .eventHandlerInvoker(eventHandlerInvoker) .messageSource(eventBus) .tokenStore(tokenStore) .transactionManager(NoTransactionManager.INSTANCE) .trackingEventProcessorConfiguration(config); testSubject = new TrackingEventProcessor(eventProcessorBuilder) { @Override
/** * Instantiate a Builder to be able to create a {@link TrackingEventProcessor}. * <p> * The {@link RollbackConfigurationType} defaults to a {@link RollbackConfigurationType#ANY_THROWABLE}, the * {@link ErrorHandler} is defaulted to a {@link PropagatingErrorHandler}, the {@link MessageMonitor} defaults to a * {@link NoOpMessageMonitor} and the {@link TrackingEventProcessorConfiguration} to a * {@link TrackingEventProcessorConfiguration#forSingleThreadedProcessing()} call. The Event Processor {@code name}, * {@link EventHandlerInvoker}, {@link StreamableMessageSource}, {@link TokenStore} and {@link TransactionManager} * are <b>hard requirements</b> and as such should be provided. * * @return a Builder to be able to create a {@link TrackingEventProcessor} */ public static Builder builder() { return new Builder(); }
private TrackingEventProcessor trackingEventProcessor(String name, EventHandlerInvoker eventHandlerInvoker, TrackingEventProcessorConfiguration config, StreamableMessageSource<TrackedEventMessage<?>> source) { return TrackingEventProcessor.builder() .name(name) .eventHandlerInvoker(eventHandlerInvoker) .rollbackConfiguration(rollbackConfiguration(name)) .errorHandler(errorHandler(name)) .messageMonitor(messageMonitor(TrackingEventProcessor.class, name)) .messageSource(source) .tokenStore(tokenStore(name)) .transactionManager(transactionManager(name)) .trackingEventProcessorConfiguration(config) .build(); }
TrackingEventProcessor.Builder eventProcessorBuilder = TrackingEventProcessor.builder() .name("test") .eventHandlerInvoker(eventHandlerInvoker) .messageSource(eventBus) .tokenStore(tokenStore) .transactionManager(mockTransactionManager); testSubject = new TrackingEventProcessor(eventProcessorBuilder) { @Override
.name("benchmark") .eventHandlerInvoker(eventHandlerInvoker) .messageSource(eventStore) .tokenStore(new InMemoryTokenStore()) .transactionManager(NoTransactionManager.INSTANCE) .build(); this.executorService = Executors.newFixedThreadPool(threadCount, new AxonThreadFactory("storageJobs"));
@Test @DirtiesContext public void testProcessorGoesToRetryModeWhenOpenStreamFails() throws Exception { eventBus = spy(eventBus); tokenStore = new InMemoryTokenStore(); eventBus.publish(createEvents(5)); when(eventBus.openStream(any())).thenThrow(new MockException()).thenCallRealMethod(); List<EventMessage<?>> ackedEvents = new ArrayList<>(); CountDownLatch countDownLatch = new CountDownLatch(5); doAnswer(invocation -> { ackedEvents.add((EventMessage<?>) invocation.getArguments()[0]); countDownLatch.countDown(); return null; }).when(mockHandler).handle(any()); testSubject = TrackingEventProcessor.builder() .name("test") .eventHandlerInvoker(eventHandlerInvoker) .messageSource(eventBus) .tokenStore(tokenStore) .transactionManager(NoTransactionManager.INSTANCE) .build(); testSubject.start(); // give it a bit of time to start Thread.sleep(200); assertTrue("Expected 5 invocations on Event Handler by now", countDownLatch.await(10, TimeUnit.SECONDS)); assertEquals(5, ackedEvents.size()); verify(eventBus, times(2)).openStream(any()); }
@Test @DirtiesContext public void testContinueFromPreviousToken() throws Exception { tokenStore = new InMemoryTokenStore(); eventBus.publish(createEvents(10)); TrackedEventMessage<?> firstEvent = eventBus.openStream(null).nextAvailable(); tokenStore.storeToken(firstEvent.trackingToken(), testSubject.getName(), 0); assertEquals(firstEvent.trackingToken(), tokenStore.fetchToken(testSubject.getName(), 0)); List<EventMessage<?>> ackedEvents = new ArrayList<>(); CountDownLatch countDownLatch = new CountDownLatch(9); doAnswer(invocation -> { ackedEvents.add((EventMessage<?>) invocation.getArguments()[0]); countDownLatch.countDown(); return null; }).when(mockHandler).handle(any()); testSubject = TrackingEventProcessor.builder() .name("test") .eventHandlerInvoker(eventHandlerInvoker) .messageSource(eventBus) .tokenStore(tokenStore) .transactionManager(NoTransactionManager.INSTANCE) .build(); testSubject.start(); // give it a bit of time to start Thread.sleep(200); assertTrue("Expected 9 invocations on Event Handler by now", countDownLatch.await(5, TimeUnit.SECONDS)); assertEquals(9, ackedEvents.size()); }
StreamableMessageSource<TrackedEventMessage<?>> stubSource = mock(StreamableMessageSource.class); testSubject = TrackingEventProcessor.builder() .name("test") .eventHandlerInvoker(eventHandlerInvoker) .messageSource(stubSource) .tokenStore(tokenStore) .transactionManager(NoTransactionManager.INSTANCE) .build();
@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)); }
@Test public void testMultiThreadProcessorGoesToRetryModeWhenOpenStreamFails() throws Exception { eventBus = spy(eventBus); tokenStore = new InMemoryTokenStore(); eventBus.publish(createEvents(5)); when(eventBus.openStream(any())).thenThrow(new MockException()).thenCallRealMethod(); final AcknowledgeByThread acknowledgeByThread = new AcknowledgeByThread(); CountDownLatch countDownLatch = new CountDownLatch(5); doAnswer(invocation -> { acknowledgeByThread.addMessage(Thread.currentThread(), (EventMessage<?>) invocation.getArguments()[0]); countDownLatch.countDown(); return null; }).when(mockHandler).handle(any()); testSubject = TrackingEventProcessor.builder() .name("test") .eventHandlerInvoker(eventHandlerInvoker) .messageSource(eventBus) .tokenStore(tokenStore) .transactionManager(NoTransactionManager.INSTANCE) .build(); testSubject.start(); assertTrue("Expected 5 invocations on Event Handler by now", countDownLatch.await(10, SECONDS)); acknowledgeByThread.assertEventsAddUpTo(5); verify(eventBus, times(2)).openStream(any()); }
@Test public void testTokenIsStoredOncePerEventBatch() throws Exception { testSubject = TrackingEventProcessor.builder() .name("test") .eventHandlerInvoker(eventHandlerInvoker) .messageSource(eventBus) .tokenStore(tokenStore) .transactionManager(NoTransactionManager.INSTANCE) .build(); CountDownLatch countDownLatch = new CountDownLatch(2); testSubject.registerHandlerInterceptor(((unitOfWork, interceptorChain) -> { unitOfWork.onCleanup(uow -> countDownLatch.countDown()); return interceptorChain.proceed(); })); testSubject.start(); // give it a bit of time to start Thread.sleep(200); eventBus.publish(createEvents(2)); assertTrue("Expected Unit of Work to have reached clean up phase for 2 messages", countDownLatch.await(5, TimeUnit.SECONDS)); InOrder inOrder = inOrder(tokenStore); inOrder.verify(tokenStore, times(1)).extendClaim(eq(testSubject.getName()), anyInt()); inOrder.verify(tokenStore, times(1)).storeToken(any(), any(), anyInt()); assertNotNull(tokenStore.fetchToken(testSubject.getName(), 0)); }
private TrackingEventProcessor trackingEventProcessor(String name, EventHandlerInvoker eventHandlerInvoker, TrackingEventProcessorConfiguration config, StreamableMessageSource<TrackedEventMessage<?>> source) { return TrackingEventProcessor.builder() .name(name) .eventHandlerInvoker(eventHandlerInvoker) .rollbackConfiguration(rollbackConfiguration(name)) .errorHandler(errorHandler(name)) .messageMonitor(messageMonitor(TrackingEventProcessor.class, name)) .messageSource(source) .tokenStore(tokenStore(name)) .transactionManager(transactionManager(name)) .trackingEventProcessorConfiguration(config) .build(); }
/** * Instantiate a Builder to be able to create a {@link TrackingEventProcessor}. * <p> * The {@link RollbackConfigurationType} defaults to a {@link RollbackConfigurationType#ANY_THROWABLE}, the * {@link ErrorHandler} is defaulted to a {@link PropagatingErrorHandler}, the {@link MessageMonitor} defaults to a * {@link NoOpMessageMonitor} and the {@link TrackingEventProcessorConfiguration} to a * {@link TrackingEventProcessorConfiguration#forSingleThreadedProcessing()} call. The Event Processor {@code name}, * {@link EventHandlerInvoker}, {@link StreamableMessageSource}, {@link TokenStore} and {@link TransactionManager} * are <b>hard requirements</b> and as such should be provided. * * @return a Builder to be able to create a {@link TrackingEventProcessor} */ public static Builder builder() { return new Builder(); }
private void configureProcessor(TrackingEventProcessorConfiguration processorConfiguration) { testSubject = TrackingEventProcessor.builder() .name("test") .eventHandlerInvoker(eventHandlerInvoker) .messageSource(eventBus) .tokenStore(tokenStore) .transactionManager(NoTransactionManager.INSTANCE) .trackingEventProcessorConfiguration(processorConfiguration) .build(); }