Skip to content

Commit e8a5cca

Browse files
kriszypclaude
andcommitted
fix: register operations in worker threads so replication WS can dispatch them
After 40600bf moved the HTTP operations API to the main thread only, `server.registerOperation` was no longer wired up in worker threads. Plugins that call `server.registerOperation?.({...})` at module load time (e.g. replication's setNode.ts, clusterStatus.ts) silently no-op'd in workers because the optional-chain short-circuits when the method is undefined. This breaks inter-node replication setup: `add_node` opens a WebSocket to the target node's replication port (9933) and sends `add_node_back`. The WS handler runs in a worker thread and dispatches via `server.operation()`, which looks up in the operation function map. Since `add_node_back` was never registered in the worker, every cluster setup attempt fails with: "Operation 'add_node_back' not found and connection was required to sign certificate" This blocks `fullyConnectedReplication.test.mjs`, `replicationLoad.test.mjs`, and anything else that exercises multi-node clustering. Fix: in worker threads, eagerly require `serverHelpers/serverUtilities` directly, which installs `server.operation`, `server.registerOperation`, and initializes the operation function map without binding the fastify HTTP layer (that stays main-thread-only per the original change). Verified by re-running `fullyConnectedReplication.test.mjs` — 12/12 pass (6 RocksDB + 6 LMDB). `replicationLoad.test.mjs` `connect nodes` and `Deploy app and test replication` now pass; remaining failures (`replicate across many databases`, `replicate insert/upsert across all nodes`) are unrelated concurrency / many-database issues. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
1 parent 063788a commit e8a5cca

1 file changed

Lines changed: 10 additions & 0 deletions

File tree

components/componentLoader.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,16 @@ export const TRUSTED_RESOURCE_PLUGINS = {
116116
};
117117
if (isMainThread) {
118118
TRUSTED_RESOURCE_PLUGINS.operationsApi = require('../server/operationsServer');
119+
} else {
120+
// The HTTP operations API itself only binds in the main thread, but worker threads still
121+
// dispatch operations — most notably, the replication WebSocket handler in workers receives
122+
// inter-node operations like `add_node_back` and calls `server.operation(...)`. That requires
123+
// `server.operation` / `server.registerOperation` to be wired up here too, and the operation
124+
// function map to be initialized, BEFORE component plugins (replication, etc.) load and call
125+
// `server.registerOperation?.({...})` at their module top level. Requiring serverUtilities
126+
// directly (rather than the full operationsServer) avoids binding the fastify HTTP layer in
127+
// workers while still installing the dispatch machinery.
128+
require('../server/serverHelpers/serverUtilities');
119129
}
120130

121131
for (const { name, packageIdentifier } of getEnvBuiltInComponents()) {

0 commit comments

Comments
 (0)