|
| 1 | +# Offline-build flow (`TRIGGER_INDEX_OFFLINE=1`) |
| 2 | + |
| 3 | +This document covers the build pipeline for operators who need to build a |
| 4 | +tasks image **without calling out to a live trigger.dev API at build time** |
| 5 | +— e.g. air-gapped / regulated build environments (Apollo Foundry, |
| 6 | +GameWarden, GovCloud single-tenant deploys) where the build host can't |
| 7 | +reach the webapp the image will eventually be deployed against. |
| 8 | + |
| 9 | +## How it works |
| 10 | + |
| 11 | +Two pieces compose: |
| 12 | + |
| 13 | +1. `TRIGGER_INDEX_OFFLINE=1` switches the in-image indexer to a stub |
| 14 | + `CliApiClient` that writes deployment metadata to disk instead of |
| 15 | + POST-ing it to the API. See |
| 16 | + [`packages/cli-v3/src/entryPoints/managed-index-controller.ts`](../src/entryPoints/managed-index-controller.ts) |
| 17 | + (`createOfflineCliApiClient`). The shim implements only the three |
| 18 | + methods that `indexDeployment` actually calls: |
| 19 | + - `getEnvironmentVariables()` → returns `{}` (no project env vars |
| 20 | + reachable at build time) |
| 21 | + - `createDeploymentBackgroundWorker(_id, body)` → writes |
| 22 | + `index-metadata.json` to `process.cwd()` |
| 23 | + - `failDeployment(_id, body)` → writes `index-error.json` |
| 24 | +2. The build script (a small `build.mjs` driven by `@trigger.dev/cli-v3`'s |
| 25 | + `internal` subpath — see [`packages/cli-v3/src/internal.ts`](../src/internal.ts)) |
| 26 | + passes `offlineIndex: true` to `buildImage` and `--containerfile-module=<path>` |
| 27 | + to use a custom Containerfile generator. See |
| 28 | + [`packages/cli-v3/src/deploy/buildImage.ts`](../src/deploy/buildImage.ts) — |
| 29 | + when `offlineIndex: true`, the generated Containerfile sets |
| 30 | + `ARG TRIGGER_INDEX_OFFLINE` and forwards it as a build arg into the |
| 31 | + indexer stage; the final stage copies `/app/index-metadata.json` into |
| 32 | + the runtime image at `/app/`. |
| 33 | + |
| 34 | +The metadata gets baked into the runtime image, then re-played against |
| 35 | +the real webapp API later by a separate **register** process running |
| 36 | +inside the cluster (where it _can_ reach the webapp). The register |
| 37 | +process uses the same image, reads `/app/index-metadata.json`, hits the |
| 38 | +real webapp API via `getProjectClient`, and finalizes the deployment. |
| 39 | + |
| 40 | +## Operator responsibilities |
| 41 | + |
| 42 | +- Provide a `containerfileModule` if the default Containerfile doesn't fit |
| 43 | + (e.g. base on UBI / chainguard / a FIPS-validated runtime). The module's |
| 44 | + job is to emit the multi-stage Containerfile text that invokes the |
| 45 | + indexer stage with `TRIGGER_INDEX_OFFLINE=1` and copies |
| 46 | + `/app/index-metadata.json` into the final image. |
| 47 | +- Run your `build.mjs` equivalent on the build host (no API access |
| 48 | + required). The output is just the tasks image pushed to your registry. |
| 49 | +- Run your `register.mjs` equivalent on the deploy host (Kubernetes Job / |
| 50 | + systemd unit / etc.) using **the same image**. It reads |
| 51 | + `/app/index-metadata.json` and re-issues `createDeploymentBackgroundWorker` |
| 52 | + against the live webapp. |
| 53 | + |
| 54 | +## Example (GovSignals) |
| 55 | + |
| 56 | +The GovSignals umbrella ships a worked example of this pattern in its |
| 57 | +consumer repo (not in this chart): |
| 58 | + |
| 59 | +- `infrastructure/containers/dockerfiles/trigger-dev/tasks/build.mjs` — |
| 60 | + build-host entry point (calls `loadConfig` → `buildWorker` → `buildImage` |
| 61 | + with `offlineIndex: true` and a custom `containerfile.mjs`). |
| 62 | +- `infrastructure/containers/dockerfiles/trigger-dev/tasks/containerfile.mjs` |
| 63 | + — the operator-supplied Containerfile generator. |
| 64 | +- `infrastructure/containers/dockerfiles/trigger-dev/register-tasks/register.mjs` |
| 65 | + — in-cluster `register-tasks` Job that re-plays the indexed payload |
| 66 | + against the live webapp. |
| 67 | + |
| 68 | +A reference implementation, not a supported public API. |
| 69 | + |
| 70 | +## Caveats |
| 71 | + |
| 72 | +- Project env vars are **not** available at build time in offline mode. |
| 73 | + Any task whose indexing step depends on a project env var will index |
| 74 | + with `{}`. If your tasks need env vars at index time, use the online |
| 75 | + flow. |
| 76 | +- The offline shim returns synthetic `id: "offline"` / `version: "offline"` |
| 77 | + from `createDeploymentBackgroundWorker`. Anything in your build pipeline |
| 78 | + reading those fields must be aware that the real id/version is assigned |
| 79 | + later, by the register step. |
| 80 | +- `TRIGGER_INDEX_OFFLINE=1` only affects the indexer stage. The rest of |
| 81 | + the runtime (the tasks themselves) still talks to the live API at |
| 82 | + runtime as normal. |
0 commit comments