This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch fix/CAMEL-24997 in repository https://gitbox.apache.org/repos/asf/camel.git
commit aaa23985b678cf1e89e5ea84c45c9ee606222c55 Author: Claus Ibsen <[email protected]> AuthorDate: Thu Sep 24 14:16:33 2026 +0200 CAMEL-24997: camel-core - Reactive executor: after a nested scheduleSync, scheduled tasks run inline instead of after the current task scheduleSync runs its task right away, also when the worker of the current thread is already running. When done it set the worker to not running, although the outer run was still in progress, so schedule() then ran tasks inline instead of queuing them after the current task. The worker now restores the running state it had before. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> Signed-off-by: Claus Ibsen <[email protected]> --- .../camel/impl/engine/DefaultReactiveExecutor.java | 5 +- .../DefaultReactiveExecutorNestedSyncTest.java | 53 ++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultReactiveExecutor.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultReactiveExecutor.java index 939c553c7991..97376baf319d 100644 --- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultReactiveExecutor.java +++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultReactiveExecutor.java @@ -163,12 +163,15 @@ public class DefaultReactiveExecutor extends ServiceSupport implements ReactiveE private void tryExecuteReactiveWork(Runnable runnable, boolean sync) { if (!running || sync) { + // a sync task can run while this worker is already running (nested), so restore the running state + // afterwards, as otherwise the outer run would no longer be regarded as running + final boolean wasRunning = running; running = true; incrementRunningWorkers(); try { executeReactiveWork(); } finally { - running = false; + running = wasRunning; decrementRunningWorkers(); } } else { diff --git a/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultReactiveExecutorNestedSyncTest.java b/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultReactiveExecutorNestedSyncTest.java new file mode 100644 index 000000000000..50e7ff1e2dfa --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultReactiveExecutorNestedSyncTest.java @@ -0,0 +1,53 @@ +/* + * 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.impl.engine; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.camel.ContextTestSupport; +import org.apache.camel.spi.ReactiveExecutor; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * After a nested scheduleSync, a task scheduled by the running task still runs after the running task (the worker is + * still running), and not inline. + */ +public class DefaultReactiveExecutorNestedSyncTest extends ContextTestSupport { + + @Test + public void testScheduleAfterNestedScheduleSync() { + ReactiveExecutor executor = context.getCamelContextExtension().getReactiveExecutor(); + List<String> order = new ArrayList<>(); + + executor.scheduleMain(() -> { + order.add("task-start"); + executor.scheduleSync(() -> order.add("sync")); + executor.schedule(() -> order.add("scheduled")); + order.add("task-end"); + }); + + assertEquals(List.of("task-start", "sync", "task-end", "scheduled"), order); + } + + @Override + public boolean isUseRouteBuilder() { + return false; + } +}
