@Override public void cancelSchedule(String deadlineName, String scheduleId) { runOnPrepareCommitOrNow(() -> cancelSchedule(new DeadlineId(deadlineName, scheduleId))); }
/** * Initializes a {@link SimpleDeadlineManager} as specified through this Builder. * * @return a {@link SimpleDeadlineManager} as specified through this Builder */ public SimpleDeadlineManager build() { return new SimpleDeadlineManager(this); }
/** * Schedules a deadline after the given {@code triggerDuration} with given {@code deadlineName}. The payload of this * deadline will be {@code null}, as none is provided. The returned {@code scheduleId} and provided * {@code deadlineName} combination can be used to cancel the scheduled deadline. * The scope within which this call is made will be retrieved by the DeadlineManager itself. * * @param triggerDuration A {@link java.time.Duration} describing the waiting period before handling the deadline * @param deadlineName A {@link String} representing the name of the deadline to schedule * @return the {@code scheduleId} as a {@link String} to use when cancelling the schedule */ default String schedule(Duration triggerDuration, String deadlineName) { return schedule(triggerDuration, deadlineName, null); }
@Override public String schedule(Instant triggerDateTime, String deadlineName, Object messageOrPayload, ScopeDescriptor deadlineScope) { DeadlineMessage<Object> deadlineMessage = asDeadlineMessage(deadlineName, messageOrPayload); String deadlineId = JOB_NAME_PREFIX + deadlineMessage.getIdentifier(); runOnPrepareCommitOrNow(() -> { DeadlineMessage interceptedDeadlineMessage = processDispatchInterceptors(deadlineMessage); try { JobDetail jobDetail = buildJobDetail(interceptedDeadlineMessage, deadlineScope, new JobKey(deadlineId, deadlineName)); scheduler.scheduleJob(jobDetail, buildTrigger(triggerDateTime, jobDetail.getKey())); } catch (SchedulerException e) { throw new DeadlineException("An error occurred while setting a timer for a deadline", e); } }); return deadlineId; }
@Override public String schedule(Duration triggerDuration, String deadlineName, Object messageOrPayload, ScopeDescriptor deadlineScope) { DeadlineMessage<?> deadlineMessage = asDeadlineMessage(deadlineName, messageOrPayload); String deadlineId = deadlineMessage.getIdentifier(); runOnPrepareCommitOrNow(() -> { DeadlineMessage<?> interceptedDeadlineMessage = processDispatchInterceptors(deadlineMessage); DeadlineTask deadlineTask = new DeadlineTask(deadlineName, deadlineScope, interceptedDeadlineMessage, deadlineId); ScheduledFuture<?> scheduledFuture = scheduledExecutorService.schedule( deadlineTask, triggerDuration.toMillis(), TimeUnit.MILLISECONDS ); scheduledTasks.put(new DeadlineId(deadlineName, deadlineId), scheduledFuture); }); return deadlineId; }
/** * Provides the default {@link DeadlineManager} implementation. Subclasses may override this method to provide their * own default. * * @param config The configuration that supplies registered components. * @return The default DeadlineManager to use */ protected DeadlineManager defaultDeadlineManager(Configuration config) { return SimpleDeadlineManager.builder().scopeAwareProvider(new ConfigurationScopeAwareProvider(config)).build(); }
@Test public void testDispatchInterceptorOnAggregate() { configuration.deadlineManager().registerDispatchInterceptor(messages -> (i, m) -> GenericDeadlineMessage.asDeadlineMessage(m.getDeadlineName(), new DeadlinePayload("fakeId"))); configuration.commandGateway().sendAndWait(new CreateMyAggregateCommand(IDENTIFIER)); assertPublishedEvents(new MyAggregateCreatedEvent(IDENTIFIER), new DeadlineOccurredEvent(new DeadlinePayload("fakeId"))); }
@Override public GenericDeadlineMessage<T> andMetaData(Map<String, ?> additionalMetaData) { return new GenericDeadlineMessage<>( deadlineName, getDelegate().andMetaData(additionalMetaData), this::getTimestamp ); }
private boolean deadlineNameMatch(DeadlineMessage message) { return deadlineNameMatchesAll() || deadlineName.equals(message.getDeadlineName()); }
@Override public void cancelAll(String deadlineName) { runOnPrepareCommitOrNow( () -> scheduledTasks.entrySet().stream() .map(Map.Entry::getKey) .filter(scheduledTaskId -> scheduledTaskId.getDeadlineName().equals(deadlineName)) .forEach(this::cancelSchedule) ); }
private void cancelSchedule(JobKey jobKey) { try { if (!scheduler.deleteJob(jobKey)) { logger.warn("The job belonging to this token could not be deleted."); } } catch (SchedulerException e) { throw new DeadlineException("An error occurred while cancelling a timer for a deadline manager", e); } }
/** * Instantiate a Builder to be able to create a {@link SimpleDeadlineManager}. * <p> * The {@link ScheduledExecutorService} is defaulted to an {@link Executors#newSingleThreadScheduledExecutor()} * which contains an {@link AxonThreadFactory}, and the {@link TransactionManager} defaults to a * {@link NoTransactionManager}. The {@link ScopeAwareProvider} is a <b>hard requirement</b> and as such should be * provided. * * @return a Builder to be able to create a {@link SimpleDeadlineManager} */ public static Builder builder() { return new Builder(); }
/** * Instantiate a {@link SimpleDeadlineManager} based on the fields contained in the {@link Builder} to handle the * process around scheduling and triggering a {@link DeadlineMessage}. * <p> * Will assert that the {@link ScopeAwareProvider}, {@link ScheduledExecutorService} and {@link TransactionManager} * are not {@code null}, and will throw an {@link AxonConfigurationException} if either of them is {@code null}. * * @param builder the {@link Builder} used to instantiate a {@link SimpleDeadlineManager} instance */ protected SimpleDeadlineManager(Builder builder) { builder.validate(); this.scopeAwareProvider = builder.scopeAwareProvider; this.scheduledExecutorService = builder.scheduledExecutorService; this.transactionManager = builder.transactionManager; }
/** * Applies registered {@link MessageDispatchInterceptor}s to the given {@code message}. * * @param message the deadline message to be intercepted * @param <T> the type of deadline message payload * @return intercepted message */ @SuppressWarnings("unchecked") protected <T> DeadlineMessage<T> processDispatchInterceptors(DeadlineMessage<T> message) { DeadlineMessage<T> intercepted = message; for (MessageDispatchInterceptor<? super DeadlineMessage<?>> interceptor : dispatchInterceptors()) { intercepted = (DeadlineMessage<T>) interceptor.handle(intercepted); } return intercepted; } }
@Override public DeadlineManager buildDeadlineManager(Configuration configuration) { return SimpleDeadlineManager.builder() .scopeAwareProvider(new ConfigurationScopeAwareProvider(configuration)) .build(); } }
@Override public GenericDeadlineMessage<T> withMetaData(Map<String, ?> metaData) { return new GenericDeadlineMessage<>(deadlineName, getDelegate().withMetaData(metaData), this::getTimestamp); }
/** * Schedules a deadline at given {@code triggerDateTime} with given {@code deadlineName}. The payload of this * deadline will be {@code null}, as none is provided. The returned {@code scheduleId} and provided * {@code deadlineName} combination can be used to cancel the scheduled deadline. The scope within which this call * is made will be retrieved by the DeadlineManager itself. * * @param triggerDateTime A {@link java.time.Instant} denoting the moment to trigger the deadline handling * @param deadlineName A {@link String} representing the name of the deadline to schedule * @return the {@code scheduleId} as a {@link String} to use when cancelling the schedule */ default String schedule(Instant triggerDateTime, String deadlineName) { return schedule(triggerDateTime, deadlineName, null); }
/** * Schedules a deadline at given {@code triggerDateTime} with provided context. The returned {@code scheduleId} and * provided {@code deadlineName} combination can be used to cancel the scheduled deadline. * <p> * The given {@code messageOrPayload} may be any object, as well as a DeadlineMessage. In the latter case, the * instance provided is the donor for the payload and {@link org.axonframework.messaging.MetaData} of the actual * deadline being used. In the former case, the given {@code messageOrPayload} will be wrapped as the payload of a * {@link DeadlineMessage}. * </p> * * @param triggerDateTime A {@link Instant} denoting the moment to trigger the deadline handling * @param deadlineName A {@link String} representing the name of the deadline to schedule * @param messageOrPayload A {@link org.axonframework.messaging.Message} or payload for a message as an * {@link Object} * @param deadlineScope A {@link ScopeDescriptor} describing the scope within which the deadline was scheduled * @return the {@code scheduleId} as a {@link String} to use when cancelling the schedule */ default String schedule(Instant triggerDateTime, String deadlineName, Object messageOrPayload, ScopeDescriptor deadlineScope) { return schedule(triggerDateTime, deadlineName, messageOrPayload, deadlineScope); }
@CommandHandler public void on(ScheduleSpecificDeadline message, DeadlineManager deadlineManager) { Object deadlinePayload = message.payload; if (deadlinePayload != null) { deadlineManager.schedule(Duration.ofMillis(DEADLINE_TIMEOUT), "specificDeadlineName", deadlinePayload); } else { deadlineManager.schedule(Duration.ofMillis(DEADLINE_TIMEOUT), "payloadlessDeadline"); } }
@SagaEventHandler(associationProperty = "id") public void on(ScheduleSpecificDeadline message, DeadlineManager deadlineManager) { Object deadlinePayload = message.payload; if (deadlinePayload != null) { deadlineManager.schedule(Duration.ofMillis(DEADLINE_TIMEOUT), "specificDeadlineName", deadlinePayload); } else { deadlineManager.schedule(Duration.ofMillis(DEADLINE_TIMEOUT), "payloadlessDeadline"); } }