You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@camel.apache.org by "Federico Mariani (Jira)" <ji...@apache.org> on 2026/09/11 08:44:00 UTC

[jira] [Commented] (CAMEL-24682) camel-groovy - Resolve the language and GroovyShellFactory once, keep the compiled script per expression, build the binding lazily

    [ https://issues.apache.org/jira/browse/CAMEL-24682?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18114154#comment-18114154 ] 

Federico Mariani commented on CAMEL-24682:
------------------------------------------

Draft PR: https://github.com/apache/camel/pull/26303

_Claude Code on behalf of Croway_

> camel-groovy - Resolve the language and GroovyShellFactory once, keep the compiled script per expression, build the binding lazily
> ----------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-24682
>                 URL: https://issues.apache.org/jira/browse/CAMEL-24682
>             Project: Camel
>          Issue Type: Improvement
>          Components: camel-groovy
>    Affects Versions: 4.22.0
>            Reporter: Federico Mariani
>            Assignee: Federico Mariani
>            Priority: Major
>             Fix For: 4.23.0
>
>
> Every evaluation of a groovy expression does work that only needs doing once:
> * {{GroovyExpression.instantiateScript}} calls {{resolveLanguage("groovy")}} and {{registry.findByType(GroovyShellFactory.class)}} on every exchange (GroovyExpression.java:70-71). {{findByType}} scans every bean in the registry, so with 500 unrelated beans one evaluation is 11.8x slower (3.36 M -> 0.28 M ops/s).
> * The binding is rebuilt on every evaluation: a globals map, a copy of it, {{ExchangeHelper.populateVariableMap}} (which copies all exchange properties through {{getAllProperties()}}), a {{DefaultAttachmentMessage}} and a {{Binding}}. That is ~154 ns and 1,152 B of a ~297 ns evaluation and 78% of the bytes it allocates.
> * The compiled script class goes through the shared 1,000-entry language cache on every evaluation; a script evicted from it is recompiled (0.70 ms and 480 KB per evaluation past 1,000 distinct scripts; a 5-minute load with 1,500 distinct scripts ran at 5,019 msg/s with 600,000 classes loaded).
> * The {{Script}} instance is created through {{ObjectHelper.newInstance}}, which copies the {{Constructor}} on every call.
> Measured on main (JDK 21): {{body + '-' + header.foo}} at 3.0 M ops/s against 47.8 M for a Java expression; the route {{filter(amount > 100) -> setBody(concat)}} at 0.48x the Java route on one thread and 0.22x on eight; a 5-minute 8-thread load at 1.08 M msg/s (0.26x Java) with a p99 of 102 us.
> Proposed fix (implemented and benchmarked): resolve the language and the shell factory once per CamelContext; keep the compiled class in the {{Expression}} (checked against context, language and a generation counter bumped on language stop and dev-mode reload, so the shared cache no longer removes classes on eviction); a lazy {{ExchangeBinding}} that snapshots {{in}}, {{body}}, {{headers}}, {{exception}}, {{out}} and materializes {{exchangeProperties}}, {{variables}} and {{attachments}} on first access; a cached constructor {{MethodHandle}}.
> With the fix: expressions 4.9-7.7x faster, route 0.94x the Java route on 1 and 8 threads, load 3.80 M msg/s (0.91x Java) with a p99 of 3 us and the same 26 MB heap after GC, 1,500 distinct scripts 2.92 M msg/s.
> Behaviour changes that need an upgrade guide entry: a {{GroovyShellFactory}} bound to the registry after the first evaluation is no longer picked up; {{exchangeProperties}}, {{variables}} and {{attachments}} are read on first access rather than when the binding is created. Protected {{createBinding}} / {{instantiateScript}} signatures are kept.
> Related: CAMEL-8259 (origin of the per-evaluation factory lookup), CAMEL-21212, CAMEL-21717, CAMEL-21755 (binding variables).
> ----
> _Found during a benchmark review of camel-groovy and the other scripting languages (camel-performance-tests branch camel-groovy-perf, tests/camel-jmh/groovy-results, JMH 1.37, JDK 21, one M1 Pro laptop). A candidate fix with tests exists on the local apache/camel branch camel-perf-all-fixes; a PR follows._
> _Claude Code on behalf of Croway_



--
This message was sent by Atlassian Jira
(v8.20.10#820010)