Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .agents/features/workers.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Workers are separate Node processes that poll the app for jobs and execute flows

> Canonical term definitions live in the bounded-context glossaries — see [CONTEXT-MAP.md](../../CONTEXT-MAP.md).

- **`Resolver` / `Runtime`** — the two roles of the in-process `@activepieces/sandbox` library that the worker drives per job. The **`Resolver`** (worker-side, owns the only `apiClient`) turns a job into a fully-materialized `ProvisionInput`: it resolves the `flowVersion`, piece metadata, and a ready (compiled) flow bundle, disabling the flow on a missing piece. It returns a discriminated `ResolveResult` (`ready` — with the resolved `flowVersion` when a `flow` was passed; `flow-not-found`; `disabled`) rather than throwing for expected missing/disabled-flow cases. The **`Runtime`** (the in-process single sandbox box) exposes `execute` / `getActiveExecutors` / `shutdown` and never reaches the app; `execute` owns the box lifecycle internally — **acquire → provision (materialize pieces/code into the bind-mounted cache) → run one engine operation → release on success / invalidate on throw** — re-raising the sandbox `ActivepiecesError` codes (timeout / memory / log-size) that handlers already catch. The Resolver's bundle path can return a **bundle hit** from the flow bundle store (`getFlowBundle` RPC): when a locked flow version's bundle is already cached, it supplies the frozen flow definition + piece manifest + compiled code directly, bypassing the per-piece `getPiece` RPC round-trips. Locked flows that change pieces must be re-locked to produce a new bundle; a freshly resolved locked version is published back (best-effort, after execution cache setup). **Bundle transport:** when the `FLOW_BUNDLE` file is S3-backed and `S3_USE_SIGNED_URLS` is on, the bundle bytes never cross the Socket.IO RPC — `getFlowBundle` returns a signed GET URL and `prepareFlowBundleUpload` returns a signed PUT URL, and the worker reads/writes S3 directly via the built-in `fetch` (`sandbox/src/lib/utils/bundle-http.ts`, dependency-free). S3-backed bundles without signed URLs stream inline `Buffer` over the socket (`uploadFlowBundle`). On **DB-backed storage bundles are not persisted at all** — `prepareFlowBundleUpload` returns `{ kind: 'skip' }` and the worker always builds inline via the legacy resolve path (DB storage gains nothing from bundle caching and a null-data pre-save would throw). Any signed-link or fetch failure likewise degrades to the legacy `getVersion` + `getPiece` resolve path — a bundle never fails a run.
- **`Resolver` / `Runtime`** — the two roles of the in-process `@activepieces/sandbox` library that the worker drives per job. The **`Resolver`** (worker-side, owns the only `apiClient`) turns a job into a fully-materialized `ProvisionInput`: it resolves the `flowVersion`, piece metadata, and a ready (compiled) flow bundle, disabling the flow on a missing piece. It returns a discriminated `ResolveResult` (`ready` — with the resolved `flowVersion` when a `flow` was passed; `flow-not-found`; `disabled`) rather than throwing for expected missing/disabled-flow cases. The **`Runtime`** (the in-process single sandbox box) exposes `execute` / `getActiveExecutors` / `shutdown` and never reaches the app; `execute` owns the box lifecycle internally — **acquire → provision (materialize pieces/code into the bind-mounted cache) → run one engine operation → release on success / invalidate on throw** — re-raising the sandbox `ActivepiecesError` codes (timeout / memory / log-size) that handlers already catch. A code step whose **dependency install (`bun install`) or compile (`esbuild`) phase fails** is degraded into a valid runtime-throwing `index.js` stub (see `code-builder.ts`) rather than letting the error escape provision — so the run ends with a user-attributed **`FAILED`** step instead of an opaque **`INTERNAL_ERROR`** that would trigger retries (the inputs are user data, not a platform fault). The Resolver's bundle path can return a **bundle hit** from the flow bundle store (`getFlowBundle` RPC): when a locked flow version's bundle is already cached, it supplies the frozen flow definition + piece manifest + compiled code directly, bypassing the per-piece `getPiece` RPC round-trips. Locked flows that change pieces must be re-locked to produce a new bundle; a freshly resolved locked version is published back (best-effort, after execution cache setup). **Bundle transport:** when the `FLOW_BUNDLE` file is S3-backed and `S3_USE_SIGNED_URLS` is on, the bundle bytes never cross the Socket.IO RPC — `getFlowBundle` returns a signed GET URL and `prepareFlowBundleUpload` returns a signed PUT URL, and the worker reads/writes S3 directly via the built-in `fetch` (`sandbox/src/lib/utils/bundle-http.ts`, dependency-free). S3-backed bundles without signed URLs stream inline `Buffer` over the socket (`uploadFlowBundle`). On **DB-backed storage bundles are not persisted at all** — `prepareFlowBundleUpload` returns `{ kind: 'skip' }` and the worker always builds inline via the legacy resolve path (DB storage gains nothing from bundle caching and a null-data pre-save would throw). Any signed-link or fetch failure likewise degrades to the legacy `getVersion` + `getPiece` resolve path — a bundle never fails a run.
- **`WorkerProps`** — typed worker identity sent in every heartbeat (`EXECUTION_MODE`, `WORKER_CONCURRENCY`, `SANDBOX_MEMORY_LIMIT`, `REUSE_SANDBOX`, `version`). Previously a free-form `Record<string,string>`.
- **`WorkerSettingsResponse`** — runtime config the app hands a worker on connect; now includes `APP_VERSION` (the app's release).
- **`connectionGeneration`** — worker-side counter bumped on every disconnect; in-flight poll loops exit when their captured generation goes stale, so a reconnect starts fresh loops.
Expand Down
Loading
Loading