fix(gateway): reduce plugin registry lock duration during load/unload - #25
Merged
Merged
Conversation
The write lock on the plugin registry was held across expensive async operations: plugin.load() (MCP handshake + subprocess spawn) and plugin.unload() (child process teardown). This blocked all other registry readers/writers for the entire duration. Restructure to take-out/put-back pattern: briefly lock to unregister the plugin, perform the async operation without the lock, then briefly lock again to re-register. Applies to: - RPC load_plugin handler - RPC unload_plugin handler - Startup auto-load background task
Member
Author
|
Confirmed not blocking when running a plugin install and a plugin list at the same time with two different terminals. |
4 tasks
joshuajbouw
added a commit
that referenced
this pull request
Jun 10, 2026
…livery (#883) ## Linked Issue Closes #882 ## Summary The publish/subscribe **ACL authorization** used the strict `topic::topic_matches` (a `*` is exactly one segment) while event **delivery** uses `astrid_events::TopicMatcher` (a trailing `*` is a subtree wildcard — one or more segments at any depth). That divergence forced capsule manifests to enumerate wildcard depth (`astrid.v1.admin.*` / `*.*` / `*.*.*`) just to authorize publishing topics whose depth varies or is unknown (uuid suffixes, variable sub-paths), and it's the same matcher asymmetry that made the cli run-loop crash confusing. This authorizes via the route-layer matcher so a declared trailing `*` covers the whole subtree, and makes `TopicMatcher::matches_topic` the single source of truth shared by delivery and ACL — they can never silently diverge again. ## Changes - `astrid-events`: extract `TopicMatcher::matches_topic(&str)` from the existing subtree logic; `matches(&event)` delegates to it. Added a direct subtree test. - `astrid-capsule`: the two ACL checks (`publish_inner`, `check_subscribe_acl`) authorize via `TopicMatcher::new(pattern).matches_topic(topic)` instead of strict `topic_matches`. - Scope: only the two ACL sites change. Interceptor dispatch (`dispatcher.rs`) keeps strict `topic_matches`; the runtime "wildcard must be terminal" subscribe gate is unchanged. Permissive change — authorizes more, denies nothing previously allowed; delivery was already subtree, so nothing that worked stops working. Adversarial pass: ACL is per-capsule declared intent (no cross-principal/escalation path); no match-all hole (a bare `*` stays single-segment; only `prefix.*` is subtree-under-prefix); subscribe pattern-vs-pattern is sound (a broad ACL authorizes a narrower request, an exact ACL does not authorize a broader wildcard request). Breadth is the operator's decision at install (the manifest declares intent; capabilities + install review are the boundary). ## Test Plan ### Automated - [x] `cargo test --workspace` passes - [x] No new clippy warnings `cargo test -p astrid-events` (matcher, incl. new `matches_topic_subtree_for_acl`) and `-p astrid-capsule --lib` (ACL / topic / audit-scope) — green, no regressions. ### Manual Rebuilt the daemon, collapsed the cli manifest to `astrid.v1.request.*` + `astrid.v1.admin.*` (dropping the depth enumeration and the mcp front-door exacts), reinstalled. `astrid agent list` (a 6-segment `astrid.v1.admin.response.agent.list` round-trip) and `astrid mcp serve` `tools/list` (8 tools, a 6-segment `astrid.v1.request.mcp.tools.list` publish) both work — authorized by the single subtree patterns. Follow-up (separate, capsule-cli): collapse the cli manifest once this lands — it currently enumerates depth + lists the mcp exacts (capsule-cli #25) because it must work against today's strict kernel. ## Checklist - [x] Linked to an issue - [x] CHANGELOG.md updated under `[Unreleased]`
75 tasks
5 tasks
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
plugin.load()(MCP handshake + subprocess spawn) andplugin.unload()(child process teardown)unregisterthe plugin, perform the async operation without the lock, then briefly lock again toregisterit backload_plugin, RPCunload_plugin, and the startup auto-load background taskTest plan
cargo check -p astrid-gateway -p astrid-cli— cleancargo clippy— no errorscargo fmt --check— no issues