You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2026/07/15 10:58:53 UTC
(camel) 01/01: CAMEL-24079: Fix QuartzScheduledPollConsumerScheduler ignoring startScheduler=false
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch fix/CAMEL-24079
in repository https://gitbox.apache.org/repos/asf/camel.git
commit cd7e748a8d84ceb77cb2375e127690819f1092ea
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Wed Jul 15 12:58:09 2026 +0200
CAMEL-24079: Fix QuartzScheduledPollConsumerScheduler ignoring startScheduler=false
Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
Signed-off-by: Claus Ibsen <cl...@gmail.com>
---
.../QuartzScheduledPollConsumerScheduler.java | 74 +++++++++++-----------
...eConsumerQuartzSchedulerStartSchedulerTest.java | 56 ++++++++++++++++
2 files changed, 94 insertions(+), 36 deletions(-)
diff --git a/components/camel-quartz/src/main/java/org/apache/camel/pollconsumer/quartz/QuartzScheduledPollConsumerScheduler.java b/components/camel-quartz/src/main/java/org/apache/camel/pollconsumer/quartz/QuartzScheduledPollConsumerScheduler.java
index 23e11316d1ee..e3c87949fbfe 100644
--- a/components/camel-quartz/src/main/java/org/apache/camel/pollconsumer/quartz/QuartzScheduledPollConsumerScheduler.java
+++ b/components/camel-quartz/src/main/java/org/apache/camel/pollconsumer/quartz/QuartzScheduledPollConsumerScheduler.java
@@ -71,6 +71,8 @@ public class QuartzScheduledPollConsumerScheduler extends ServiceSupport
private boolean deleteJob = true;
private volatile CronTrigger trigger;
private volatile JobDetail job;
+ private volatile boolean scheduled;
+ private volatile TriggerKey rescheduleKey;
@Override
public void onInit(Consumer consumer) {
@@ -100,16 +102,43 @@ public class QuartzScheduledPollConsumerScheduler extends ServiceSupport
@Override
public void startScheduler() {
- // the quartz component starts the scheduler
+ if (!scheduled) {
+ try {
+ if (rescheduleKey != null) {
+ LOG.debug("Re-scheduling job: {} with trigger: {}", job, trigger.getKey());
+ quartzScheduler.rescheduleJob(rescheduleKey, trigger);
+ } else {
+ LOG.debug("Scheduling job: {} with trigger: {}", job, trigger.getKey());
+ try {
+ quartzScheduler.scheduleJob(job, trigger);
+ } catch (ObjectAlreadyExistsException ex) {
+ QuartzComponent quartz = getCamelContext().getComponent("quartz", QuartzComponent.class);
+ if (!(quartz.isClustered())) {
+ throw ex;
+ } else {
+ TriggerKey triggerKey = trigger.getKey();
+ trigger = (CronTrigger) quartzScheduler.getTrigger(triggerKey);
+ if (trigger == null) {
+ throw new SchedulerException("Trigger could not be found in quartz scheduler.");
+ }
+ }
+ }
+ }
+ scheduled = true;
+ if (LOG.isInfoEnabled()) {
+ LOG.info("Job {} (triggerType={}, jobClass={}) is scheduled. Next fire date is {}",
+ trigger.getKey(), trigger.getClass().getSimpleName(),
+ job.getJobClass().getSimpleName(), trigger.getNextFireTime());
+ }
+ } catch (SchedulerException e) {
+ throw RuntimeCamelException.wrapRuntimeCamelException(e);
+ }
+ }
}
@Override
public boolean isSchedulerStarted() {
- try {
- return quartzScheduler != null && quartzScheduler.isStarted();
- } catch (SchedulerException e) {
- return false;
- }
+ return scheduled;
}
@Override
@@ -244,9 +273,6 @@ public class QuartzScheduledPollConsumerScheduler extends ServiceSupport
LOG.debug("Setting user extra triggerParameters {}", copy);
PropertyBindingSupport.bindProperties(camelContext, trigger, copy);
}
-
- LOG.debug("Scheduling job: {} with trigger: {}", job, trigger.getKey());
- quartzScheduler.scheduleJob(job, trigger);
} else {
checkTriggerIsNonConflicting(existingTrigger);
@@ -264,36 +290,10 @@ public class QuartzScheduledPollConsumerScheduler extends ServiceSupport
.withSchedule(CronScheduleBuilder.cronSchedule(getCron()).inTimeZone(getTimeZone()))
.build();
- // Reschedule job if trigger settings were changed
if (hasTriggerChanged(existingTrigger, trigger)) {
- LOG.debug("Re-scheduling job: {} with trigger: {}", job, trigger.getKey());
- quartzScheduler.rescheduleJob(triggerKey, trigger);
- } else {
- // Schedule it now. Remember that scheduler might not be started it, but we can schedule now.
- LOG.debug("Scheduling job: {} with trigger: {}", job, trigger.getKey());
- try {
- // Schedule it now. Remember that scheduler might not be started it, but we can schedule now.
- quartzScheduler.scheduleJob(job, trigger);
- } catch (ObjectAlreadyExistsException ex) {
- // some other VM might may have stored the job & trigger in DB in clustered mode, in the mean time
- QuartzComponent quartz = getCamelContext().getComponent("quartz", QuartzComponent.class);
- if (!(quartz.isClustered())) {
- throw ex;
- } else {
- trigger = (CronTrigger) quartzScheduler.getTrigger(triggerKey);
- if (trigger == null) {
- throw new SchedulerException("Trigger could not be found in quartz scheduler.");
- }
- }
- }
+ rescheduleKey = triggerKey;
}
}
-
- if (LOG.isInfoEnabled()) {
- LOG.info("Job {} (triggerType={}, jobClass={}) is scheduled. Next fire date is {}",
- trigger.getKey(), trigger.getClass().getSimpleName(),
- job.getJobClass().getSimpleName(), trigger.getNextFireTime());
- }
}
@Override
@@ -313,6 +313,8 @@ public class QuartzScheduledPollConsumerScheduler extends ServiceSupport
quartzScheduler.unscheduleJob(trigger.getKey());
}
}
+ scheduled = false;
+ rescheduleKey = null;
}
private void checkTriggerIsNonConflicting(Trigger trigger) {
diff --git a/components/camel-quartz/src/test/java/org/apache/camel/pollconsumer/quartz/FileConsumerQuartzSchedulerStartSchedulerTest.java b/components/camel-quartz/src/test/java/org/apache/camel/pollconsumer/quartz/FileConsumerQuartzSchedulerStartSchedulerTest.java
new file mode 100644
index 000000000000..b70689d1b328
--- /dev/null
+++ b/components/camel-quartz/src/test/java/org/apache/camel/pollconsumer/quartz/FileConsumerQuartzSchedulerStartSchedulerTest.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.pollconsumer.quartz;
+
+import java.nio.file.Path;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.apache.camel.test.junit6.TestSupport;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import static org.awaitility.Awaitility.await;
+
+public class FileConsumerQuartzSchedulerStartSchedulerTest extends CamelTestSupport {
+ @TempDir
+ Path testDirectory;
+
+ @Test
+ public void testStartSchedulerFalseMustNotPoll() throws Exception {
+ template.sendBodyAndHeader(TestSupport.fileUri(testDirectory), "Hello World", Exchange.FILE_NAME, "hello.txt");
+
+ getMockEndpoint("mock:result").expectedMessageCount(0);
+
+ // startScheduler=false should prevent polling even with scheduler=quartz
+ await().during(3, TimeUnit.SECONDS).atMost(4, TimeUnit.SECONDS)
+ .untilAsserted(() -> getMockEndpoint("mock:result").assertIsSatisfied());
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ from(TestSupport.fileUri(testDirectory, "?scheduler=quartz&scheduler.cron=0/2+*+*+*+*+?&startScheduler=false"))
+ .to("mock:result");
+ }
+ };
+ }
+}