Repository navigation
refactor(rocm): break the import cycles between the service launch, control and text modules - #933
Closed
jussielo-amd wants to merge 3 commits into
Closed
jussielo-amd wants to merge 3 commits into
jussielo-amd wants to merge 3 commits into
Conversation
….rs into background_helper.rs services_text.rs imported background_helper_note from service_launch.rs while service_launch.rs imports the stop-result renderers from services_text.rs, so the two modules depended on each other. The note (HelperNote, helper_note_for, background_helper_note) and the liveness check it reads (background_helper_already_running) move verbatim into a new leaf module that imports nothing from the service modules. services_text.rs and uninstall_plan.rs read the note from there, and service_launch.rs reads background_helper_already_running from there for its autostart decision; spawning the helper stays in service_launch.rs. Pure move: no behaviour change. The tests that cover the moved items move with them and keep their names; the runtime_state and set_helper_facts fixtures become pub(crate) because the autostart and stop-output tests that stay in service_launch.rs use them too. docs/architecture.md gains the new module's entry and drops the claim that services_text.rs still reaches into service_launch.rs. Signed-off-by: Jussi Elo <jussi.elo@amd.com>
…importing service_control service_launch.rs imported run_internal_sandbox_tool from service_control.rs only to stop the server when the user presses Ctrl-C in an attached serve, while service_control.rs imports the spawn helpers and the endpoint-key guard from service_launch.rs, so the two modules depended on each other. run_internal_sandbox_tool cannot move down, because it calls the stop and restart paths that live in service_control.rs, so the dependency is cut at its single call site instead: run_attached_service takes the stop as a parameter and serve_cmd.rs, which already sits above both modules, passes the same run_internal_sandbox_tool(StopServer, service id, native fallback allowed) call. The stop still runs at the same point, with the same arguments, and its answer goes to finish_attached_stop unchanged, so behaviour is the same. docs/architecture.md and the service_control.rs header now describe the one-way edge. Signed-off-by: Jussi Elo <jussi.elo@amd.com>
jussielo-amd
marked this pull request as ready for review
November 5, 2026 20:42
jussielo-amd
requested review from
siloteemu
and
a balanced review from Copilot
November 5, 2026 20:42
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues are recorded for the managed-service dependency refactor.
No open issues 🎉
What changed in this PR
Removes circular dependencies among the managed-service modules in apps/rocm, establishing one-way dependencies without intended user-visible behavior changes.
Changes:
- Extracts background-helper liveness checks, notification text, and existing tests into
background_helper.rs. - Passes the attached-serve Ctrl-C stop operation from
serve_cmd.rsinto the launcher as a callback. - Updates architecture documentation and module comments to describe the new dependency structure.
| File | Description |
|---|---|
docs/architecture.md |
Documents the helper module and one-way service dependencies. |
apps/rocm/src/uninstall_plan.rs |
Reads helper warnings from the extracted module. |
apps/rocm/src/services_text.rs |
Reads helper notes without depending on the launcher. |
apps/rocm/src/service_launch.rs |
Uses extracted helper checks and accepts a stop callback. |
apps/rocm/src/service_control.rs |
Updates comments describing callers and dependencies. |
apps/rocm/src/serve_cmd.rs |
Supplies the existing managed-stop operation as a callback. |
apps/rocm/src/main.rs |
Registers the new helper module. |
apps/rocm/src/background_helper.rs |
Houses relocated helper logic, tests, and shared test fixtures. |
Review effort: Balanced
Only docs/architecture.md conflicted: the clap-tree move re-pointed several module entries from main.rs to cli.rs where this branch added the background_helper.rs entry and reworded the service_launch.rs one. Takes the re-pointed entries from main, keeps this branch's new and reworded text, and applies the cli.rs re-pointing to the reworded service_launch.rs entry. Signed-off-by: Jussi Elo <jussi.elo@amd.com>
Collaborator
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes ROCMAI-871. The managed-service modules in
apps/rocmimported each other in production code:services_text.rsandservice_launch.rswere a pair (the stop-result text needed the background-helper note from the launcher, and the launcher needed the stop-result renderers), and since the stop path moved intoservice_control.rs,service_launch.rsandservice_control.rswere a second pair (the launcher tookrun_internal_sandbox_toolfrom the control module for the attached-serve Ctrl-C, and the control module took the endpoint-key guard and the spawn helpers from the launcher). The two pairs also closed a three-module loop, so none of the three could be read, tested or moved without the other two. This change makes the graph one-way with two small commits and no behaviour change.The dependency order is now
services_text.rsbelowservice_launch.rsbelowservice_control.rs, withservices_cmd.rs,runtime_services.rsandserve_cmd.rsabove them. Only two edges had to go. The endpoint-key guard and the spawn helpers stay where they are, because the control module is the natural caller of them and the launcher does not import it any more.What moved
background_helper_already_running,HelperNote,helper_note_for,background_helper_note(and their five tests plus theruntime_stateandset_helper_factsfixtures)service_launch.rsbackground_helper.rsservice_launch.rscalledservice_control::run_internal_sandbox_toolrun_attached_servicetakes the stop as a parameter,serve_cmd.rspasses the same callThe first commit is a verbatim move. The leaf imports nothing from the service modules, so
services_text.rsanduninstall_plan.rsread the note from it, andservice_launch.rsreads the liveness check from it for its autostart decision (spawning the helper stays inservice_launch.rs). The two fixtures becamepub(crate)because the autostart and stop-output tests that stay inservice_launch.rsuse them too.The second commit is not a move, and I could not make it one:
run_internal_sandbox_toolcalls the stop and restart paths that live inservice_control.rs, so it cannot be pushed down below the launcher. Its one call inservice_launch.rsis the Ctrl-C arm of an attached serve, so the dependency is cut there:run_attached_servicegets a finalstop_service: impl FnOnce(&AppPaths, &str) -> Result<serde_json::Value>argument, andserve_cmd.rs, which already sits above both modules and is the only caller, passesrun_internal_sandbox_tool(paths, SandboxToolArg::StopServer, Some(service_id), true), the exact call that was made before. The stop runs at the same point with the same arguments and its answer still goes tofinish_attached_stopunchanged.Production import edges among the seven service modules, before and after (test-only code ignored;
service_launch.rs -> service_hints.rsandservices_text.rs -> service_hints.rsare unchanged and omitted below where nothing changed). Removed edges are marked.services_texttoservice_launch(background_helper_note)service_launchtoservice_control(run_internal_sandbox_tool)service_launchtoservices_text(render_service_action_result,render_service_action_result_with_helper_note,service_stop_unconfirmed,read_optional_tail_lines)service_controltoservice_launch(ensure_public_service_has_endpoint_key,attach_background_stdio,detach_background_command,managed_engine_startup_failure_detail,managed_service_process_command)service_controltoservices_text(internal_stop_server_value,load_managed_service,read_managed_service_manifest)service_recordstoservices_text(load_managed_service,validate_service_id)services_cmdtoservice_control,service_records,service_hints,services_textruntime_servicestoservice_control(restart_internal_managed_service),services_text(load_managed_service)serve_cmdtoservice_control(run_internal_sandbox_tool)services_text,service_launch,uninstall_plantobackground_helperBefore the change a script over the production
use crate::...statements and inlinecrate::...paths of the seven files found three cycles:services_textandservice_launch,service_launchandservice_control, andservices_text,service_launch,service_control. After it the same script reports none.Verification
Ran on this branch:
cargo fmt --all --check;cargo clippy -p rocm --all-targets -- -D warnings;cargo test -p rocm --bin rocm --no-fail-fast(1509 passed, 8 ignored); the sorted leaf-name test list fromcargo test -p rocm --bin rocm -- --listis identical before and after (1517 tests, including the five tests that moved tobackground_helper.rs);cargo xtask manifest --check;cargo xtask check-crate-edges; the lychee hook ondocs/architecture.md(runs in the commit hooks); the leak scan of the diff against the base (the only keyword hits are existing identifiers such asrun_internal_sandbox_tooland Rust's "private types"); and the end-to-end scenarios that traverse the changed paths against a debug build with the test hooks (ROCM_CLI_BINARYandROCM_CLI_ROCMD_BINARYpointing at it):service-stop-01toservice-stop-05,automations-11(the helper exiting once the last watcher is off, which the note's text names) and the sevenservice-cleanupscenarios, all green.Not run: the Windows type-check of this crate (
cargo clippy -p rocm --target x86_64-pc-windows-msvc), which cannot build here because the C toolchain foraws-lc-sysis missing for that target. Nothing gated oncfg(windows)was edited and the moved items carry no cfg gates, so the risk is limited to import lists. The full workspace gate,scripts/smoke_local.pyand the whole e2e suite are left to CI.No test was added, so there is no new test to break. The one changed call site (the attached-serve Ctrl-C stop in
run_attached_service) has no unit or scenario coverage before or after, because it needs an interactive terminal;finish_attached_stop, which handles the answer, keeps its existing tests. I checked the call by reading it against the removed one rather than by a test.User-visible behaviour
None, so no new scenario. This is a structure change inside
apps/rocm: no command output, exit code, file or engine selection changes. The scenarios listed above are the ones that already cover the stop path, the stop text and the helper note.Notes for reviewers
Read the commits in order. The first is mechanical; the second is the only place a signature changes.
docs/architecture.mdis updated in each commit (a new entry forbackground_helper.rs, and theservice_control.rsandservice_launch.rsentries now describe the one-way edges instead of the cycles). Two of the touched lines still carry the older "Phase 6b" wording because I edited them in place rather than rewriting them.Open pull requests that touch the same files: the one that moves the stop routine into
rocm-core(#929) editsservice_control.rsand the same longservice_control.rsentry indocs/architecture.md, so expect a one-line conflict there that resolves by keeping both changes; it merges cleanly in the code. The endpoint-key guard pull request (#926) also editsservice_launch.rs; its code hunks do not overlap this change, and it already conflicts with the current base inmain.rsandservices_text.rsindependently of this change, since it predates the move of the stop path.