ServiceActivator / Poller似乎忽略了Trigger

时间:2017-03-15 12:01:05

标签: spring-integration

我正在使用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。自述文件包含解释如何复制的注释。

2 个答案:

答案 0 :(得分:0)

注意你有max-messages-per-poll="${poller.maxMessagesPerPoll}"。因此,如果队列中存在该号码的消息,则将在一个计划任务期间处理它们。

如果没有消息,这是正确的,轮询器将移动到nextExecutionTime并进入睡眠状态。

尽量让它像1一样,至少在试验时,弄清楚它是如何运作的。

查看CustomPeriodicTrigger

的代码会有所帮助

<强>更新

您的问题可能是customTaskExecutor没有足够的${container.threads},并且许多任务都存储在内部队列中。当您的触发器停止轮询时,这些任务就会到达现场......

答案 1 :(得分:0)

我将ThreadPoolTask​​Executor的配置修改为以下内容:

<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