Worker Communication
Product Factory uses a gateway pattern where all client requests flow through a single entry point (worker-gateway) that routes them to the appropriate service worker.
Request Flow
Client (Browser) │ ▼worker-gateway (port 8787) │ ├── Session verification (/auth/get-session → worker-auth) ├── Header injection (X-User-Id, X-User-Role, X-App-Key) │ ▼ Route matching ├── /auth/* → worker-auth ├── /credits/* → worker-billing ├── /orders/* → worker-billing ├── /tickets/* → worker-support ├── /keys/* → worker-ai ├── /content/* → worker-content ├── /admin/* → worker-admin (or domain-specific worker) └── /payment/* → worker-billingService Bindings
Workers communicate via Cloudflare Service Bindings, which allow direct invocation without network overhead. Bindings are configured in each worker’s wrangler.toml:
[[services]]binding = "AUTH_SERVICE"service = "worker-auth"The gateway uses bindings to proxy requests:
app.all("/auth/*", (c) => c.env.AUTH_SERVICE.fetch(c.req.raw));Context Propagation
For authenticated routes, the gateway injects user context before proxying:
- Verify session via
worker-auth - Extract
user_id,role, andapp_keyfrom the session - Set
X-User-Id,X-User-Role, andX-App-Keyheaders on the proxied request - Downstream workers read these headers to identify the caller
This means downstream workers trust the gateway for authentication and do not independently verify sessions.
Cross-Service Calls
When a worker needs data from another service (e.g., worker-ai checking credit balance on worker-billing), it uses the service binding directly:
const response = await c.env.BILLING_SERVICE.fetch( new Request("http://internal/credits/check", { method: "POST", headers: { "X-User-Id": userId, "X-App-Key": appKey }, body: JSON.stringify({ amount: requiredCredits }), }));Error Handling
If a downstream worker returns an error, the gateway passes it through to the client. The consistent ok/error response format ensures clients can handle errors uniformly regardless of which worker produced them.