我正在使用SpringBoot 1.4.4.RELEASE和Brixton.SR6。我正在使用SpringIntegration与JMS和RabbitMQ。
我有一个JMS支持的队列定义为:
<int-jms:channel id="actionInstructionTransformed" queue-name="Action.FieldJmsBackup" message-driven="false" />
我有一个默认的轮询器定义为:
<bean id="customPeriodicTrigger" class="uk.gov.ons.ctp.response.kirona.drs.utility.CustomPeriodicTrigger" />
<bean id="customTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="${container.threads}" />
</bean>
<int:poller id="customPoller" default="true" trigger="customPeriodicTrigger" task-executor="customTaskExecutor" max-messages-per-poll="${poller.maxMessagesPerPoll}" error-channel="drsGatewayPollerError">
<int:transactional propagation="REQUIRED" read-only="true" transaction-manager="transactionManager"/>
</int:poller>
我的CustomPeriodicTrigger实现了org.springframework.scheduling.Trigger。我有覆盖公共日期nextExecutionTime(TriggerContext triggerContext)。在我的日志中,我可以看到nextExecutionTime被不断调用,现在输出时间。服务激活器处理好。然后在某个阶段,在nextExecutionTime中,我将下一个执行时间设置为将来的日期,因为我想从JMS队列中暂停处理。在日志中,我可以看到nextExecutionTime将来输出我的日期,然后在达到未来日期之前不再调用它。
CustomPeriodicTrigger的代码如下:
@Slf4j
@Data
public class CustomPeriodicTrigger implements Trigger {
@Autowired
private PollerConfig pollerConfig;
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
Date currentDate = new Date(System.currentTimeMillis());
Date earliestActiveDate = provideEarliestActiveDate(currentDate);
log.debug("earliestActiveDate is {}", earliestActiveDate);
Date result = null;
if (earliestActiveDate != null) {
result = new Date(earliestActiveDate.getTime() + pollerConfig.getInitialDelay());
} else {
if (triggerContext.lastScheduledExecutionTime() == null) {
result = new Date(System.currentTimeMillis() + pollerConfig.getInitialDelay());
} else {
if (pollerConfig.isFixedRate()) {
result = new Date(triggerContext.lastScheduledExecutionTime().getTime() +
pollerConfig.getFixedDelay());
} else {
result = new Date(triggerContext.lastCompletionTime().getTime() +
pollerConfig.getFixedDelay());
}
}
}
log.debug("result is {}", result);
return result;
}
/**
* This returns null if the current date is active, ie outside of support hours.
* If the current date is within support hours, it returns the earliest active date.
*
* @param date the current date
* @return aDate
*/
public Date provideEarliestActiveDate(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int dateHours = calendar.get(Calendar.HOUR_OF_DAY);
int dateMinutes = calendar.get(Calendar.MINUTE);
int supportHourStart = pollerConfig.getSupportHourStart();
int supportMinuteStart = pollerConfig.getSupportMinuteStart();
int supportHourEnd = pollerConfig.getSupportHourEnd();
if (dateHours < supportHourStart || dateHours >= supportHourEnd) {
return null;
} else {
if (dateMinutes < supportMinuteStart) {
return null;
} else {
calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, supportHourEnd);
calendar.set(Calendar.MINUTE, 0);
return calendar.getTime();
}
}
}
}
下面是我的application.yml:
poller:
fixedDelay: 100
fixedRate: false
initialDelay: 1000
maxMessagesPerPoll: 1
supportHourStart: 11
supportMinuteStart: 31
supportHourEnd: 18
问题在于,与此同时,如果我在Action.FieldJmsBackup上排队了消息,则会对它们进行处理。
我的服务激活器定义为:@ServiceActivator(inputChannel = "actionInstructionTransformed", poller = @Poller(value = "customPoller"))
public final void processInstruction(final ActionInstruction instruction) {
我已经为org.springframework.integration打开了调试功能,当处理完消息时,尽管轮询器说它不应该,但我可以在日志中看到:
2017-03-15 11:30:40.068 DEBUG [DRSGatewaySvc,,,] 20634 --- [mTaskExecutor-1] o.s.i.handler.ServiceActivatingHandler : handler 'ServiceActivator for [org.springframework.integration.handler.MethodInvokingMessageProcessor@6e821210] (actionInstructionReceiverImpl.processInstruction.serviceActivator.handler)' produced no reply for request Message: GenericMessage [payload=uk.gov.ons.ctp.response.action.message.instruction.ActionInstruction@1ce9e8d6, headers={jms_destination=RMQDestination{destinationName='Action.Field', queue(permanent)', amqpExchangeName='jms.durable.queues', amqpRoutingKey='Action.Field', amqpQueueName='Action.Field'}, X-Message-Sent=true, messageSent=true, priority=4, jms_timestamp=1489053876187, spanTraceId=8d176bdcbb9b1ace, spanId=74113b330ce8133e, jms_redelivered=false, X-B3-SpanId=74113b330ce8133e, X-B3-Sampled=0, X-B3-TraceId=8d176bdcbb9b1ace, id=5c429c04-1df8-6197-42dc-45236ec4a288, HANDLER=Field, spanSampled=0, jms_messageId=ID:9a2d4ca0-e173-4725-a2eb-34328c4160f7, timestamp=1489054627940}]
2017-03-15 11:30:40.068 DEBUG [DRSGatewaySvc,,,] 20634 --- [mTaskExecutor-1] o.s.i.t.PseudoTransactionManager : Initiating transaction commit
2017-03-15 11:30:40.148 DEBUG [DRSGatewaySvc,,,] 20634 --- [mTaskExecutor-1] o.s.i.t.PseudoTransactionManager : Creating new transaction with name [org.springframework.integration.endpoint.AbstractPollingEndpoint$1.call]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly
2017-03-15 11:30:40.149 DEBUG [DRSGatewaySvc,,,] 20634 --- [mTaskExecutor-1] o.s.integration.jms.DynamicJmsTemplate : Executing callback on JMS Session: Cached JMS Session: com.rabbitmq.jms.client.RMQSession@345df5df
2017-03-15 11:30:40.166 DEBUG [DRSGatewaySvc,,,] 20634 --- [mTaskExecutor-1] o.s.integration.jms.PollableJmsChannel : postReceive on channel 'actionInstructionTransformed', message: GenericMessage [payload=uk.gov.ons.ctp.response.action.message.instruction.ActionInstruction@1d71b5e7, headers={jms_destination=RMQDestination{destinationName='Action.Field', queue(permanent)', amqpExchangeName='jms.durable.queues', amqpRoutingKey='Action.Field', amqpQueueName='Action.Field'}, X-Message-Sent=true, messageSent=true, priority=4, jms_timestamp=1489053876220, spanTraceId=8d176bdcbb9b1ace, spanId=18a59ce043b47b3c, jms_redelivered=false, X-B3-SpanId=18a59ce043b47b3c, X-B3-Sampled=0, X-B3-TraceId=8d176bdcbb9b1ace, id=fc05c4e2-5c8c-783b-ccbc-e9f46d662ff7, HANDLER=Field, spanSampled=0, jms_messageId=ID:3c794447-49bc-4b47-9e60-eead8d6aa715, timestamp=1489054627979}]
2017-03-15 11:30:40.166 DEBUG [DRSGatewaySvc,,,] 20634 --- [mTaskExecutor-1] o.s.i.endpoint.PollingConsumer : Poll resulted in Message: GenericMessage [payload=uk.gov.ons.ctp.response.action.message.instruction.ActionInstruction@1d71b5e7, headers={jms_destination=RMQDestination{destinationName='Action.Field', queue(permanent)', amqpExchangeName='jms.durable.queues', amqpRoutingKey='Action.Field', amqpQueueName='Action.Field'}, X-Message-Sent=true, messageSent=true, priority=4, jms_timestamp=1489053876220, spanTraceId=8d176bdcbb9b1ace, spanId=18a59ce043b47b3c, jms_redelivered=false, X-B3-SpanId=18a59ce043b47b3c, X-B3-Sampled=0, X-B3-TraceId=8d176bdcbb9b1ace, id=fc05c4e2-5c8c-783b-ccbc-e9f46d662ff7, HANDLER=Field, spanSampled=0, jms_messageId=ID:3c794447-49bc-4b47-9e60-eead8d6aa715, timestamp=1489054627979}]
2017-03-15 11:30:40.166 DEBUG [DRSGatewaySvc,,,] 20634 --- [mTaskExecutor-1] o.s.i.handler.ServiceActivatingHandler : ServiceActivator for [org.springframework.integration.handler.MethodInvokingMessageProcessor@6e821210] (actionInstructionReceiverImpl.processInstruction.serviceActivator.handler) received message: GenericMessage [payload=uk.gov.ons.ctp.response.action.message.instruction.ActionInstruction@1d71b5e7, headers={jms_destination=RMQDestination{destinationName='Action.Field', queue(permanent)', amqpExchangeName='jms.durable.queues', amqpRoutingKey='Action.Field', amqpQueueName='Action.Field'}, X-Message-Sent=true, messageSent=true, priority=4, jms_timestamp=1489053876220, spanTraceId=8d176bdcbb9b1ace, spanId=18a59ce043b47b3c, jms_redelivered=false, X-B3-SpanId=18a59ce043b47b3c, X-B3-Sampled=0, X-B3-TraceId=8d176bdcbb9b1ace, id=fc05c4e2-5c8c-783b-ccbc-e9f46d662ff7, HANDLER=Field, spanSampled=0, jms_messageId=ID:3c794447-49bc-4b47-9e60-eead8d6aa715, timestamp=1489054627979}]
如果你能指出我正确的方向,那就太好了。
从我的application.yml和CustomPeriodicTrigger,您可以看到我有3个被动期,在此期间我不希望ServiceActivator处理:00:01-08:30,12:09-13:30和21 :00-23:59。如果我在12:00开始我的应用程序,它将一直处理到12:09,然后它不会停止,尽管在12:09执行时CustomPeriodicTrigger = 13:30中的nextExecutionTime。现在如果我在12:30开始我的应用程序,我可以在CustomPeriodicTrigger = 13:30看到相同的日志条目说nextExecutionTime。并且,它确实正常工作,因为直到13:30才进行处理。我不明白为什么在第一种情况下,我的自定义perioridic触发器被忽略了。
我已经整理了一个示例项目来帮助复制问题。见https://github.com/pilif42/projectTotestTaskExecutorPauses。自述文件包含解释如何复制的注释。
答案 0 :(得分:0)
注意你有max-messages-per-poll="${poller.maxMessagesPerPoll}"
。因此,如果队列中存在该号码的消息,则将在一个计划任务期间处理它们。
如果没有消息,这是正确的,轮询器将移动到nextExecutionTime
并进入睡眠状态。
尽量让它像1
一样,至少在试验时,弄清楚它是如何运作的。
查看CustomPeriodicTrigger
。
<强>更新强>
您的问题可能是customTaskExecutor没有足够的${container.threads}
,并且许多任务都存储在内部队列中。当您的触发器停止轮询时,这些任务就会到达现场......
答案 1 :(得分:0)
我将ThreadPoolTaskExecutor的配置修改为以下内容:
<bean id="customTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="1" />
<property name="maxPoolSize" value="1" />
<property name="queueCapacity" value="2" />
</bean>
我可以看到,一旦队列长度(值2)被消耗,进程就会暂停。
但是,我用下面的内容填写了我的日志。这是有道理的,因为队列处于最大容量并且不能接受任何更多消息。这些错误应该是WARN吗?:
2017-03-21 12:16:00.002 ERROR [projectTotestTaskExecutorPauses,83e9d055613437a4,83e9d055613437a4,false] 16069 --- [ask-scheduler-9] o.s.integration.handler.LoggingHandler : org.springframework.core.task.TaskRejectedException: Executor [java.util.concurrent.ThreadPoolExecutor@77f8a1a8[Running, pool size = 1, active threads = 1, queued tasks = 2, completed tasks = 1]] did not accept task: org.springframework.integration.util.ErrorHandlingTaskExecutor$1@61c0532b
at org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor.execute(ThreadPoolTaskExecutor.java:296)
at org.springframework.integration.util.ErrorHandlingTaskExecutor.execute(ErrorHandlingTaskExecutor.java:51)
at org.springframework.integration.endpoint.AbstractPollingEndpoint$Poller.run(AbstractPollingEndpoint.java:344)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.util.concurrent.RejectedExecutionException: Task org.springframework.integration.util.ErrorHandlingTaskExecutor$1@61c0532b rejected from java.util.concurrent.ThreadPoolExecutor@77f8a1a8[Running, pool size = 1, active threads = 1, queued tasks = 2, completed tasks = 1]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
at org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor.execute(ThreadPoolTaskExecutor.java:293)
... 11 more