shashank created CAMEL-25606:
--------------------------------
Summary: camel-wasm - Optional runtime compiler for the wasm
endpoint (compile=true, module loaded and compiled once per endpoint)
Key: CAMEL-25606
URL: https://issues.apache.org/jira/browse/CAMEL-25606
Project: Camel
Issue Type: Improvement
Reporter: shashank
Assignee: shashank
Since CAMEL-25531 the {{wasm}} endpoint runs WASI Preview 1 command modules,
one new instance per exchange, with the Endive interpreter. The interpreter is
slow for modules that compute a lot per message or have a large runtime
(standard Go programs). Endive has a runtime compiler that translates a module
to JVM bytecode. This ticket makes it available as an endpoint option.
h3. The option
* {{compile}} (boolean, endpoint option, default {{false}}). With
{{compile=true}} the module is translated to JVM bytecode with
{{run.endive.compiler.MachineFactoryCompiler}} instead of being interpreted.
* Default off, because compiling costs start-up time and generates classes at
run time, which a GraalVM native image cannot load.
* Everything else is the same with the compiler on: result headers, exit codes,
traps, {{maxMemoryPages}}, {{maxOutputSize}}, environment and arguments,
{{SecureRandom}} for {{random_get}}, {{timeout}} (compiled code checks the
thread interrupt like the interpreter), the body read on the calling thread
when a timeout is set, streams opened by the type converter closed, the body
after a failed run. The option gives a module no new capability.
* New dependency of camel-wasm: {{run.endive:compiler}} (Apache-2.0, 163 KB),
which brings ASM in the version Camel already manages.
* New public API: {{WasmConfiguration.isCompile/setCompile}},
{{WasiCommand(WasmModule, List<String>, int, boolean)}},
{{WasiCommand.isCompiled()}}. The three-argument constructor is kept.
h3. When the module is loaded and compiled
* Once per endpoint, when the first producer of the endpoint is initialized:
when the route is first started, or at the first message with
{{lazyStartProducer=true}} or {{toD}}. {{WasmEndpoint}} keeps one immutable
{{WasiCommand}} for as long as it exists, and all its producers share it.
Exchanges still run on separate instances; they share only the generated
classes.
* With CAMEL-25531 every producer parsed the module itself, and a route start
creates a new producer, so a compiler in the producer would compile the same
module at every route start. With this change a route stop and start neither
reads nor compiles the module again. A changed module file is read by a new
endpoint only (route removed and added again, application restarted).
* The generated classes can be unloaded when the endpoint is no longer
reachable, not when a route stops. A route reload in development mode removes
all routes and endpoints by default, so it reads and compiles the module again.
* With a dynamic endpoint ({{toD}}) every different URI is an endpoint with its
own compiled copy of the module, so many different compiled URIs make metaspace
grow. The component page says so.
* A failed load is not kept: the next producer that is initialized tries again.
h3. Failure modes
* A function that is too large for a JVM method is left to the interpreter and
the rest of the module is compiled. Endive reports that on {{System.err}} by
default ({{InterpreterFallback.WARN}}). The component compiles with {{FAIL}}
first and, when that fails, again with {{SILENT}}, and logs once per endpoint
at WARN with the name of the module; nothing is written to {{System.err}}.
* A module the compiler cannot translate fails when the first producer is
initialized, with an {{IllegalStateException}} that names the module by its
file name and has the Endive exception as cause.
* {{WasiCommand}} refers to the compiler through one nested class, so it still
loads and interprets when {{run.endive:compiler}} is excluded from the
classpath; {{compile=true}} then fails with an {{IllegalStateException}} that
names the artifact.
h3. Docs
* Component page, section Performance: the option, when the module is compiled,
when to keep the default. No numbers.
* Upgrade guide 4.24: one paragraph in the existing camel-wasm section (the
option, the new dependency, the module loaded once per endpoint).
h3. Tests
* camel-wasm: 132 tests, 0 failures. {{WasmCompiledComponentTest}} extends
{{WasmComponentTest}} and runs all its 58 tests with {{compile=true}}; no test
behaves differently with the compiler on.
* New tests: the second producer of an endpoint gets the same command without
reading the module again; a route stop and start keeps the command; a load that
failed is tried again by the next producer; a trap shows generated classes with
{{compile=true}} and interpreter frames without; a function that is too large
is interpreted, the module runs and nothing is printed to {{System.err}}; a
module that cannot be compiled fails with its name; {{compile=true}} without
the compiler on the classpath fails with the name of the artifact.
h3. Not run
* A GraalVM native image (neither that {{compile=true}} fails there nor that
the interpreter works there).
* The full build from the root.
* A route reload in development mode with a compiled module, and a metaspace
measurement with {{toD}}.
* Performance on the final change: earlier measurements through a route (one
machine, an earlier state of the CAMEL-25531 work) showed compiled modules 5 to
150 times faster per exchange and a first start of up to about a second for a
2.3 MB Go program; they are indicative only and are in the pull request.
h3. Open questions for the pull request
* {{run.endive:compiler}} as a normal dependency (proposed, about 0.55 MB with
ASM) or an optional one (which needs {{--dep}} with {{camel run}}).
* A hook for modules compiled at build time with the Endive Maven plugin (the
native-image friendly way); not part of this ticket.
* The handling of functions that are too large: fallback to the interpreter
with a WARN (proposed), silent fallback, or failure.
* The module is now loaded by the endpoint and kept as long as the endpoint
exists.
_Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v8.20.10#820010)