first commit
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
# `RemoteWorker`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
`RemoteWorker` extends `AbstractWorker` and delegates execution to a remote endpoint via an injected `WorkerCommunicator`. It manages the connect / reconnect lifecycle (with `@suaveplan/retry`-style exponential backoff routed through `sleep`), runs a periodic health-check loop, and reacts to communication failures by pinging and either reporting the worker still-reachable or marking it `UNHEALTHY`. The connect loop is bounded — no recursion — and every retry attempt is captured in the OTel `queue_dist_http.connect.attempts_total` counter.
|
||||
|
||||
## Features
|
||||
|
||||
- `start()` calls `#connect` (exponential backoff between attempts) then starts a `setInterval` health-check loop.
|
||||
- `stop(force, signal?)` halts the loop, disconnects the communicator, and flips `#isConnected` to `false`.
|
||||
- `doExecuteTask` refuses when not connected (`HTTP.CONNECT_FAILED`).
|
||||
- Communication-error recovery: ping with a 5-second timeout; reachable → log + propagate; unreachable → `markUnhealthy("Unreachable")` + `#isConnected = false`.
|
||||
- `getHealth()` proxies to the remote and refreshes `lastHealthCheck` / `lastHealthStatus`; on failure returns a fallback unhealthy payload.
|
||||
- Configurable `healthCheckIntervalMs`, `maxConnectionAttempts`, `initialBackoffMs`, `maxBackoffMs`.
|
||||
- `getCapabilities()` advertises `{ isRemote: true, protocol, endpoint }` so strategies can route work.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { HttpWorkerCommunicator } from "@suaveplan/queue-distribution-http";
|
||||
import { RemoteWorker } from "@suaveplan/queue-distribution-http/worker/remote/remote";
|
||||
|
||||
const communicator = new HttpWorkerCommunicator();
|
||||
const worker = new RemoteWorker("https://worker.example", communicator, {
|
||||
healthCheckIntervalMs: 15_000,
|
||||
maxConnectionAttempts: 5,
|
||||
});
|
||||
|
||||
await worker.start();
|
||||
const result = await worker.executeTask(task, input);
|
||||
await worker.stop();
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
For deterministic property-tests, inject a custom communicator and watch connect retries with a fake clock.
|
||||
|
||||
```ts
|
||||
import { RemoteWorker } from "@suaveplan/queue-distribution-http/worker/remote/remote";
|
||||
import type { WorkerCommunicator } from "@suaveplan/queue-distribution-http";
|
||||
|
||||
let connectAttempts = 0;
|
||||
const flakyCommunicator: WorkerCommunicator = {
|
||||
sendTask: async (_e, _t, input) => input as never,
|
||||
connect: async () => {
|
||||
connectAttempts += 1;
|
||||
if (connectAttempts < 3) throw new Error("refused");
|
||||
},
|
||||
checkStatus: async () => "ONLINE",
|
||||
checkHealth: async () => ({
|
||||
isHealthy: true,
|
||||
metrics: { cpu: 0, memory: 0, tasksFailed: 0, tasksSucceeded: 0, responseTime: 0 },
|
||||
}),
|
||||
disconnect: async () => undefined,
|
||||
ping: async () => 5,
|
||||
getProtocol: () => "http",
|
||||
};
|
||||
|
||||
const worker = new RemoteWorker("https://worker", flakyCommunicator, {
|
||||
maxConnectionAttempts: 5,
|
||||
initialBackoffMs: 0,
|
||||
healthCheckIntervalMs: 60_000,
|
||||
});
|
||||
await worker.start();
|
||||
console.log(connectAttempts); // 3
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `class RemoteWorker extends AbstractWorker`.
|
||||
- `constructor(endpoint, communicator, options?: RemoteWorkerOptions, deps?: AbstractWorkerDeps)`.
|
||||
- `interface RemoteWorkerOptions extends AbstractWorkerOptions` — `healthCheckIntervalMs?`, `maxConnectionAttempts?`, `initialBackoffMs?`, `maxBackoffMs?`.
|
||||
- `getEndpoint(): string`, `getCommunicator(): WorkerCommunicator`, `isConnected(): boolean`.
|
||||
- `getHealth(signal?): Promise<WorkerHealth>` — overrides the abstract default.
|
||||
- Protected: `doExecuteTask`, `doStart`, `doStop`, `getType()`, `getCapabilities()`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The connect loop iterates up to `maxConnectionAttempts` times, doubling the delay each iteration (capped at `maxBackoffMs`). On every retry, the loop also re-checks the remote status — so a worker that responds OK on the third attempt connects without further delay. Communication errors during sendTask are NOT silently swallowed: the worker rethrows so the calling `WorkerManager` can retry against a different worker via its load-balancing strategy. The ping-based reachability probe runs in parallel with the rethrow so the worker's `status` is up-to-date by the time the next strategy invocation observes the pool.
|
||||
Reference in New Issue
Block a user