[
https://issues.apache.org/jira/browse/CAMEL-25911?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
shashank updated CAMEL-25911:
-----------------------------
Description:
Stage 2 of CAMEL-25738, as discussed on dev@ ("[DISCUSS] An internal time
source in camel-util (for deterministic simulation tests)", +1 from Claus).
camel-test-dst runs the real consumer code of a component under one seeded
scheduler with virtual time. It controls Camel's thread pools through the
existing {{ThreadPoolFactory}} SPI, but core reads the clock and sleeps through
{{System}} and {{Thread.sleep}} directly, so today a world either has the core
classes rewritten at load time or lives with real time and real sleeps in core
(redelivery delays, shutdown waits, task back-offs, throttlers).
*Proposal*
* A small static, internal {{TimeSource}} in camel-util with
{{currentTimeMillis()}}, {{nanoTime()}}, {{instant()}} and {{sleep(long)}}. The
default provider delegates to {{System}} and {{Thread.sleep}}; a test harness
can install another provider ({{install(Provider)}}, a volatile field). Static
rather than per CamelContext, because {{StopWatch}} and {{MonotonicClock}} have
no context.
* Move only the about 30 core call sites that change behaviour:
** waits: {{RedeliveryPolicy.sleep}} and the sleep loop of
{{RedeliveryErrorHandler}}, {{ForegroundTask}}, the wait loop of
{{DefaultShutdownStrategy}}, {{DelayProcessorSupport}}, {{MulticastProcessor}},
{{OptimisticLockRetryPolicy}}, {{DefaultStartupConditionStrategy}};
** task timing: {{StopWatch}}, {{MonotonicClock}}, {{AbstractTask}},
{{BackgroundTask}}, {{TimeBoundedBudget}}, {{BackOffTimerTask}},
{{DefaultTimeoutMap}};
** throttling: {{TotalRequestsThrottler}}, {{ConcurrentRequestsThrottler}},
{{SamplingThrottler}}, {{ThrottlingExceptionRoutePolicy}}.
* Event timestamps and the direct clock reads of the debugger, the tracer,
management and the consoles stay on {{System}}. The durations they measure with
{{StopWatch}} or {{MonotonicClock}} follow {{TimeSource}} (with the default
provider this is the same {{System.nanoTime()}}; the JMH {{StopWatch}} figure
below is that cost).
* camel-test-dst installs its virtual clock as the provider, so the load-time
rewriting is only needed for the component under test, and for the core waits
that are not clock reads (the permit queue of {{TotalRequestsThrottler}}).
Loading the agent with {{-javaagent}} instead of a runtime attach is a
follow-up issue.
* Later: components use {{TimeSource}} when they are touched anyway; a
forbidden-apis rule can keep new {{Thread.sleep}} / {{Instant.now()}} out of
consumers.
*Cost*: a JMH benchmark posted to the dev@ thread (JDK 21, AArch64, 3 forks)
measured about 0.2 ns more per {{nanoTime()}} call and about 0.5 ns per
{{StopWatch}} on one thread, nothing measurable for {{currentTimeMillis()}} and
nothing measurable with 8 threads; a volatile field was not measurably slower
than a plain one. For scale, the simplest direct -> log route takes about 410
ns per message.
*Plan*: one pull request with {{TimeSource}} and its tests, the call sites
above, and camel-test-dst using it; no behaviour change with the default
provider. An existing world (for example camel-aws2-sqs) shows the core waits
running in virtual time.
_Filed with Claude Code on behalf of allthingssecurity._
was:
Stage 2 of CAMEL-25738, as discussed on dev@ ("[DISCUSS] An internal time
source in camel-util (for deterministic simulation tests)", +1 from Claus).
camel-test-dst runs the real consumer code of a component under one seeded
scheduler with virtual time. It controls Camel's thread pools through the
existing {{ThreadPoolFactory}} SPI, but core reads the clock and sleeps through
{{System}} and {{Thread.sleep}} directly, so today a world either has the core
classes rewritten at load time or lives with real time and real sleeps in core
(redelivery delays, shutdown waits, task back-offs, throttlers).
*Proposal*
* A small static, internal {{TimeSource}} in camel-util with
{{currentTimeMillis()}}, {{nanoTime()}}, {{instant()}} and {{sleep(long)}}. The
default provider delegates to {{System}} and {{Thread.sleep}}; a test harness
can install another provider ({{install(Provider)}}, a volatile field). Static
rather than per CamelContext, because {{StopWatch}} and {{MonotonicClock}} have
no context.
* Move only the about 30 core call sites that change behaviour:
** waits: {{RedeliveryPolicy.sleep}} and the sleep loop of
{{RedeliveryErrorHandler}}, {{ForegroundTask}}, the wait loop of
{{DefaultShutdownStrategy}}, {{DelayProcessorSupport}}, {{MulticastProcessor}},
{{OptimisticLockRetryPolicy}}, {{DefaultStartupConditionStrategy}};
** task timing: {{StopWatch}}, {{MonotonicClock}}, {{AbstractTask}},
{{BackgroundTask}}, {{TimeBoundedBudget}}, {{BackOffTimerTask}},
{{DefaultTimeoutMap}};
** throttling: {{TotalRequestsThrottler}}, {{ConcurrentRequestsThrottler}},
{{SamplingThrottler}}, {{ThrottlingExceptionRoutePolicy}}.
* Event timestamps, the debugger, the tracer, management and the consoles stay
on {{System}}.
* camel-test-dst installs its virtual clock as the provider, so the load-time
rewriting is only needed for the component under test (and is loaded with
{{-javaagent}} instead of a runtime attach).
* Later: components use {{TimeSource}} when they are touched anyway; a
forbidden-apis rule can keep new {{Thread.sleep}} / {{Instant.now()}} out of
consumers.
*Cost*: a JMH benchmark posted to the dev@ thread (JDK 21, AArch64, 3 forks)
measured about 0.2 ns more per {{nanoTime()}} call and about 0.5 ns per
{{StopWatch}} on one thread, nothing measurable for {{currentTimeMillis()}} and
nothing measurable with 8 threads; a volatile field was not measurably slower
than a plain one. For scale, the simplest direct -> log route takes about 410
ns per message.
*Plan*: one pull request with {{TimeSource}} and its tests, the call sites
above, and camel-test-dst using it; no behaviour change with the default
provider. An existing world (for example camel-aws2-sqs) shows the core waits
running in virtual time.
_Filed with Claude Code on behalf of allthingssecurity._
> camel-test-dst - stage 2: an internal TimeSource in camel-util for the core
> code that waits, times tasks or throttles
> ---------------------------------------------------------------------------------------------------------------------
>
> Key: CAMEL-25911
> URL: https://issues.apache.org/jira/browse/CAMEL-25911
> Project: Camel
> Issue Type: Improvement
> Components: camel-core, camel-test
> Reporter: shashank
> Assignee: shashank
> Priority: Major
>
> Stage 2 of CAMEL-25738, as discussed on dev@ ("[DISCUSS] An internal time
> source in camel-util (for deterministic simulation tests)", +1 from Claus).
> camel-test-dst runs the real consumer code of a component under one seeded
> scheduler with virtual time. It controls Camel's thread pools through the
> existing {{ThreadPoolFactory}} SPI, but core reads the clock and sleeps
> through {{System}} and {{Thread.sleep}} directly, so today a world either has
> the core classes rewritten at load time or lives with real time and real
> sleeps in core (redelivery delays, shutdown waits, task back-offs,
> throttlers).
> *Proposal*
> * A small static, internal {{TimeSource}} in camel-util with
> {{currentTimeMillis()}}, {{nanoTime()}}, {{instant()}} and {{sleep(long)}}.
> The default provider delegates to {{System}} and {{Thread.sleep}}; a test
> harness can install another provider ({{install(Provider)}}, a volatile
> field). Static rather than per CamelContext, because {{StopWatch}} and
> {{MonotonicClock}} have no context.
> * Move only the about 30 core call sites that change behaviour:
> ** waits: {{RedeliveryPolicy.sleep}} and the sleep loop of
> {{RedeliveryErrorHandler}}, {{ForegroundTask}}, the wait loop of
> {{DefaultShutdownStrategy}}, {{DelayProcessorSupport}},
> {{MulticastProcessor}}, {{OptimisticLockRetryPolicy}},
> {{DefaultStartupConditionStrategy}};
> ** task timing: {{StopWatch}}, {{MonotonicClock}}, {{AbstractTask}},
> {{BackgroundTask}}, {{TimeBoundedBudget}}, {{BackOffTimerTask}},
> {{DefaultTimeoutMap}};
> ** throttling: {{TotalRequestsThrottler}}, {{ConcurrentRequestsThrottler}},
> {{SamplingThrottler}}, {{ThrottlingExceptionRoutePolicy}}.
> * Event timestamps and the direct clock reads of the debugger, the tracer,
> management and the consoles stay on {{System}}. The durations they measure
> with {{StopWatch}} or {{MonotonicClock}} follow {{TimeSource}} (with the
> default provider this is the same {{System.nanoTime()}}; the JMH
> {{StopWatch}} figure below is that cost).
> * camel-test-dst installs its virtual clock as the provider, so the load-time
> rewriting is only needed for the component under test, and for the core waits
> that are not clock reads (the permit queue of {{TotalRequestsThrottler}}).
> Loading the agent with {{-javaagent}} instead of a runtime attach is a
> follow-up issue.
> * Later: components use {{TimeSource}} when they are touched anyway; a
> forbidden-apis rule can keep new {{Thread.sleep}} / {{Instant.now()}} out of
> consumers.
> *Cost*: a JMH benchmark posted to the dev@ thread (JDK 21, AArch64, 3 forks)
> measured about 0.2 ns more per {{nanoTime()}} call and about 0.5 ns per
> {{StopWatch}} on one thread, nothing measurable for {{currentTimeMillis()}}
> and nothing measurable with 8 threads; a volatile field was not measurably
> slower than a plain one. For scale, the simplest direct -> log route takes
> about 410 ns per message.
> *Plan*: one pull request with {{TimeSource}} and its tests, the call sites
> above, and camel-test-dst using it; no behaviour change with the default
> provider. An existing world (for example camel-aws2-sqs) shows the core waits
> running in virtual time.
> _Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)