You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The self-hosted server flavour is meant to deploy as a copyable folder — user copies the build output to a server and runs it (a packaging CLI is planned to produce this folder). This works in webiny watch today, but the produced build/ is not self-contained for a real deploy. Two related gaps, both stemming from how the api handler is bundled (packages/build-tools/bundling/function/createRsbuildConfig.js, target: node, everything bundled into build/handler.mjs).
Problem A — runtime sidecar worker files are not shipped
Two server packages load a separate file at runtime via import.meta.url:
@webiny/background-tasks-server → dist/worker/workerEntry.js (spawned via worker_threads).
@webiny/api-scheduler-server → dist/jobs/pollWorker.js (handed to bree).
When bundled, rspack:
freezes import.meta.url to the build-machine source path, e.g. file:///Users/.../packages/background-tasks-server/dist/service/WorkerTaskService.js, and
does not emit the sidecar files into build/.
So on a shipped build/, new Worker(...) / bree resolve to a nonexistent path → ENOENT. (In dev it happens to work only because the frozen absolute path points at the real monorepo dist/.)
Confirmed: grep workerEntry build/handler.mjs finds only the string; there is no build/worker/ or build/jobs/, no emitted chunk.
Problem B — bundle externals are not provisioned for the server flavour
The bundler externalizes packages that shouldn't/can't be bundled:
Native binaries:sharp, better-sqlite3 (via knex) — cannot be turned into JS.
Externals are resolved from node_modules at runtime. Who provides them differs per flavour:
External
AWS provides via
Server provides via
aws-sdk
Lambda runtime (ambient)
nothing — must ship
sharp
Lambda layer
nothing — must ship
knex / better-sqlite3
(n/a)
must ship
background-tasks-server
(unused)
must ship
api-scheduler-server
(unused)
must ship
On AWS, externals are ambient (layer + runtime), so build/ alone deploys — leave AWS as-is. On the server, nothing is ambient: every external must be physically included in the deploy artifact. sharp is the loudest example — image processing silently breaks on a server deploy without it, exactly like the worker files.
Problem C — native deps are OS/arch-specific → package in CI
sharp and better-sqlite3 ship per-OS/arch binaries. Assembling the externals node_modules on a Mac bundles the darwin binary → fails on a Linux server. The bundle (handler.mjs) is platform-agnostic JS, but the externals node_modules must be resolved for the target OS/arch — i.e. the packaging step runs in CI on the target platform, or cross-installs (npm --os/--cpu, optionalDependencies).
Proposed direction
Externalize@webiny/background-tasks-server + @webiny/api-scheduler-server in createRsbuildConfig.js (mirrors the existing knex rationale). This ships their sidecar files and un-freezes import.meta.url (resolves from node_modules). Safe for AWS (not imported there; no-op like knex).
Packaging CLI — new command that produces the shippable folder: build/ + a platform-correctbuild/node_modules/ containing the full externals set. Runs in CI for the target platform.
Deploy artifact = build/ + build/node_modules/ (externals). Document this as the server deploy contract.
Externals the server packaging must provision
sharp, knex, better-sqlite3, @webiny/background-tasks-server, @webiny/api-scheduler-server (+ their transitive deps).
Notes / scope
Dev (webiny watch) already works and needs no change: build/ sits deep in the monorepo, so Node resolves all externals by walking up to the root node_modules (which has everything, @webiny/* symlinked to packages/*/dist).
The current PR (feat(self-hosted): background tasks, scheduler & real-time on the server flavour #5414, self-hosted background tasks + scheduler + websockets) intentionally leaves this untouched — watch works there. This issue tracks making the server flavour deployable (externalization + packaging CLI + CI/platform handling), to be done separately.
Context
The self-hosted server flavour is meant to deploy as a copyable folder — user copies the build output to a server and runs it (a packaging CLI is planned to produce this folder). This works in
webiny watchtoday, but the producedbuild/is not self-contained for a real deploy. Two related gaps, both stemming from how the api handler is bundled (packages/build-tools/bundling/function/createRsbuildConfig.js,target: node, everything bundled intobuild/handler.mjs).Problem A — runtime sidecar worker files are not shipped
Two server packages load a separate file at runtime via
import.meta.url:@webiny/background-tasks-server→dist/worker/workerEntry.js(spawned viaworker_threads).@webiny/api-scheduler-server→dist/jobs/pollWorker.js(handed tobree).When bundled, rspack:
import.meta.urlto the build-machine source path, e.g.file:///Users/.../packages/background-tasks-server/dist/service/WorkerTaskService.js, andbuild/.So on a shipped
build/,new Worker(...)/ bree resolve to a nonexistent path →ENOENT. (In dev it happens to work only because the frozen absolute path points at the real monorepodist/.)Confirmed:
grep workerEntry build/handler.mjsfinds only the string; there is nobuild/worker/orbuild/jobs/, no emitted chunk.Problem B — bundle externals are not provisioned for the server flavour
The bundler externalizes packages that shouldn't/can't be bundled:
sharp,better-sqlite3(viaknex) — cannot be turned into JS.aws-sdk.background-tasks-server,api-scheduler-server.Externals are resolved from
node_modulesat runtime. Who provides them differs per flavour:aws-sdksharpknex/better-sqlite3background-tasks-serverapi-scheduler-serverOn AWS, externals are ambient (layer + runtime), so
build/alone deploys — leave AWS as-is. On the server, nothing is ambient: every external must be physically included in the deploy artifact.sharpis the loudest example — image processing silently breaks on a server deploy without it, exactly like the worker files.So the server "self-contained bundle" is really:
Problem C — native deps are OS/arch-specific → package in CI
sharpandbetter-sqlite3ship per-OS/arch binaries. Assembling the externalsnode_moduleson a Mac bundles the darwin binary → fails on a Linux server. The bundle (handler.mjs) is platform-agnostic JS, but the externalsnode_modulesmust be resolved for the target OS/arch — i.e. the packaging step runs in CI on the target platform, or cross-installs (npm --os/--cpu,optionalDependencies).Proposed direction
@webiny/background-tasks-server+@webiny/api-scheduler-serverincreateRsbuildConfig.js(mirrors the existingknexrationale). This ships their sidecar files and un-freezesimport.meta.url(resolves fromnode_modules). Safe for AWS (not imported there; no-op likeknex).build/+ a platform-correctbuild/node_modules/containing the full externals set. Runs in CI for the target platform.build/+build/node_modules/(externals). Document this as the server deploy contract.Externals the server packaging must provision
sharp,knex,better-sqlite3,@webiny/background-tasks-server,@webiny/api-scheduler-server(+ their transitive deps).Notes / scope
webiny watch) already works and needs no change:build/sits deep in the monorepo, so Node resolves all externals by walking up to the rootnode_modules(which has everything,@webiny/*symlinked topackages/*/dist).Related