Federico Mariani created CAMEL-26397:
----------------------------------------

             Summary: camel-jbang-mcp - on Linux camel_control restart always 
fails and dev mode goes undetected, because the JDK hides a command line longer 
than 4 KB
                 Key: CAMEL-26397
                 URL: https://issues.apache.org/jira/browse/CAMEL-26397
             Project: Camel
          Issue Type: Bug
          Components: camel-jbang, camel-jbang-mcp
    Affects Versions: 4.23.0
            Reporter: Federico Mariani
            Assignee: Federico Mariani


Found on main (4.24.0-SNAPSHOT, commit ffef175654d1); the line numbers below 
are from that commit. The same code is in the 4.23.0 release.

h3. Reproduction

On Linux, start an integration with the Camel CLI, then restart it through the 
MCP server:

{code}
camel_run {"directory":"/tmp/probe","dev":false,"name":"probe"}
-> {"status":"started","pid":2406,...}
camel_control {"action":"restart","name":"probe"}
-> Cannot restart pid 2406: its command line is not available; stop it and run 
it again
{code}

The JDK cause, reproduced in a plain container (Eclipse Temurin 21, Linux 
aarch64):
{noformat}
java -cp <3000 chars> Sl   -> info.arguments() = [3 args], commandLine length 
3049
java -cp <4000 chars> Sl   -> info.arguments() = [3 args], commandLine length 
4049
java -cp <4100 chars> Sl   -> info.arguments() = Optional.empty, commandLine 
cut at 4096
camel run t.yaml (jbang)   -> /proc/<pid>/cmdline is 15,592 bytes: arguments() 
= Optional.empty
{noformat}
On Linux, {{ProcessHandle.Info}} reads only the first page (4096 bytes) of 
{{/proc/<pid>/cmdline}}. When the command line is longer, {{arguments()}} is 
empty and {{commandLine()}} is cut short. A {{camel run}} started through jbang 
always has a longer command line, because its {{-classpath}} alone is about 15 
KB. macOS has no such limit, which is why this does not show up on a developer 
laptop.

Eval evidence (200 trials on 4.24.0-SNAPSHOT in Linux containers): *12 of 12* 
{{camel_control restart}} calls failed (GLM 5.3: 9, DeepSeek V4.1 Flash: 2, 
Claude Haiku 4.5: 1), in 9 trials, and no restart ever worked. After the error, 
the agent did {{stop}} + {{camel_run}} in 7 cases (2 extra calls each). In 5 
cases it left the MCP tools and killed and restarted the app from its shell 
with {{kill}}/{{pkill}} + {{camel run}}.

The same lookup also turns off the reload report of the write tools, without 
any error. In one trial (GLM 5.3) {{camel_run}} started the app in dev mode 
from {{/workspace}} ({{"devMode":true}}, pid 807). Then two {{camel_edit_file}} 
calls on its route file answered only the generic "An integration running the 
file in dev mode reloads it now; otherwise restart ...", with no {{reload}} 
result, although the app did reload (its log shows the reload). The agent added 
{{sleep 5}} + {{camel_get_log}} to find out.

h3. Cause

{{IntegrationLauncher}} reads the integration's command line with 
{{ProcessHandle.Info.arguments()}}:
* {{restart}}: 
{{camel-jbang-core/.../commands/ai/IntegrationLauncher.java:620-635}}. The 
arguments are empty, so it throws "command line is not available".
* {{devModeFrom}} ({{:486-494}}). The arguments are null, so no dev-mode 
integration is found and {{camel_write_file}}/{{camel_edit_file}} skip the 
reload wait ({{commands/ai/AuthoringTools.java:1726-1733}}).
* {{watchesFile}} ({{:466-468}}). It falls back to "watches every file".
* {{runningMessage}} ({{:441-446}}). It falls back to the generic message.

{{camel restart}} ({{commands/process/RestartProcess.java:74-92}}) falls back 
to {{Info.commandLine()}}, which on Linux is cut at 4096 characters. So it 
would relaunch with a broken classpath.

h3. Fix

* One helper that returns the full argument list of a pid: on Linux, read 
{{/proc/<pid>/cmdline}} (NUL-separated, no length limit; the same user can read 
it), else {{ProcessHandle.Info.command()}} + {{arguments()}}. Use it in the 
four {{IntegrationLauncher}} methods and in {{RestartProcess}}. Do not parse 
{{commandLine()}} when it is exactly 4096 characters long, because then it was 
cut.
* Optionally, {{camel_run}} keeps the command it launched (next to the 
{{ProcessHandle}} it already keeps per directory in 
{{IntegrationLauncher.LAUNCHED}}, {{:78}}), and {{restart}} uses it first for 
the processes it started.
* Test: an integration whose command line is longer than 4 KB (a long 
{{-classpath}}), on Linux: restart works, and {{devModeFrom}} finds it.




--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to