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 2021/03/22 15:07:21 UTC

[camel] 01/02: CAMEL-16383: camel-scheduler - ConcurrentTasks option renamed to poolSize and avoid scheduler to cause concurrent triggers that causes routing problems.

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git

commit daa4348271e84658cb19eb9341c5759da3c94296
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Mar 22 16:03:17 2021 +0100

    CAMEL-16383: camel-scheduler - ConcurrentTasks option renamed to poolSize and avoid scheduler to cause concurrent triggers that causes routing problems.
---
 .../camel/catalog/docs/scheduler-component.adoc    |  4 +-
 .../scheduler/SchedulerComponentConfigurer.java    | 12 ++--
 .../scheduler/SchedulerEndpointConfigurer.java     | 12 ++--
 .../scheduler/SchedulerEndpointUriFactory.java     |  2 +-
 .../camel/component/scheduler/scheduler.json       |  4 +-
 .../src/main/docs/scheduler-component.adoc         |  4 +-
 .../component/scheduler/SchedulerComponent.java    | 18 +++---
 .../component/scheduler/SchedulerEndpoint.java     | 12 ++--
 .../dsl/SchedulerComponentBuilderFactory.java      | 12 ++--
 .../component/scheduler/SchedulerBlockingTest.java | 44 +++++++++++++++
 .../scheduler/SchedulerNoPolledMessagesTest.java   |  2 +-
 .../TwoSchedulerConcurrentTasksOneRouteTest.java   |  8 +--
 .../scheduler/TwoSchedulerConcurrentTasksTest.java |  2 +-
 .../dsl/SchedulerEndpointBuilderFactory.java       | 64 +++++++++++-----------
 .../DefaultScheduledPollConsumerScheduler.java     | 24 ++++----
 .../modules/ROOT/pages/scheduler-component.adoc    |  4 +-
 .../ROOT/pages/camel-3x-upgrade-guide-3_10.adoc    | 19 +++++++
 .../modules/ROOT/pages/camel-3x-upgrade-guide.adoc |  1 +
 18 files changed, 153 insertions(+), 95 deletions(-)

diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/scheduler-component.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/scheduler-component.adoc
index 96148bd..1a571f0 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/scheduler-component.adoc
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/scheduler-component.adoc
@@ -51,7 +51,7 @@ The Scheduler component supports 3 options, which are listed below.
 | Name | Description | Default | Type
 | *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
 | *autowiredEnabled* (advanced) | Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc. | true | boolean
-| *concurrentTasks* (scheduler) | Number of threads used by the scheduling thread pool. Is by default using a single thread | 1 | int
+| *poolSize* (scheduler) | Number of core threads in the thread pool used by the scheduling thread pool. Is by default using a single thread | 1 | int
 |===
 // component options: END
 
@@ -90,10 +90,10 @@ with the following path and query parameters:
 | *backoffErrorThreshold* (scheduler) | The number of subsequent error polls (failed due some error) that should happen before the backoffMultipler should kick-in. |  | int
 | *backoffIdleThreshold* (scheduler) | The number of subsequent idle polls that should happen before the backoffMultipler should kick-in. |  | int
 | *backoffMultiplier* (scheduler) | To let the scheduled polling consumer backoff if there has been a number of subsequent idles/errors in a row. The multiplier is then the number of polls that will be skipped before the next actual attempt is happening again. When this option is in use then backoffIdleThreshold and/or backoffErrorThreshold must also be configured. |  | int
-| *concurrentTasks* (scheduler) | Number of threads used by the scheduling thread pool. Is by default using a single thread | 1 | int
 | *delay* (scheduler) | Milliseconds before the next poll. | 500 | long
 | *greedy* (scheduler) | If greedy is enabled, then the ScheduledPollConsumer will run immediately again, if the previous run polled 1 or more messages. | false | boolean
 | *initialDelay* (scheduler) | Milliseconds before the first poll starts. | 1000 | long
+| *poolSize* (scheduler) | Number of core threads in the thread pool used by the scheduling thread pool. Is by default using a single thread | 1 | int
 | *repeatCount* (scheduler) | Specifies a maximum limit of number of fires. So if you set it to 1, the scheduler will only fire once. If you set it to 5, it will only fire five times. A value of zero or negative means fire forever. | 0 | long
 | *runLoggingLevel* (scheduler) | The consumer logs a start/complete log line when it polls. This option allows you to configure the logging level for that. There are 6 enums and the value can be one of: TRACE, DEBUG, INFO, WARN, ERROR, OFF | TRACE | LoggingLevel
 | *scheduledExecutorService* (scheduler) | Allows for configuring a custom/shared thread pool to use for the consumer. By default each consumer has its own single threaded thread pool. |  | ScheduledExecutorService
diff --git a/components/camel-scheduler/src/generated/java/org/apache/camel/component/scheduler/SchedulerComponentConfigurer.java b/components/camel-scheduler/src/generated/java/org/apache/camel/component/scheduler/SchedulerComponentConfigurer.java
index c4bb132..46de04c 100644
--- a/components/camel-scheduler/src/generated/java/org/apache/camel/component/scheduler/SchedulerComponentConfigurer.java
+++ b/components/camel-scheduler/src/generated/java/org/apache/camel/component/scheduler/SchedulerComponentConfigurer.java
@@ -25,8 +25,8 @@ public class SchedulerComponentConfigurer extends PropertyConfigurerSupport impl
         case "autowiredEnabled": target.setAutowiredEnabled(property(camelContext, boolean.class, value)); return true;
         case "bridgeerrorhandler":
         case "bridgeErrorHandler": target.setBridgeErrorHandler(property(camelContext, boolean.class, value)); return true;
-        case "concurrenttasks":
-        case "concurrentTasks": target.setConcurrentTasks(property(camelContext, int.class, value)); return true;
+        case "poolsize":
+        case "poolSize": target.setPoolSize(property(camelContext, int.class, value)); return true;
         default: return false;
         }
     }
@@ -38,8 +38,8 @@ public class SchedulerComponentConfigurer extends PropertyConfigurerSupport impl
         case "autowiredEnabled": return boolean.class;
         case "bridgeerrorhandler":
         case "bridgeErrorHandler": return boolean.class;
-        case "concurrenttasks":
-        case "concurrentTasks": return int.class;
+        case "poolsize":
+        case "poolSize": return int.class;
         default: return null;
         }
     }
@@ -52,8 +52,8 @@ public class SchedulerComponentConfigurer extends PropertyConfigurerSupport impl
         case "autowiredEnabled": return target.isAutowiredEnabled();
         case "bridgeerrorhandler":
         case "bridgeErrorHandler": return target.isBridgeErrorHandler();
-        case "concurrenttasks":
-        case "concurrentTasks": return target.getConcurrentTasks();
+        case "poolsize":
+        case "poolSize": return target.getPoolSize();
         default: return null;
         }
     }
diff --git a/components/camel-scheduler/src/generated/java/org/apache/camel/component/scheduler/SchedulerEndpointConfigurer.java b/components/camel-scheduler/src/generated/java/org/apache/camel/component/scheduler/SchedulerEndpointConfigurer.java
index e1ffdd9..6e91f49 100644
--- a/components/camel-scheduler/src/generated/java/org/apache/camel/component/scheduler/SchedulerEndpointConfigurer.java
+++ b/components/camel-scheduler/src/generated/java/org/apache/camel/component/scheduler/SchedulerEndpointConfigurer.java
@@ -29,8 +29,6 @@ public class SchedulerEndpointConfigurer extends PropertyConfigurerSupport imple
         case "backoffMultiplier": target.setBackoffMultiplier(property(camelContext, int.class, value)); return true;
         case "bridgeerrorhandler":
         case "bridgeErrorHandler": target.setBridgeErrorHandler(property(camelContext, boolean.class, value)); return true;
-        case "concurrenttasks":
-        case "concurrentTasks": target.setConcurrentTasks(property(camelContext, int.class, value)); return true;
         case "delay": target.setDelay(property(camelContext, long.class, value)); return true;
         case "exceptionhandler":
         case "exceptionHandler": target.setExceptionHandler(property(camelContext, org.apache.camel.spi.ExceptionHandler.class, value)); return true;
@@ -41,6 +39,8 @@ public class SchedulerEndpointConfigurer extends PropertyConfigurerSupport imple
         case "initialDelay": target.setInitialDelay(property(camelContext, long.class, value)); return true;
         case "pollstrategy":
         case "pollStrategy": target.setPollStrategy(property(camelContext, org.apache.camel.spi.PollingConsumerPollStrategy.class, value)); return true;
+        case "poolsize":
+        case "poolSize": target.setPoolSize(property(camelContext, int.class, value)); return true;
         case "repeatcount":
         case "repeatCount": target.setRepeatCount(property(camelContext, long.class, value)); return true;
         case "runlogginglevel":
@@ -74,8 +74,6 @@ public class SchedulerEndpointConfigurer extends PropertyConfigurerSupport imple
         case "backoffMultiplier": return int.class;
         case "bridgeerrorhandler":
         case "bridgeErrorHandler": return boolean.class;
-        case "concurrenttasks":
-        case "concurrentTasks": return int.class;
         case "delay": return long.class;
         case "exceptionhandler":
         case "exceptionHandler": return org.apache.camel.spi.ExceptionHandler.class;
@@ -86,6 +84,8 @@ public class SchedulerEndpointConfigurer extends PropertyConfigurerSupport imple
         case "initialDelay": return long.class;
         case "pollstrategy":
         case "pollStrategy": return org.apache.camel.spi.PollingConsumerPollStrategy.class;
+        case "poolsize":
+        case "poolSize": return int.class;
         case "repeatcount":
         case "repeatCount": return long.class;
         case "runlogginglevel":
@@ -120,8 +120,6 @@ public class SchedulerEndpointConfigurer extends PropertyConfigurerSupport imple
         case "backoffMultiplier": return target.getBackoffMultiplier();
         case "bridgeerrorhandler":
         case "bridgeErrorHandler": return target.isBridgeErrorHandler();
-        case "concurrenttasks":
-        case "concurrentTasks": return target.getConcurrentTasks();
         case "delay": return target.getDelay();
         case "exceptionhandler":
         case "exceptionHandler": return target.getExceptionHandler();
@@ -132,6 +130,8 @@ public class SchedulerEndpointConfigurer extends PropertyConfigurerSupport imple
         case "initialDelay": return target.getInitialDelay();
         case "pollstrategy":
         case "pollStrategy": return target.getPollStrategy();
+        case "poolsize":
+        case "poolSize": return target.getPoolSize();
         case "repeatcount":
         case "repeatCount": return target.getRepeatCount();
         case "runlogginglevel":
diff --git a/components/camel-scheduler/src/generated/java/org/apache/camel/component/scheduler/SchedulerEndpointUriFactory.java b/components/camel-scheduler/src/generated/java/org/apache/camel/component/scheduler/SchedulerEndpointUriFactory.java
index 073c2bf..8bb4b9d 100644
--- a/components/camel-scheduler/src/generated/java/org/apache/camel/component/scheduler/SchedulerEndpointUriFactory.java
+++ b/components/camel-scheduler/src/generated/java/org/apache/camel/component/scheduler/SchedulerEndpointUriFactory.java
@@ -24,10 +24,10 @@ public class SchedulerEndpointUriFactory extends org.apache.camel.support.compon
         props.add("backoffMultiplier");
         props.add("synchronous");
         props.add("sendEmptyMessageWhenIdle");
+        props.add("poolSize");
         props.add("schedulerProperties");
         props.add("exchangePattern");
         props.add("initialDelay");
-        props.add("concurrentTasks");
         props.add("backoffIdleThreshold");
         props.add("scheduler");
         props.add("bridgeErrorHandler");
diff --git a/components/camel-scheduler/src/generated/resources/org/apache/camel/component/scheduler/scheduler.json b/components/camel-scheduler/src/generated/resources/org/apache/camel/component/scheduler/scheduler.json
index 1918d99..ee37b47 100644
--- a/components/camel-scheduler/src/generated/resources/org/apache/camel/component/scheduler/scheduler.json
+++ b/components/camel-scheduler/src/generated/resources/org/apache/camel/component/scheduler/scheduler.json
@@ -24,7 +24,7 @@
   "componentProperties": {
     "bridgeErrorHandler": { "kind": "property", "displayName": "Bridge Error Handler", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a me [...]
     "autowiredEnabled": { "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which t [...]
-    "concurrentTasks": { "kind": "property", "displayName": "Concurrent Tasks", "group": "scheduler", "label": "scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1, "description": "Number of threads used by the scheduling thread pool. Is by default using a single thread" }
+    "poolSize": { "kind": "property", "displayName": "Pool Size", "group": "scheduler", "label": "scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1, "description": "Number of core threads in the thread pool used by the scheduling thread pool. Is by default using a single thread" }
   },
   "properties": {
     "name": { "kind": "path", "displayName": "Name", "group": "consumer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The name of the scheduler" },
@@ -37,10 +37,10 @@
     "backoffErrorThreshold": { "kind": "parameter", "displayName": "Backoff Error Threshold", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "The number of subsequent error polls (failed due some error) that should happen before the backoffMultipler should kick-in." },
     "backoffIdleThreshold": { "kind": "parameter", "displayName": "Backoff Idle Threshold", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "The number of subsequent idle polls that should happen before the backoffMultipler should kick-in." },
     "backoffMultiplier": { "kind": "parameter", "displayName": "Backoff Multiplier", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "To let the scheduled polling consumer backoff if there has been a number of subsequent idles\/errors in a row. The multiplier is then the number of polls that will be skipped before the next actual attempt is happening agai [...]
-    "concurrentTasks": { "kind": "parameter", "displayName": "Concurrent Tasks", "group": "scheduler", "label": "scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1, "description": "Number of threads used by the scheduling thread pool. Is by default using a single thread" },
     "delay": { "kind": "parameter", "displayName": "Delay", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 500, "description": "Milliseconds before the next poll." },
     "greedy": { "kind": "parameter", "displayName": "Greedy", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If greedy is enabled, then the ScheduledPollConsumer will run immediately again, if the previous run polled 1 or more messages." },
     "initialDelay": { "kind": "parameter", "displayName": "Initial Delay", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1000, "description": "Milliseconds before the first poll starts." },
+    "poolSize": { "kind": "parameter", "displayName": "Pool Size", "group": "scheduler", "label": "scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1, "description": "Number of core threads in the thread pool used by the scheduling thread pool. Is by default using a single thread" },
     "repeatCount": { "kind": "parameter", "displayName": "Repeat Count", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 0, "description": "Specifies a maximum limit of number of fires. So if you set it to 1, the scheduler will only fire once. If you set it to 5, it will only fire five times. A value of zero or negative means fire forever." },
     "runLoggingLevel": { "kind": "parameter", "displayName": "Run Logging Level", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "object", "javaType": "org.apache.camel.LoggingLevel", "enum": [ "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "TRACE", "description": "The consumer logs a start\/complete log line when it polls. This option allows you to configure the logging level  [...]
     "scheduledExecutorService": { "kind": "parameter", "displayName": "Scheduled Executor Service", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "object", "javaType": "java.util.concurrent.ScheduledExecutorService", "deprecated": false, "autowired": false, "secret": false, "description": "Allows for configuring a custom\/shared thread pool to use for the consumer. By default each consumer has its own single threaded thread pool." },
diff --git a/components/camel-scheduler/src/main/docs/scheduler-component.adoc b/components/camel-scheduler/src/main/docs/scheduler-component.adoc
index 96148bd..1a571f0 100644
--- a/components/camel-scheduler/src/main/docs/scheduler-component.adoc
+++ b/components/camel-scheduler/src/main/docs/scheduler-component.adoc
@@ -51,7 +51,7 @@ The Scheduler component supports 3 options, which are listed below.
 | Name | Description | Default | Type
 | *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
 | *autowiredEnabled* (advanced) | Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc. | true | boolean
-| *concurrentTasks* (scheduler) | Number of threads used by the scheduling thread pool. Is by default using a single thread | 1 | int
+| *poolSize* (scheduler) | Number of core threads in the thread pool used by the scheduling thread pool. Is by default using a single thread | 1 | int
 |===
 // component options: END
 
@@ -90,10 +90,10 @@ with the following path and query parameters:
 | *backoffErrorThreshold* (scheduler) | The number of subsequent error polls (failed due some error) that should happen before the backoffMultipler should kick-in. |  | int
 | *backoffIdleThreshold* (scheduler) | The number of subsequent idle polls that should happen before the backoffMultipler should kick-in. |  | int
 | *backoffMultiplier* (scheduler) | To let the scheduled polling consumer backoff if there has been a number of subsequent idles/errors in a row. The multiplier is then the number of polls that will be skipped before the next actual attempt is happening again. When this option is in use then backoffIdleThreshold and/or backoffErrorThreshold must also be configured. |  | int
-| *concurrentTasks* (scheduler) | Number of threads used by the scheduling thread pool. Is by default using a single thread | 1 | int
 | *delay* (scheduler) | Milliseconds before the next poll. | 500 | long
 | *greedy* (scheduler) | If greedy is enabled, then the ScheduledPollConsumer will run immediately again, if the previous run polled 1 or more messages. | false | boolean
 | *initialDelay* (scheduler) | Milliseconds before the first poll starts. | 1000 | long
+| *poolSize* (scheduler) | Number of core threads in the thread pool used by the scheduling thread pool. Is by default using a single thread | 1 | int
 | *repeatCount* (scheduler) | Specifies a maximum limit of number of fires. So if you set it to 1, the scheduler will only fire once. If you set it to 5, it will only fire five times. A value of zero or negative means fire forever. | 0 | long
 | *runLoggingLevel* (scheduler) | The consumer logs a start/complete log line when it polls. This option allows you to configure the logging level for that. There are 6 enums and the value can be one of: TRACE, DEBUG, INFO, WARN, ERROR, OFF | TRACE | LoggingLevel
 | *scheduledExecutorService* (scheduler) | Allows for configuring a custom/shared thread pool to use for the consumer. By default each consumer has its own single threaded thread pool. |  | ScheduledExecutorService
diff --git a/components/camel-scheduler/src/main/java/org/apache/camel/component/scheduler/SchedulerComponent.java b/components/camel-scheduler/src/main/java/org/apache/camel/component/scheduler/SchedulerComponent.java
index 5db0bbe..475044a 100644
--- a/components/camel-scheduler/src/main/java/org/apache/camel/component/scheduler/SchedulerComponent.java
+++ b/components/camel-scheduler/src/main/java/org/apache/camel/component/scheduler/SchedulerComponent.java
@@ -33,7 +33,7 @@ public class SchedulerComponent extends DefaultComponent {
     private final Map<String, AtomicInteger> refCounts = new HashMap<>();
 
     @Metadata(defaultValue = "1", label = "scheduler")
-    private int concurrentTasks = 1;
+    private int poolSize = 1;
 
     public SchedulerComponent() {
     }
@@ -41,34 +41,34 @@ public class SchedulerComponent extends DefaultComponent {
     @Override
     protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
         SchedulerEndpoint answer = new SchedulerEndpoint(uri, this, remaining);
-        answer.setConcurrentTasks(getConcurrentTasks());
+        answer.setPoolSize(getPoolSize());
         setProperties(answer, parameters);
         return answer;
     }
 
-    public int getConcurrentTasks() {
-        return concurrentTasks;
+    public int getPoolSize() {
+        return poolSize;
     }
 
     /**
-     * Number of threads used by the scheduling thread pool.
+     * Number of core threads in the thread pool used by the scheduling thread pool.
      * <p/>
      * Is by default using a single thread
      */
-    public void setConcurrentTasks(int concurrentTasks) {
-        this.concurrentTasks = concurrentTasks;
+    public void setPoolSize(int poolSize) {
+        this.poolSize = poolSize;
     }
 
     protected ScheduledExecutorService addConsumer(SchedulerConsumer consumer) {
         String name = consumer.getEndpoint().getName();
-        int concurrentTasks = consumer.getEndpoint().getConcurrentTasks();
+        int poolSize = consumer.getEndpoint().getPoolSize();
 
         ScheduledExecutorService answer;
         synchronized (executors) {
             answer = executors.get(name);
             if (answer == null) {
                 answer = getCamelContext().getExecutorServiceManager().newScheduledThreadPool(this, "scheduler://" + name,
-                        concurrentTasks);
+                        poolSize);
                 executors.put(name, answer);
                 // store new reference counter
                 refCounts.put(name, new AtomicInteger(1));
diff --git a/components/camel-scheduler/src/main/java/org/apache/camel/component/scheduler/SchedulerEndpoint.java b/components/camel-scheduler/src/main/java/org/apache/camel/component/scheduler/SchedulerEndpoint.java
index d1528eb..b460e5a 100644
--- a/components/camel-scheduler/src/main/java/org/apache/camel/component/scheduler/SchedulerEndpoint.java
+++ b/components/camel-scheduler/src/main/java/org/apache/camel/component/scheduler/SchedulerEndpoint.java
@@ -42,7 +42,7 @@ public class SchedulerEndpoint extends ScheduledPollEndpoint {
     @Metadata(required = true)
     private String name;
     @UriParam(defaultValue = "1", label = "scheduler")
-    private int concurrentTasks = 1;
+    private int poolSize = 1;
     @UriParam(defaultValue = "false", label = "advanced",
               description = "Sets whether synchronous processing should be strictly used")
     private boolean synchronous;
@@ -80,17 +80,17 @@ public class SchedulerEndpoint extends ScheduledPollEndpoint {
         this.name = name;
     }
 
-    public int getConcurrentTasks() {
-        return concurrentTasks;
+    public int getPoolSize() {
+        return poolSize;
     }
 
     /**
-     * Number of threads used by the scheduling thread pool.
+     * Number of core threads in the thread pool used by the scheduling thread pool.
      * <p/>
      * Is by default using a single thread
      */
-    public void setConcurrentTasks(int concurrentTasks) {
-        this.concurrentTasks = concurrentTasks;
+    public void setPoolSize(int poolSize) {
+        this.poolSize = poolSize;
     }
 
     public boolean isSynchronous() {
diff --git a/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SchedulerComponentBuilderFactory.java b/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SchedulerComponentBuilderFactory.java
index e59414b..2f5f7ed 100644
--- a/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SchedulerComponentBuilderFactory.java
+++ b/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SchedulerComponentBuilderFactory.java
@@ -96,19 +96,19 @@ public interface SchedulerComponentBuilderFactory {
             return this;
         }
         /**
-         * Number of threads used by the scheduling thread pool. Is by default
-         * using a single thread.
+         * Number of core threads in the thread pool used by the scheduling
+         * thread pool. Is by default using a single thread.
          * 
          * The option is a: &lt;code&gt;int&lt;/code&gt; type.
          * 
          * Default: 1
          * Group: scheduler
          * 
-         * @param concurrentTasks the value to set
+         * @param poolSize the value to set
          * @return the dsl builder
          */
-        default SchedulerComponentBuilder concurrentTasks(int concurrentTasks) {
-            doSetProperty("concurrentTasks", concurrentTasks);
+        default SchedulerComponentBuilder poolSize(int poolSize) {
+            doSetProperty("poolSize", poolSize);
             return this;
         }
     }
@@ -130,7 +130,7 @@ public interface SchedulerComponentBuilderFactory {
             switch (name) {
             case "bridgeErrorHandler": ((SchedulerComponent) component).setBridgeErrorHandler((boolean) value); return true;
             case "autowiredEnabled": ((SchedulerComponent) component).setAutowiredEnabled((boolean) value); return true;
-            case "concurrentTasks": ((SchedulerComponent) component).setConcurrentTasks((int) value); return true;
+            case "poolSize": ((SchedulerComponent) component).setPoolSize((int) value); return true;
             default: return false;
             }
         }
diff --git a/core/camel-core/src/test/java/org/apache/camel/component/scheduler/SchedulerBlockingTest.java b/core/camel-core/src/test/java/org/apache/camel/component/scheduler/SchedulerBlockingTest.java
new file mode 100644
index 0000000..674e316
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/component/scheduler/SchedulerBlockingTest.java
@@ -0,0 +1,44 @@
+package org.apache.camel.component.scheduler;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+@Disabled("Manual test")
+public class SchedulerBlockingTest extends ContextTestSupport {
+
+    @Test
+    public void testScheduler() throws Exception {
+        Thread.sleep(60000);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                SchedulerComponent comp = getContext().getComponent("scheduler", SchedulerComponent.class);
+                comp.setPoolSize(4);
+
+                from("scheduler://trigger?delay=2000&repeatCount=3").routeId("scheduler")
+                        .threads(10)
+                        .log("1")
+                        .inOut("seda:route1")
+                        .log("1.1");
+
+                from("seda:route1?concurrentConsumers=2").routeId("first route")
+                        .log("2")
+                        .delay(5000)
+                        .log("2.1")
+                        .inOut("seda:route2")
+                        .log("2.2");
+
+                from("seda:route2").routeId("second route")
+                        .log("3")
+                        .delay(3000)
+                        .log("3.1");
+            }
+        };
+    }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/component/scheduler/SchedulerNoPolledMessagesTest.java b/core/camel-core/src/test/java/org/apache/camel/component/scheduler/SchedulerNoPolledMessagesTest.java
index 2833df3..ecc4f07 100644
--- a/core/camel-core/src/test/java/org/apache/camel/component/scheduler/SchedulerNoPolledMessagesTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/component/scheduler/SchedulerNoPolledMessagesTest.java
@@ -42,7 +42,7 @@ public class SchedulerNoPolledMessagesTest extends ContextTestSupport {
     protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {
             public void configure() {
-                from("scheduler://foo?delay=100&backoffMultiplier=10&backoffIdleThreshold=2&scheduler.concurrentTasks=2")
+                from("scheduler://foo?delay=100&backoffMultiplier=10&backoffIdleThreshold=2&poolSize=2")
                         .log("Fired scheduler").process(new Processor() {
                             @Override
                             public void process(Exchange exchange) throws Exception {
diff --git a/core/camel-core/src/test/java/org/apache/camel/component/scheduler/TwoSchedulerConcurrentTasksOneRouteTest.java b/core/camel-core/src/test/java/org/apache/camel/component/scheduler/TwoSchedulerConcurrentTasksOneRouteTest.java
index 305512d..6918876 100644
--- a/core/camel-core/src/test/java/org/apache/camel/component/scheduler/TwoSchedulerConcurrentTasksOneRouteTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/component/scheduler/TwoSchedulerConcurrentTasksOneRouteTest.java
@@ -39,13 +39,11 @@ public class TwoSchedulerConcurrentTasksOneRouteTest extends ContextTestSupport
     protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {
             public void configure() {
-                // number of concurrent task a thread pool should have
+                // number of core threads a thread pool should have
                 SchedulerComponent comp = context.getComponent("scheduler", SchedulerComponent.class);
-                comp.setConcurrentTasks(2);
+                comp.setPoolSize(2);
 
-                // let this route scheduler use all 2 concurrent tasks at the
-                // same time
-                from("scheduler://foo?delay=250&scheduler.concurrentTasks=2").process(new Processor() {
+                from("scheduler://foo?delay=250").process(new Processor() {
                     @Override
                     public void process(Exchange exchange) throws Exception {
                         if (sleep.compareAndSet(true, false)) {
diff --git a/core/camel-core/src/test/java/org/apache/camel/component/scheduler/TwoSchedulerConcurrentTasksTest.java b/core/camel-core/src/test/java/org/apache/camel/component/scheduler/TwoSchedulerConcurrentTasksTest.java
index 2443208..66e3eed 100644
--- a/core/camel-core/src/test/java/org/apache/camel/component/scheduler/TwoSchedulerConcurrentTasksTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/component/scheduler/TwoSchedulerConcurrentTasksTest.java
@@ -35,7 +35,7 @@ public class TwoSchedulerConcurrentTasksTest extends ContextTestSupport {
         return new RouteBuilder() {
             public void configure() {
                 SchedulerComponent comp = context.getComponent("scheduler", SchedulerComponent.class);
-                comp.setConcurrentTasks(2);
+                comp.setPoolSize(2);
 
                 from("scheduler://foo?delay=100").to("log:a").to("mock:a");
 
diff --git a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SchedulerEndpointBuilderFactory.java b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SchedulerEndpointBuilderFactory.java
index 5bf11c9..f3edaf5 100644
--- a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SchedulerEndpointBuilderFactory.java
+++ b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SchedulerEndpointBuilderFactory.java
@@ -229,38 +229,6 @@ public interface SchedulerEndpointBuilderFactory {
             return this;
         }
         /**
-         * Number of threads used by the scheduling thread pool. Is by default
-         * using a single thread.
-         * 
-         * The option is a: &lt;code&gt;int&lt;/code&gt; type.
-         * 
-         * Default: 1
-         * Group: scheduler
-         * 
-         * @param concurrentTasks the value to set
-         * @return the dsl builder
-         */
-        default SchedulerEndpointBuilder concurrentTasks(int concurrentTasks) {
-            doSetProperty("concurrentTasks", concurrentTasks);
-            return this;
-        }
-        /**
-         * Number of threads used by the scheduling thread pool. Is by default
-         * using a single thread.
-         * 
-         * The option will be converted to a &lt;code&gt;int&lt;/code&gt; type.
-         * 
-         * Default: 1
-         * Group: scheduler
-         * 
-         * @param concurrentTasks the value to set
-         * @return the dsl builder
-         */
-        default SchedulerEndpointBuilder concurrentTasks(String concurrentTasks) {
-            doSetProperty("concurrentTasks", concurrentTasks);
-            return this;
-        }
-        /**
          * Milliseconds before the next poll.
          * 
          * The option is a: &lt;code&gt;long&lt;/code&gt; type.
@@ -354,6 +322,38 @@ public interface SchedulerEndpointBuilderFactory {
             return this;
         }
         /**
+         * Number of core threads in the thread pool used by the scheduling
+         * thread pool. Is by default using a single thread.
+         * 
+         * The option is a: &lt;code&gt;int&lt;/code&gt; type.
+         * 
+         * Default: 1
+         * Group: scheduler
+         * 
+         * @param poolSize the value to set
+         * @return the dsl builder
+         */
+        default SchedulerEndpointBuilder poolSize(int poolSize) {
+            doSetProperty("poolSize", poolSize);
+            return this;
+        }
+        /**
+         * Number of core threads in the thread pool used by the scheduling
+         * thread pool. Is by default using a single thread.
+         * 
+         * The option will be converted to a &lt;code&gt;int&lt;/code&gt; type.
+         * 
+         * Default: 1
+         * Group: scheduler
+         * 
+         * @param poolSize the value to set
+         * @return the dsl builder
+         */
+        default SchedulerEndpointBuilder poolSize(String poolSize) {
+            doSetProperty("poolSize", poolSize);
+            return this;
+        }
+        /**
          * Specifies a maximum limit of number of fires. So if you set it to 1,
          * the scheduler will only fire once. If you set it to 5, it will only
          * fire five times. A value of zero or negative means fire forever.
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/DefaultScheduledPollConsumerScheduler.java b/core/camel-support/src/main/java/org/apache/camel/support/DefaultScheduledPollConsumerScheduler.java
index 3a7e253..af6aa81 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/DefaultScheduledPollConsumerScheduler.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/DefaultScheduledPollConsumerScheduler.java
@@ -47,7 +47,7 @@ public class DefaultScheduledPollConsumerScheduler extends ServiceSupport implem
     private boolean shutdownExecutor;
     private volatile List<ScheduledFuture<?>> futures = new ArrayList<>();
     private Runnable task;
-    private int concurrentTasks = 1;
+    private int poolSize = 1;
 
     private long initialDelay = -1;
     private long delay = -1;
@@ -111,12 +111,12 @@ public class DefaultScheduledPollConsumerScheduler extends ServiceSupport implem
         this.scheduledExecutorService = scheduledExecutorService;
     }
 
-    public int getConcurrentTasks() {
-        return concurrentTasks;
+    public int getPoolSize() {
+        return poolSize;
     }
 
-    public void setConcurrentTasks(int concurrentTasks) {
-        this.concurrentTasks = concurrentTasks;
+    public void setPoolSize(int poolSize) {
+        this.poolSize = poolSize;
     }
 
     @Override
@@ -170,20 +170,16 @@ public class DefaultScheduledPollConsumerScheduler extends ServiceSupport implem
                             currentInitialDelay, currentDelay, getTimeUnit().name().toLowerCase(Locale.ENGLISH),
                             consumer.getEndpoint());
                 }
-                for (int i = 0; i < concurrentTasks; i++) {
-                    futures.add(scheduledExecutorService.scheduleWithFixedDelay(task, currentInitialDelay, currentDelay,
-                            getTimeUnit()));
-                }
+                futures.add(scheduledExecutorService.scheduleWithFixedDelay(task, currentInitialDelay, currentDelay,
+                        getTimeUnit()));
             } else {
                 if (LOG.isDebugEnabled()) {
                     LOG.debug("Scheduling poll (fixed rate) with initialDelay: {}, delay: {} ({}) for: {}",
                             currentInitialDelay, currentDelay, getTimeUnit().name().toLowerCase(Locale.ENGLISH),
                             consumer.getEndpoint());
                 }
-                for (int i = 0; i < concurrentTasks; i++) {
-                    futures.add(scheduledExecutorService.scheduleAtFixedRate(task, currentInitialDelay, currentDelay,
-                            getTimeUnit()));
-                }
+                futures.add(scheduledExecutorService.scheduleAtFixedRate(task, currentInitialDelay, currentDelay,
+                        getTimeUnit()));
             }
         }
     }
@@ -203,7 +199,7 @@ public class DefaultScheduledPollConsumerScheduler extends ServiceSupport implem
         if (scheduledExecutorService == null) {
             // we only need one thread in the pool to schedule this task
             this.scheduledExecutorService = getCamelContext().getExecutorServiceManager()
-                    .newScheduledThreadPool(consumer, consumer.getEndpoint().getEndpointUri(), concurrentTasks);
+                    .newScheduledThreadPool(consumer, consumer.getEndpoint().getEndpointUri(), poolSize);
             // and we should shutdown the thread pool when no longer needed
             this.shutdownExecutor = true;
         }
diff --git a/docs/components/modules/ROOT/pages/scheduler-component.adoc b/docs/components/modules/ROOT/pages/scheduler-component.adoc
index abab3ed..8f13478 100644
--- a/docs/components/modules/ROOT/pages/scheduler-component.adoc
+++ b/docs/components/modules/ROOT/pages/scheduler-component.adoc
@@ -53,7 +53,7 @@ The Scheduler component supports 3 options, which are listed below.
 | Name | Description | Default | Type
 | *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
 | *autowiredEnabled* (advanced) | Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc. | true | boolean
-| *concurrentTasks* (scheduler) | Number of threads used by the scheduling thread pool. Is by default using a single thread | 1 | int
+| *poolSize* (scheduler) | Number of core threads in the thread pool used by the scheduling thread pool. Is by default using a single thread | 1 | int
 |===
 // component options: END
 
@@ -92,10 +92,10 @@ with the following path and query parameters:
 | *backoffErrorThreshold* (scheduler) | The number of subsequent error polls (failed due some error) that should happen before the backoffMultipler should kick-in. |  | int
 | *backoffIdleThreshold* (scheduler) | The number of subsequent idle polls that should happen before the backoffMultipler should kick-in. |  | int
 | *backoffMultiplier* (scheduler) | To let the scheduled polling consumer backoff if there has been a number of subsequent idles/errors in a row. The multiplier is then the number of polls that will be skipped before the next actual attempt is happening again. When this option is in use then backoffIdleThreshold and/or backoffErrorThreshold must also be configured. |  | int
-| *concurrentTasks* (scheduler) | Number of threads used by the scheduling thread pool. Is by default using a single thread | 1 | int
 | *delay* (scheduler) | Milliseconds before the next poll. | 500 | long
 | *greedy* (scheduler) | If greedy is enabled, then the ScheduledPollConsumer will run immediately again, if the previous run polled 1 or more messages. | false | boolean
 | *initialDelay* (scheduler) | Milliseconds before the first poll starts. | 1000 | long
+| *poolSize* (scheduler) | Number of core threads in the thread pool used by the scheduling thread pool. Is by default using a single thread | 1 | int
 | *repeatCount* (scheduler) | Specifies a maximum limit of number of fires. So if you set it to 1, the scheduler will only fire once. If you set it to 5, it will only fire five times. A value of zero or negative means fire forever. | 0 | long
 | *runLoggingLevel* (scheduler) | The consumer logs a start/complete log line when it polls. This option allows you to configure the logging level for that. There are 6 enums and the value can be one of: TRACE, DEBUG, INFO, WARN, ERROR, OFF | TRACE | LoggingLevel
 | *scheduledExecutorService* (scheduler) | Allows for configuring a custom/shared thread pool to use for the consumer. By default each consumer has its own single threaded thread pool. |  | ScheduledExecutorService
diff --git a/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide-3_10.adoc b/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide-3_10.adoc
new file mode 100644
index 0000000..3dedb00
--- /dev/null
+++ b/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide-3_10.adoc
@@ -0,0 +1,19 @@
+= Apache Camel 3.x Upgrade Guide
+
+This document is for helping you upgrade your Apache Camel application
+from Camel 3.x to 3.y. For example if you are upgrading Camel 3.0 to 3.2, then you should follow the guides
+from both 3.0 to 3.1 and 3.1 to 3.2.
+
+== Upgrading Camel 3.9 to 3.10
+
+=== camel-scheduler
+
+The option `concurrentTasks` has been renamed to `poolSize` to better reflect its purpose.
+The scheduler has also been fixed to only schedule triggering by one, and not as mistakenly by causing
+concurrent triggering which causes routing mistakes.
+
+The option configures the pool size of the scheduled thread pool used by the scheduler.
+
+If the scheduler thread is being blocked by anywhere in the downstream routing, and you want the scheduler
+to schedule with a fixed interval, you can use the Threads EIP as queue for pending tasks.
+
diff --git a/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide.adoc b/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide.adoc
index 2b46f95..1639c9d 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide.adoc
@@ -18,3 +18,4 @@ You can find upgrade guide for each release in the following pages:
 - xref:camel-3x-upgrade-guide-3_7.adoc[Upgrade guide from 3.6 to 3.7]
 - xref:camel-3x-upgrade-guide-3_8.adoc[Upgrade guide from 3.7 to 3.8]
 - xref:camel-3x-upgrade-guide-3_9.adoc[Upgrade guide from 3.8 to 3.9]
+- xref:camel-3x-upgrade-guide-3_10.adoc[Upgrade guide from 3.9 to 3.10]