feat(node): activate dynamic plugins#366
Conversation
|
Caution Review failedAn error occurred during the review process. Please try again later. WalkthroughChangesThe plugin system now supports owned dynamic activation with serialized mutations, registration-aware rollback, guarded native and worker teardown, and explicit lifecycle handles. CLI startup uses static or dynamic activation modes, while Node.js exposes dynamic activation and asynchronous close APIs with integration coverage. Plugin activation lifecycle
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant NodeClient
participant NodeBinding
participant PluginHostActivation
participant PluginRegistry
participant NativeOrWorkerRuntime
NodeClient->>NodeBinding: activateDynamicPlugins(config, specs)
NodeBinding->>PluginHostActivation: activate(config, specs)
PluginHostActivation->>PluginRegistry: acquire host lease and initialize callbacks
PluginHostActivation->>NativeOrWorkerRuntime: load and register dynamic plugins
NativeOrWorkerRuntime-->>PluginHostActivation: activation handles and report
PluginHostActivation-->>NodeBinding: owned activation
NodeBinding-->>NodeClient: activation report and close()
NodeClient->>NodeBinding: close()
NodeBinding->>PluginHostActivation: clear()
PluginHostActivation->>PluginRegistry: clear callbacks and configuration
PluginHostActivation->>NativeOrWorkerRuntime: deregister and shut down
NativeOrWorkerRuntime-->>PluginHostActivation: teardown outcome
PluginHostActivation-->>NodeBinding: completion
NodeBinding-->>NodeClient: close resolved
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
AteebNoOne
left a comment
There was a problem hiding this comment.
Thanks for putting this together! I took a look at the JavaScript bindings and left a quick suggestion on the JSDoc typing to help with intellisense. Looking forward to seeing this land!
| * @returns {object|null|undefined} The last activation report, if one exists. | ||
| * @remarks This returns an empty value until `initialize` succeeds at least | ||
| * once in the current process. | ||
| */ |
There was a problem hiding this comment.
ince deterministic teardown is required for these dynamic plugins, should we implement Symbol.asyncDispose on the returned activation object under the hood? Doing so would allow Node developers to use the modern await using syntax for guaranteed cleanup, even if the runtime throws an error before close() is explicitly called.
a4ecdcc to
baa5cd8
Compare
License DiffCompared against Lockfile license changesLockfile License ChangesRustAdded
Removed
Updated/Changed
NodeAdded
Removed
Updated/Changed
PythonAdded
Removed
Updated/Changed
Status output |
baa5cd8 to
bce713b
Compare
bce713b to
0931dc0
Compare
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
0931dc0 to
7f9ac76
Compare
mnajafian-nv
left a comment
There was a problem hiding this comment.
Thanks, this is in good shape overall. I left one Node-surface comment on the public activation-handle contract.
| export interface DynamicPluginActivation { | ||
| /** Validation report produced by the successful activation. */ | ||
| readonly report: ConfigReport; | ||
| /** Whether this object still owns the dynamic plugin host. */ |
There was a problem hiding this comment.
I’d tighten this public wording to match the behavior the tests already lock in. active becomes false as soon as close() starts, before the returned promise resolves and before teardown is necessarily complete. Framing this as 'teardown has not started for this handle' or calling out that false does not by itself mean a replacement activation can succeed yet would make the Node contract easier to use correctly.
zhongxuanwang-nv
left a comment
There was a problem hiding this comment.
I think overall this is good. Thanks Bryan!
| function activateDynamicPlugins(config, specs) { | ||
| return lib.activateDynamicPlugins(config, specs); | ||
| } | ||
|
|
There was a problem hiding this comment.
I think this is the same thing that happened in PR-365, that here they might skip the base plugins.toml file
Overview
This adds an owned Node binding for explicit native and worker dynamic-plugin activation. It is stacked on #364; once that PR lands, this diff reduces to the Node binding and its tests.
Static-only harness-native applications keep using
plugin.initialize()/plugin.clear().activateDynamicPlugins(...)requires at least one dynamic specification; its base config may also contain static components, which initialize before components appended by the dynamic plugins.Details
activateDynamicPlugins(config, specs)with camelCase native and worker specifications.report,active, and asyncclose().plugin.initialize()andplugin.clear()behavior. Empty dynamic activation is rejected without claiming process ownership, so static initialization remains available.Where should the reviewer start?
Start with
crates/node/src/api/mod.rsfor N-API ownership and cleanup, thencrates/node/plugin.d.tsfor the public contract. The lifecycle cases are incrates/node/tests/dynamic_plugin_tests.mjs.Validation
npm run build-debugcargo fmt --all -- --checkcargo clippy -p nemo-relay-node --all-targets -- -D warningsgit diff --checkRelated Issues: (use one of the action keywords Closes / Fixes / Resolves / Relates to)
Relates to #364.
Summary by CodeRabbit
New Features
close()teardown.Bug Fixes