From 35dbaedf699c7b5f42d7db25c95572fd806c1967 Mon Sep 17 00:00:00 2001 From: nicktrn <55853254+nicktrn@users.noreply.github.com> Date: Mon, 10 Jun 2024 14:13:04 +0100 Subject: [PATCH] v3: self-hosting (#1147) * add amin email regex env var * fix displayed init command for self-hosted setups * shared env var to disable telemetry in cli and webapp * pin sdk version during init * if specified, add api url to dev command shown after init * improve checkpoint support detection * control forced checkpoint simulation via env var * add public init to providers * better checkpoint support check for coordinator * add docker to coordinator image * update docker provider containerfile * bump remaining containers to node 20 * add infra image build to default publish workflow * lockfile * remove concurrency group from infra workflow * add docker provider to build matrix * fix var subst * checkpoint test is docker specific * enable v3 projects by default on self-hosted instances * fix v3 setup command again * add default posthog key * self-hosting docs * add latest tags to versioned infra and webapp builds * some checkpoint errors should skip retrying * add changeset * shorten paragraph * some docs updates * update tunnelling section * add registry setup section * use correct cli push flag * add checkout to v3 branch * update the worker machine setup steps * fix infra build * small docs update * remove unused feature function * Revert "remove unused feature function" This reverts commit cfe07887a12b6893dca8ce499964481a9b3dc9db. * fix self-hosted v3 feature gate * add note about missing arm support * simplify helper script syntax --- .changeset/spicy-terms-bow.md | 9 + .env.example | 2 + .github/workflows/publish-docker.yml | 17 +- .github/workflows/publish-infra.yml | 49 +++- .github/workflows/publish.yml | 5 + apps/coordinator/Containerfile | 8 +- apps/coordinator/src/index.ts | 96 +++--- apps/docker-provider/Containerfile | 51 +++- apps/docker-provider/src/index.ts | 78 +++-- apps/kubernetes-provider/Containerfile | 6 +- apps/kubernetes-provider/src/index.ts | 4 + apps/webapp/app/components/SetupCommands.tsx | 36 ++- apps/webapp/app/env.server.ts | 4 +- apps/webapp/app/features.server.ts | 30 +- apps/webapp/app/models/organization.server.ts | 5 +- apps/webapp/app/models/user.server.ts | 13 +- apps/webapp/app/services/telemetry.server.ts | 5 + docs/images/v3/self-hosting.png | Bin 0 -> 131002 bytes docs/v3/cli-deploy.mdx | 6 +- docs/v3/open-source-self-hosting.mdx | 273 +++++++++++++++++- packages/cli-v3/src/commands/deploy.ts | 2 +- packages/cli-v3/src/commands/init.ts | 13 +- packages/cli-v3/src/telemetry/tracing.ts | 8 +- packages/core-apps/package.json | 7 +- packages/core-apps/src/checkpoints.ts | 67 +++++ packages/core-apps/src/index.ts | 1 + packages/core-apps/src/provider.ts | 7 +- pnpm-lock.yaml | 4 + 28 files changed, 652 insertions(+), 154 deletions(-) create mode 100644 .changeset/spicy-terms-bow.md create mode 100644 docs/images/v3/self-hosting.png create mode 100644 packages/core-apps/src/checkpoints.ts diff --git a/.changeset/spicy-terms-bow.md b/.changeset/spicy-terms-bow.md new file mode 100644 index 000000000..bdb478fa1 --- /dev/null +++ b/.changeset/spicy-terms-bow.md @@ -0,0 +1,9 @@ +--- +"@trigger.dev/core-apps": patch +"trigger.dev": patch +--- + +- Fix init command SDK pinning +- Show --api-url / -a flag where needed +- CLI now also respects `TRIGGER_TELEMETRY_DISABLED` +- Dedicated docker checkpoint test function \ No newline at end of file diff --git a/.env.example b/.env.example index bf5be8f95..26152641b 100644 --- a/.env.example +++ b/.env.example @@ -25,6 +25,8 @@ DEV_OTEL_BATCH_PROCESSING_ENABLED="0" # OPTIONAL VARIABLES # This is used for validating emails that are allowed to log in. Every email that do not match this regex will be rejected. # WHITELISTED_EMAILS="authorized@yahoo\.com|authorized@gmail\.com" +# Accounts with these emails will get global admin rights. This grants access to the admin UI. +# ADMIN_EMAILS="admin@example\.com|another-admin@example\.com" # This is used for logging in via GitHub. You can leave these commented out if you don't want to use GitHub for authentication. # AUTH_GITHUB_CLIENT_ID= # AUTH_GITHUB_CLIENT_SECRET= diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index e8d943724..ef98fc339 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -39,11 +39,25 @@ jobs: exit 1 fi echo "::set-output name=version::${IMAGE_TAG}" + - name: 🔢 Get the commit hash id: get_commit run: | echo ::set-output name=sha_short::$(echo ${{ github.sha }} | cut -c1-7) + - name: 📛 Set the tags + id: set_tags + run: | + ref_without_tag=ghcr.io/triggerdotdev/trigger.dev + image_tags=$ref_without_tag:${{ steps.get_version.outputs.version }} + + # if it's a versioned tag, also tag it as latest + if [[ "${{ github.ref_name }}" == v.docker.* ]]; then + image_tags=$image_tags,$ref_without_tag:latest + fi + + echo "IMAGE_TAGS=${image_tags}" >> "$GITHUB_OUTPUT" + - name: 🐙 Login to GitHub Container Registry uses: docker/login-action@v2 with: @@ -56,6 +70,5 @@ jobs: with: file: ./docker/Dockerfile platforms: linux/amd64,linux/arm64 - tags: | - ghcr.io/triggerdotdev/trigger.dev:${{ steps.get_version.outputs.version }} + tags: ${{ steps.set_tags.outputs.IMAGE_TAGS }} push: true diff --git a/.github/workflows/publish-infra.yml b/.github/workflows/publish-infra.yml index ec67436a6..c6d858b7d 100644 --- a/.github/workflows/publish-infra.yml +++ b/.github/workflows/publish-infra.yml @@ -1,6 +1,7 @@ name: "🚢 Publish Infra Images" on: + workflow_call: push: tags: - "infra-dev-*" @@ -29,9 +30,6 @@ permissions: packages: write contents: read -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - env: AWS_REGION: us-east-1 @@ -39,7 +37,7 @@ jobs: build: strategy: matrix: - package: [coordinator, kubernetes-provider] + package: [coordinator, docker-provider, kubernetes-provider] runs-on: buildjet-16vcpu-ubuntu-2204 env: DOCKER_BUILDKIT: "1" @@ -48,20 +46,40 @@ jobs: - name: Generate image reference id: prep - # WARNING: This step expects the workflow to have been triggered by a specific tag format of: infra-${env}-* run: | - env=$(echo ${{ github.ref_name }} | cut -d- -f2) - sha=${GITHUB_SHA::7} - ts=$(date +%s) + # set image repo if [[ "${{ matrix.package }}" == *-provider ]]; then - provider_type=$(echo ${{ matrix.package }} | cut -d- -f1) + provider_type=$(echo "${{ matrix.package }}" | cut -d- -f1) repository=provider/${provider_type} else - repository=${{ matrix.package }} + repository="${{ matrix.package }}" fi - echo "IMAGE_TAG=${env}-${sha}-${ts}" >> "$GITHUB_OUTPUT" echo "REPOSITORY=${repository}" >> "$GITHUB_OUTPUT" + # set image tag + if [[ "${{ github.ref_type }}" == "tag" ]]; then + if [[ "${{ github.ref_name }}" == infra-*-* ]]; then + env=$(echo ${{ github.ref_name }} | cut -d- -f2) + sha=$(echo ${{ github.sha }} | head -c7) + ts=$(date +%s) + image_tag=${env}-${sha}-${ts} + elif [[ "${{ github.ref_name }}" == v.docker.* ]]; then + version="${GITHUB_REF_NAME#v.docker.}" + image_tag="v${version}" + elif [[ "${{ github.ref_name }}" == build-* ]]; then + image_tag="${GITHUB_REF_NAME#build-}" + else + echo "Invalid tag: ${{ github.ref_name }}" + exit 1 + fi + elif [[ "${{ github.ref_name }}" == "main" ]]; then + image_tag="main" + else + echo "Invalid reference: ${{ github.ref }}" + exit 1 + fi + echo "IMAGE_TAG=${image_tag}" >> "$GITHUB_OUTPUT" + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -92,3 +110,12 @@ jobs: REGISTRY: ghcr.io/triggerdotdev REPOSITORY: ${{ steps.prep.outputs.REPOSITORY }} IMAGE_TAG: ${{ steps.prep.outputs.IMAGE_TAG }} + + - name: 🐙 Push 'latest' to GitHub Container Registry + if: startsWith(github.ref_name, 'v.docker.') + run: | + docker tag infra_image $REGISTRY/$REPOSITORY:latest + docker push $REGISTRY/$REPOSITORY:latest + env: + REGISTRY: ghcr.io/triggerdotdev + REPOSITORY: ${{ steps.prep.outputs.REPOSITORY }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 73d15343b..fdef9ab4a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -57,3 +57,8 @@ jobs: needs: [typecheck, units] uses: ./.github/workflows/publish-docker.yml secrets: inherit + + publish-infra: + needs: [typecheck, units] + uses: ./.github/workflows/publish-infra.yml + secrets: inherit diff --git a/apps/coordinator/Containerfile b/apps/coordinator/Containerfile index cd301811b..c42b663d2 100644 --- a/apps/coordinator/Containerfile +++ b/apps/coordinator/Containerfile @@ -1,19 +1,19 @@ # syntax=docker/dockerfile:labs -FROM node:18-bullseye-slim@sha256:a4edd54dcfdcacc8a4100fee71498e8671d99556a1acf5614539214a70092426 AS node-18 +FROM node:20-bookworm-slim@sha256:72f2f046a5f8468db28730b990b37de63ce93fd1a72a40f531d6aa82afdf0d46 AS node-20 WORKDIR /app -FROM node-18 AS pruner +FROM node-20 AS pruner COPY --chown=node:node . . RUN npx -q turbo@1.10.9 prune --scope=coordinator --docker RUN find . -name "node_modules" -type d -prune -exec rm -rf '{}' + -FROM node-18 AS base +FROM node-20 AS base RUN apt-get update \ - && apt-get install -y buildah ca-certificates dumb-init \ + && apt-get install -y buildah ca-certificates dumb-init docker.io \ && rm -rf /var/lib/apt/lists/* COPY --chown=node:node .gitignore .gitignore diff --git a/apps/coordinator/src/index.ts b/apps/coordinator/src/index.ts index 19ad2b909..30b179e7f 100644 --- a/apps/coordinator/src/index.ts +++ b/apps/coordinator/src/index.ts @@ -12,7 +12,7 @@ import { } from "@trigger.dev/core/v3"; import { ZodNamespace } from "@trigger.dev/core/v3/zodNamespace"; import { ZodSocketConnection } from "@trigger.dev/core/v3/zodSocket"; -import { HttpReply, getTextBody, SimpleLogger } from "@trigger.dev/core-apps"; +import { HttpReply, getTextBody, SimpleLogger, testDockerCheckpoint } from "@trigger.dev/core-apps"; import { ExponentialBackoff } from "./backoff"; import { collectDefaultMetrics, register, Gauge } from "prom-client"; @@ -72,7 +72,10 @@ type CheckpointAndPushOptions = { type CheckpointAndPushResult = | { success: true; checkpoint: CheckpointData } - | { success: false; reason?: "CANCELED" | "DISABLED" | "ERROR" | "IN_PROGRESS" | "NO_SUPPORT" }; + | { + success: false; + reason?: "CANCELED" | "DISABLED" | "ERROR" | "IN_PROGRESS" | "NO_SUPPORT" | "SKIP_RETRYING"; + }; type CheckpointData = { location: string; @@ -125,65 +128,53 @@ class Checkpointer { constructor(private opts = { forceSimulate: false }) {} - async initialize(): Promise { + async init(): Promise { if (this.#initialized) { - return this.#getInitializeReturn(); + return this.#getInitReturn(this.#canCheckpoint); } this.#logger.log(`${this.#dockerMode ? "Docker" : "Kubernetes"} mode`); if (this.#dockerMode) { - try { - await $`criu --version`; - } catch (error) { - this.#logger.error("No checkpoint support: Missing CRIU binary"); - this.#logger.error("Will simulate instead"); - this.#canCheckpoint = false; - this.#initialized = true; + const testCheckpoint = await testDockerCheckpoint(); - return this.#getInitializeReturn(); + if (testCheckpoint.ok) { + return this.#getInitReturn(true); } - try { - await $`docker checkpoint`; - } catch (error) { - this.#logger.error( - "No checkpoint support: Docker needs to have experimental features enabled" - ); - this.#logger.error("Will simulate instead"); - this.#canCheckpoint = false; - this.#initialized = true; - - return this.#getInitializeReturn(); - } + this.#logger.error(testCheckpoint.message, testCheckpoint.error ?? ""); + return this.#getInitReturn(false); } else { try { await $`buildah login --get-login ${REGISTRY_HOST}`; } catch (error) { this.#logger.error(`No checkpoint support: Not logged in to registry ${REGISTRY_HOST}`); - this.#canCheckpoint = false; - this.#initialized = true; - - return this.#getInitializeReturn(); + return this.#getInitReturn(false); } } - this.#logger.log( - `Full checkpoint support${ - this.#dockerMode && this.opts.forceSimulate ? " with forced simulation enabled." : "!" - }` - ); - - this.#initialized = true; - this.#canCheckpoint = true; - - return this.#getInitializeReturn(); + return this.#getInitReturn(true); } - #getInitializeReturn(): CheckpointerInitializeReturn { + #getInitReturn(canCheckpoint: boolean): CheckpointerInitializeReturn { + this.#initialized = true; + this.#canCheckpoint = canCheckpoint; + + if (canCheckpoint) { + this.#logger.log("Full checkpoint support!"); + } + + const willSimulate = this.#dockerMode && (!this.#canCheckpoint || this.opts.forceSimulate); + + if (willSimulate) { + this.#logger.log("Simulation mode enabled. Containers will be paused, not checkpointed.", { + forceSimulate: this.opts.forceSimulate, + }); + } + return { - canCheckpoint: this.#canCheckpoint, - willSimulate: this.#dockerMode && (!this.#canCheckpoint || this.opts.forceSimulate), + canCheckpoint, + willSimulate, }; } @@ -327,6 +318,11 @@ class Checkpointer { return result; } + if (result.reason === "SKIP_RETRYING") { + this.#logger.log("Skipping retrying", { runId }); + return result; + } + continue; } catch (error) { this.#logger.error("Checkpoint error", { @@ -355,7 +351,7 @@ class Checkpointer { projectRef, deploymentVersion, }: CheckpointAndPushOptions): Promise { - await this.initialize(); + await this.init(); const options = { runId, @@ -473,7 +469,8 @@ class Checkpointer { // Create checkpoint (CRI) if (!this.#canCheckpoint) { - throw new Error("No checkpoint support in kubernetes mode."); + this.#logger.error("No checkpoint support in kubernetes mode."); + return { success: false, reason: "SKIP_RETRYING" }; } const containerId = this.#logger.debug( @@ -484,7 +481,8 @@ class Checkpointer { ); if (!containerId.stdout) { - throw new Error("could not find container id"); + this.#logger.error("could not find container id", { options, containterName }); + return { success: false, reason: "SKIP_RETRYING" }; } const start = performance.now(); @@ -617,7 +615,7 @@ class TaskCoordinator { private host = "0.0.0.0" ) { this.#httpServer = this.#createHttpServer(); - this.#checkpointer.initialize(); + this.#checkpointer.init(); this.#delayThresholdInMs = this.#getDelayThreshold(); if (process.env.DELAY_THRESHOLD_IN_MS) { @@ -1034,7 +1032,7 @@ class TaskCoordinator { return; } - const { canCheckpoint, willSimulate } = await this.#checkpointer.initialize(); + const { canCheckpoint, willSimulate } = await this.#checkpointer.init(); const willCheckpointAndRestore = canCheckpoint || willSimulate; @@ -1131,7 +1129,7 @@ class TaskCoordinator { return; } - const { canCheckpoint, willSimulate } = await this.#checkpointer.initialize(); + const { canCheckpoint, willSimulate } = await this.#checkpointer.init(); const willCheckpointAndRestore = canCheckpoint || willSimulate; @@ -1185,7 +1183,7 @@ class TaskCoordinator { socket.on("WAIT_FOR_TASK", async (message, callback) => { logger.log("[WAIT_FOR_TASK]", message); - const { canCheckpoint, willSimulate } = await this.#checkpointer.initialize(); + const { canCheckpoint, willSimulate } = await this.#checkpointer.init(); const willCheckpointAndRestore = canCheckpoint || willSimulate; @@ -1227,7 +1225,7 @@ class TaskCoordinator { socket.on("WAIT_FOR_BATCH", async (message, callback) => { logger.log("[WAIT_FOR_BATCH]", message); - const { canCheckpoint, willSimulate } = await this.#checkpointer.initialize(); + const { canCheckpoint, willSimulate } = await this.#checkpointer.init(); const willCheckpointAndRestore = canCheckpoint || willSimulate; diff --git a/apps/docker-provider/Containerfile b/apps/docker-provider/Containerfile index f10d20655..bea730bda 100644 --- a/apps/docker-provider/Containerfile +++ b/apps/docker-provider/Containerfile @@ -1,16 +1,47 @@ -# syntax=docker/dockerfile:labs - -FROM node:18-slim AS base - -RUN apt-get update \ - && apt-get install -y dumb-init - -FROM base +FROM node:20-alpine@sha256:7a91aa397f2e2dfbfcdad2e2d72599f374e0b0172be1d86eeb73f1d33f36a4b2 AS node-20-alpine WORKDIR /app -COPY --chown=node dist/index.mjs /app/ +FROM node-20-alpine AS pruner + +COPY --chown=node:node . . +RUN npx -q turbo@1.10.9 prune --scope=docker-provider --docker +RUN find . -name "node_modules" -type d -prune -exec rm -rf '{}' + + +FROM node-20-alpine AS base + +RUN apk add --no-cache dumb-init docker + +COPY --chown=node:node .gitignore .gitignore +COPY --from=pruner --chown=node:node /app/out/json/ . +COPY --from=pruner --chown=node:node /app/out/pnpm-lock.yaml ./pnpm-lock.yaml +COPY --from=pruner --chown=node:node /app/out/pnpm-workspace.yaml ./pnpm-workspace.yaml + +FROM base AS dev-deps +RUN corepack enable +ENV NODE_ENV development + +RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store pnpm fetch --no-frozen-lockfile +RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store pnpm install --ignore-scripts --no-frozen-lockfile + +FROM base AS builder +RUN corepack enable + +COPY --from=pruner --chown=node:node /app/out/full/ . +COPY --from=dev-deps --chown=node:node /app/ . +COPY --chown=node:node turbo.json turbo.json + +RUN pnpm run -r --filter docker-provider build:bundle + +FROM base AS runner + +RUN corepack enable +ENV NODE_ENV production + +COPY --from=builder --chown=node:node /app/apps/docker-provider/dist/index.mjs ./index.mjs EXPOSE 8000 -ENTRYPOINT [ "/usr/bin/dumb-init", "--", "/usr/local/bin/node", "/app/index.mjs" ] +USER node + +CMD [ "/usr/bin/dumb-init", "--", "/usr/local/bin/node", "./index.mjs" ] diff --git a/apps/docker-provider/src/index.ts b/apps/docker-provider/src/index.ts index a5e588956..d339b5a93 100644 --- a/apps/docker-provider/src/index.ts +++ b/apps/docker-provider/src/index.ts @@ -6,6 +6,8 @@ import { TaskOperationsRestoreOptions, TaskOperationsCreateOptions, TaskOperationsIndexOptions, + isExecaChildProcess, + testDockerCheckpoint, } from "@trigger.dev/core-apps"; import { setTimeout } from "node:timers/promises"; import { PostStartCauses, PreStopCauses } from "@trigger.dev/core/v3"; @@ -23,70 +25,58 @@ const FORCE_CHECKPOINT_SIMULATION = ["1", "true"].includes( const logger = new SimpleLogger(`[${MACHINE_NAME}]`); -type InitializeReturn = { +type TaskOperationsInitReturn = { canCheckpoint: boolean; willSimulate: boolean; }; -function isExecaChildProcess(maybeExeca: unknown): maybeExeca is Awaited { - return typeof maybeExeca === "object" && maybeExeca !== null && "escapedCommand" in maybeExeca; -} - class DockerTaskOperations implements TaskOperations { #initialized = false; #canCheckpoint = false; constructor(private opts = { forceSimulate: false }) {} - async #initialize(): Promise { + async init(): Promise { if (this.#initialized) { - return this.#getInitializeReturn(); + return this.#getInitReturn(this.#canCheckpoint); } logger.log("Initializing task operations"); - if (this.opts.forceSimulate) { - logger.log("Forced simulation enabled. Will simulate regardless of checkpoint support."); + const testCheckpoint = await testDockerCheckpoint(); + + if (testCheckpoint.ok) { + return this.#getInitReturn(true); } - try { - await $`criu --version`; - } catch (error) { - logger.error("No checkpoint support: Missing CRIU binary. Will simulate instead."); - this.#canCheckpoint = false; - this.#initialized = true; - - return this.#getInitializeReturn(); - } - - try { - await $`docker checkpoint`; - } catch (error) { - logger.error("No checkpoint support: Docker needs to have experimental features enabled"); - logger.error("Will simulate instead"); - this.#canCheckpoint = false; - this.#initialized = true; - - return this.#getInitializeReturn(); - } - - logger.log("Full checkpoint support!"); - - this.#initialized = true; - this.#canCheckpoint = true; - - return this.#getInitializeReturn(); + logger.error(testCheckpoint.message, testCheckpoint.error); + return this.#getInitReturn(false); } - #getInitializeReturn(): InitializeReturn { + #getInitReturn(canCheckpoint: boolean): TaskOperationsInitReturn { + this.#initialized = true; + this.#canCheckpoint = canCheckpoint; + + if (canCheckpoint) { + logger.log("Full checkpoint support!"); + } + + const willSimulate = !canCheckpoint || this.opts.forceSimulate; + + if (willSimulate) { + logger.log("Simulation mode enabled. Containers will be paused, not checkpointed.", { + forceSimulate: this.opts.forceSimulate, + }); + } + return { - canCheckpoint: this.#canCheckpoint, - willSimulate: !this.#canCheckpoint || this.opts.forceSimulate, + canCheckpoint, + willSimulate, }; } async index(opts: TaskOperationsIndexOptions) { - await this.#initialize(); + await this.init(); const containerName = this.#getIndexContainerName(opts.shortCode); @@ -129,7 +119,7 @@ class DockerTaskOperations implements TaskOperations { } async create(opts: TaskOperationsCreateOptions) { - await this.#initialize(); + await this.init(); const containerName = this.#getRunContainerName(opts.runId); @@ -165,7 +155,7 @@ class DockerTaskOperations implements TaskOperations { } async restore(opts: TaskOperationsRestoreOptions) { - await this.#initialize(); + await this.init(); const containerName = this.#getRunContainerName(opts.runId); @@ -194,7 +184,7 @@ class DockerTaskOperations implements TaskOperations { } async delete(opts: { runId: string }) { - await this.#initialize(); + await this.init(); const containerName = this.#getRunContainerName(opts.runId); await this.#sendPreStop(containerName); @@ -203,7 +193,7 @@ class DockerTaskOperations implements TaskOperations { } async get(opts: { runId: string }) { - await this.#initialize(); + await this.init(); logger.log("noop: get"); } diff --git a/apps/kubernetes-provider/Containerfile b/apps/kubernetes-provider/Containerfile index f9fad85f4..fb96304c2 100644 --- a/apps/kubernetes-provider/Containerfile +++ b/apps/kubernetes-provider/Containerfile @@ -1,14 +1,14 @@ -FROM node:18-alpine@sha256:ca9f6cb0466f9638e59e0c249d335a07c867cd50c429b5c7830dda1bed584649 AS node-18-alpine +FROM node:20-alpine@sha256:7a91aa397f2e2dfbfcdad2e2d72599f374e0b0172be1d86eeb73f1d33f36a4b2 AS node-20-alpine WORKDIR /app -FROM node-18-alpine AS pruner +FROM node-20-alpine AS pruner COPY --chown=node:node . . RUN npx -q turbo@1.10.9 prune --scope=kubernetes-provider --docker RUN find . -name "node_modules" -type d -prune -exec rm -rf '{}' + -FROM node-18-alpine AS base +FROM node-20-alpine AS base RUN apk add --no-cache dumb-init diff --git a/apps/kubernetes-provider/src/index.ts b/apps/kubernetes-provider/src/index.ts index 0f177b59c..67aa0cf8b 100644 --- a/apps/kubernetes-provider/src/index.ts +++ b/apps/kubernetes-provider/src/index.ts @@ -47,6 +47,10 @@ class KubernetesTaskOperations implements TaskOperations { this.#k8sApi = this.#createK8sApi(); } + async init() { + // noop + } + async index(opts: TaskOperationsIndexOptions) { await this.#createJob( { diff --git a/apps/webapp/app/components/SetupCommands.tsx b/apps/webapp/app/components/SetupCommands.tsx index 8b3bb274c..510e58d77 100644 --- a/apps/webapp/app/components/SetupCommands.tsx +++ b/apps/webapp/app/components/SetupCommands.tsx @@ -8,6 +8,7 @@ import { } from "./primitives/ClientTabs"; import { ClipboardField } from "./primitives/ClipboardField"; import { Paragraph } from "./primitives/Paragraph"; +import { useAppOrigin } from "~/hooks/useAppOrigin"; export function InitCommand({ appOrigin, apiKey }: { appOrigin: string; apiKey: string }) { return ( @@ -133,9 +134,38 @@ export function TriggerDevStep({ extra }: { extra?: string }) { // Trigger.dev version 3 setup commands const v3PackageTag = "beta"; +function getApiUrlArg() { + const appOrigin = useAppOrigin(); + + let apiUrl: string | undefined = undefined; + + switch (appOrigin) { + case "https://cloud.trigger.dev": + // don't display the arg, use the CLI default + break; + case "https://test-cloud.trigger.dev": + apiUrl = "https://test-api.trigger.dev"; + break; + case "https://internal.trigger.dev": + apiUrl = "https://internal-api.trigger.dev"; + break; + default: + apiUrl = appOrigin; + break; + } + + return apiUrl ? `-a ${apiUrl}` : undefined; +} + export function InitCommandV3() { const project = useProject(); const projectRef = project.ref; + + const apiUrlArg = getApiUrlArg(); + + const initCommandParts = [`trigger.dev@${v3PackageTag}`, "init", `-p ${projectRef}`, apiUrlArg]; + const initCommand = initCommandParts.filter(Boolean).join(" "); + return ( @@ -148,7 +178,7 @@ export function InitCommandV3() { variant="primary/medium" iconButton className="mb-4" - value={`npx trigger.dev@${v3PackageTag} init -p ${projectRef}`} + value={`npx ${initCommand}`} /> @@ -156,7 +186,7 @@ export function InitCommandV3() { variant="primary/medium" iconButton className="mb-4" - value={`pnpm dlx trigger.dev@${v3PackageTag} init -p ${projectRef}`} + value={`pnpm dlx ${initCommand}`} /> @@ -164,7 +194,7 @@ export function InitCommandV3() { variant="primary/medium" iconButton className="mb-4" - value={`yarn dlx trigger.dev@${v3PackageTag} init -p ${projectRef}`} + value={`yarn dlx ${initCommand}`} /> diff --git a/apps/webapp/app/env.server.ts b/apps/webapp/app/env.server.ts index 315f89067..7b72710fc 100644 --- a/apps/webapp/app/env.server.ts +++ b/apps/webapp/app/env.server.ts @@ -27,15 +27,17 @@ const EnvironmentSchema = z.object({ .string() .refine(isValidRegex, "WHITELISTED_EMAILS must be a valid regex.") .optional(), + ADMIN_EMAILS: z.string().refine(isValidRegex, "ADMIN_EMAILS must be a valid regex.").optional(), REMIX_APP_PORT: z.string().optional(), LOGIN_ORIGIN: z.string().default("http://localhost:3030"), APP_ORIGIN: z.string().default("http://localhost:3030"), APP_ENV: z.string().default(process.env.NODE_ENV), SERVICE_NAME: z.string().default("trigger.dev webapp"), SECRET_STORE: SecretStoreOptionsSchema.default("DATABASE"), - POSTHOG_PROJECT_KEY: z.string().optional(), + POSTHOG_PROJECT_KEY: z.string().default("phc_LFH7kJiGhdIlnO22hTAKgHpaKhpM8gkzWAFvHmf5vfS"), TELEMETRY_TRIGGER_API_KEY: z.string().optional(), TELEMETRY_TRIGGER_API_URL: z.string().optional(), + TRIGGER_TELEMETRY_DISABLED: z.string().optional(), HIGHLIGHT_PROJECT_ID: z.string().optional(), AUTH_GITHUB_CLIENT_ID: z.string().optional(), AUTH_GITHUB_CLIENT_SECRET: z.string().optional(), diff --git a/apps/webapp/app/features.server.ts b/apps/webapp/app/features.server.ts index a5f11e79b..8acc49f98 100644 --- a/apps/webapp/app/features.server.ts +++ b/apps/webapp/app/features.server.ts @@ -7,20 +7,28 @@ export type TriggerFeatures = { alertsEnabled: boolean; }; -// If the request host is cloud.trigger.dev then we are on the managed cloud -// or if env.NODE_ENV is development -export function featuresForRequest(request: Request): TriggerFeatures { - const url = requestUrl(request); - - const isManagedCloud = - url.host === "cloud.trigger.dev" || - url.host === "test-cloud.trigger.dev" || - url.host === "internal.trigger.dev" || - process.env.CLOUD_ENV === "development"; +function isManagedCloud(host: string): boolean { + return ( + host === "cloud.trigger.dev" || + host === "test-cloud.trigger.dev" || + host === "internal.trigger.dev" || + process.env.CLOUD_ENV === "development" + ); +} +function featuresForHost(host: string): TriggerFeatures { return { - isManagedCloud, + isManagedCloud: isManagedCloud(host), v3Enabled: env.V3_ENABLED === "true", alertsEnabled: env.ALERT_FROM_EMAIL !== undefined && env.ALERT_RESEND_API_KEY !== undefined, }; } + +export function featuresForRequest(request: Request): TriggerFeatures { + const url = requestUrl(request); + return featuresForUrl(url); +} + +export function featuresForUrl(url: URL): TriggerFeatures { + return featuresForHost(url.host); +} diff --git a/apps/webapp/app/models/organization.server.ts b/apps/webapp/app/models/organization.server.ts index 814f946f3..049ba3412 100644 --- a/apps/webapp/app/models/organization.server.ts +++ b/apps/webapp/app/models/organization.server.ts @@ -8,10 +8,10 @@ import type { import { customAlphabet } from "nanoid"; import slug from "slug"; import { prisma, PrismaClientOrTransaction } from "~/db.server"; -import { createProject } from "./project.server"; import { generate } from "random-words"; import { createApiKeyForEnv, createPkApiKeyForEnv, envSlug } from "./api-key.server"; import { env } from "~/env.server"; +import { featuresForUrl } from "~/features.server"; export type { Organization }; @@ -52,6 +52,8 @@ export async function createOrganization( ); } + const features = featuresForUrl(new URL(env.APP_ORIGIN)); + const organization = await prisma.organization.create({ data: { title, @@ -64,6 +66,7 @@ export async function createOrganization( role: "ADMIN", }, }, + v3Enabled: features.v3Enabled && !features.isManagedCloud, }, include: { members: true, diff --git a/apps/webapp/app/models/user.server.ts b/apps/webapp/app/models/user.server.ts index 19d5a2ee7..df4d43ca4 100644 --- a/apps/webapp/app/models/user.server.ts +++ b/apps/webapp/app/models/user.server.ts @@ -47,12 +47,21 @@ export async function findOrCreateMagicLinkUser( }, }); + const adminEmailRegex = env.ADMIN_EMAILS ? new RegExp(env.ADMIN_EMAILS) : undefined; + const makeAdmin = adminEmailRegex ? adminEmailRegex.test(input.email) : false; + const user = await prisma.user.upsert({ where: { email: input.email, }, - update: { email: input.email }, - create: { email: input.email, authenticationMethod: "MAGIC_LINK" }, + update: { + email: input.email, + }, + create: { + email: input.email, + authenticationMethod: "MAGIC_LINK", + admin: makeAdmin, // only on create, to prevent automatically removing existing admins + }, }); return { diff --git a/apps/webapp/app/services/telemetry.server.ts b/apps/webapp/app/services/telemetry.server.ts index 341a8094a..afd4d1f75 100644 --- a/apps/webapp/app/services/telemetry.server.ts +++ b/apps/webapp/app/services/telemetry.server.ts @@ -22,6 +22,11 @@ class Telemetry { #triggerClient: TriggerClient | undefined = undefined; constructor({ postHogApiKey, trigger }: Options) { + if (env.TRIGGER_TELEMETRY_DISABLED !== undefined) { + console.log("📉 Telemetry disabled"); + return; + } + if (postHogApiKey) { this.#posthogClient = new PostHog(postHogApiKey, { host: "https://eu.posthog.com" }); } else { diff --git a/docs/images/v3/self-hosting.png b/docs/images/v3/self-hosting.png new file mode 100644 index 0000000000000000000000000000000000000000..b41724da42691d9edaa5311e0ebdbe2eb96b40c5 GIT binary patch literal 131002 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 T&zPbu@IR>wa^i{Sb?^Njv}f|M literal 0 HcmV?d00001 diff --git a/docs/v3/cli-deploy.mdx b/docs/v3/cli-deploy.mdx index d9933da59..addf9c996 100644 --- a/docs/v3/cli-deploy.mdx +++ b/docs/v3/cli-deploy.mdx @@ -68,7 +68,7 @@ Load the built image into your local docker. #### Self-hosted (builds locally) `--self-hosted` -Builds and loads the image using your local docker. Use the `--registry` option to specify the registry to push the image to when using `--self-hosted`, or just use `--push-image` to push to the default registry. +Builds and loads the image using your local docker. Use the `--registry` option to specify the registry to push the image to when using `--self-hosted`, or just use `--push` to push to the default registry. #### Registry `--registry` @@ -76,9 +76,7 @@ Builds and loads the image using your local docker. Use the `--registry` option The registry to push the image to when using --self-hosted. -#### Push image `--push-image` - - +#### Push image `--push` When using the --self-hosted flag, push the image to the default registry. (defaults to false when not using --registry) diff --git a/docs/v3/open-source-self-hosting.mdx b/docs/v3/open-source-self-hosting.mdx index 87b33a0ce..51e1142fc 100644 --- a/docs/v3/open-source-self-hosting.mdx +++ b/docs/v3/open-source-self-hosting.mdx @@ -3,4 +3,275 @@ title: "Self-hosting" description: "You can self-host Trigger.dev on your own infrastructure." --- - +## Overview + + + Self-hosting architecture + + +The self-hosting guide comes in two parts. The first part is a simple setup where you run everything on one server. In the second part, the webapp and worker components are split on two separate machines. + +You're going to need at least one Debian (or derivative) machine with Docker and Docker Compose installed. We'll also use Ngrok to expose the webapp to the internet. + +## Caveats + +The v3 worker components don't have ARM support yet. + +This guide outlines a quick way to start self-hosting Trigger.dev. Scaling, security, and reliability concerns are not fully addressed here. It's unlikely to result in a production-ready deployment on its own, but it's a good starting point. + +As self-hosted deployments tend to have unique requirements and configurations, we don't provide specific advice for scaling up or improving security and reliability. + +Should the burden ever get too much, we'd be happy to see you on [Trigger.dev cloud](https://trigger.dev/pricing) where we deal with these concerns for you. + + +- The Docker [checkpoint command](https://docs.docker.com/reference/cli/docker/checkpoint/) is an experimental feature which may not work as expected. It won't be enabled by default. Instead, the containers will stay up and their processes frozen. They won't consume CPU but they _will_ consume RAM. +- The Docker provider does not currently enforce any resource limits. This means your tasks can consume up to the total machine CPU and RAM. Having no limits may be preferable when self-hosting, but can impact the performance of other services. +- The worker components (not the tasks!) have direct access to the Docker socket. This means they can run any Docker command. To restrict access, you may want to consider using [Docker Socket Proxy](https://github.com/Tecnativa/docker-socket-proxy). +- The task containers are running with host networking. This means there is no network isolation between them and the host machine. They will be able to access any networked service on the host. +- There is currently no support for adding multiple worker machines. This would require a more elaborate provider, or possibly a switch to Docker Swarm. This is not currently planned, but you are welcome to [contribute](https://github.com/triggerdotdev/trigger.dev/blob/main/CONTRIBUTING.md). + + +## Requirements + +- 4 CPU +- 8 GB RAM +- Debian or derivative +- Optional: A separate machine for the worker components + +You will also need a way to expose the webapp to the internet. This can be done with a reverse proxy, or with a service like Ngrok. We will be using the latter in this guide. + +## Part 1: Single server + +This is the simplest setup. You run everything on one server. It's a good option if you have spare capacity on an existing machine, and have no need to independently scale worker capacity. + +### Server setup + +Some very basic steps to get started: + +1. [Install Docker](https://docs.docker.com/get-docker/) +2. [Install Docker Compose](https://docs.docker.com/compose/install/) +3. [Install Ngrok](https://ngrok.com/download) + +On a Debian server, you can install everything you need with the following commands: + +```bash +curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | \ + sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null && \ + echo "deb https://ngrok-agent.s3.amazonaws.com buster main" | \ + sudo tee /etc/apt/sources.list.d/ngrok.list + +sudo apt-get update +sudo apt-get install -y \ + docker.io \ + docker-compose \ + ngrok +``` + +### Trigger.dev setup + +1. Clone the [Trigger.dev docker repository](https://github.com/triggerdotdev/docker) and checkout the v3 branch +```bash +git clone https://github.com/triggerdotdev/docker +cd docker +git checkout v3 +``` + +2. Run the start script and follow the prompts +```bash +./start.sh # hint: you can append -d to run in detached mode +``` + +### Manual setup + +Alternatively, you can follow these manual steps after cloning the docker repo: + +1. Create the `.env` file + +```bash +cp .env.example .env +``` + +2. Generate the required secrets + +```bash +echo MAGIC_LINK_SECRET=$(openssl rand -hex 16) +echo SESSION_SECRET=$(openssl rand -hex 16) +echo ENCRYPTION_KEY=$(openssl rand -hex 16) +echo PROVIDER_SECRET=$(openssl rand -hex 32) +echo COORDINATOR_SECRET=$(openssl rand -hex 32) +``` + +3. Replace the default secrets in the `.env` file with the generated ones + +4. Run docker compose to start the services + +```bash +. lib.sh # source the helper function +docker_compose -p=trigger up +``` + +### Tunnelling + +You will need to expose the webapp to the internet. You can use Ngrok for this. If you already have a working reverse proxy setup and a domain, you can skip to the last step. + +1. Start Ngrok. You may get prompted to sign up - it's free. + +```bash +./tunnel.sh +``` + +2. Copy the domain from the output, for example: `1234-42-42-42-42.ngrok-free.app` + +3. Uncomment the `TRIGGER_PROTOCOL` and `TRIGGER_DOMAIN` lines in the `.env` file. Set it to the domain you copied. + +```bash +TRIGGER_PROTOCOL=https +TRIGGER_DOMAIN=1234-42-42-42-42.ngrok-free.app +``` + +4. Quit the start script and launch it again, or run this: + +```bash +./stop.sh && ./start.sh +``` + +### Registry setup + +If you want to deploy v3 projects, you will need access to a Docker registry. The [CLI deploy](/v3/cli-deploy) command will push the images, and then the worker machine can pull them when needed. We will use Docker Hub as an example. + +1. Sign up for a free account at [Docker Hub](https://hub.docker.com/) + +2. Edit the `.env` file and add the registry details + +```bash +DEPLOY_REGISTRY_HOST=docker.io +DEPLOY_REGISTRY_NAMESPACE= +``` + +3. Log in to Docker Hub both locally and your server. For the split setup, this will be the worker machine. You may want to create an [access token](https://hub.docker.com/settings/security) for this. + +```bash +docker login -u +``` + +4. Restart the services + +```bash +./stop.sh && ./start.sh +``` + +5. You can now deploy v3 projects using the CLI with these flags: + +```bash +trigger deploy --self-hosted --push +``` + +## Part 2: Split services + +With this setup, the webapp will run on a different machine than the worker components. This allows independent scaling of your workload capacity. + +### Webapp setup + +All steps are the same as in Part 1, except for the following: + +1. Run the start script with the `webapp` argument + +```bash +./start.sh webapp +``` + +2. Tunnelling is now _required_. Please follow the tunnelling section from above. + +### Worker setup + +1. Copy your `.env` file from the webapp to the worker machine + +```bash +# an example using scp +scp -3 root@:docker/.env root@:docker/.env +``` + +2. Run the start script with the `worker` argument + +```bash +./start.sh worker +``` + +2. Tunnelling is _not_ required for the worker components. + +## Checkpoint support + +This requires an _experimental Docker feature_. Successfully checkpointing a task today, does not mean you will be able to restore it tomorrow. Your data may be lost. You've been warned! + +Checkpointing allows you to save the state of a running container to disk and restore it later. This can be useful for +long-running tasks that need to be paused and resumed without losing state. Think fan-out and fan-in, or long waits in email campaigns. + +### Requirements + +- Debian, **NOT** a derivative like Ubuntu +- Additional storage space for the checkpointed containers + +### Setup + +Underneath the hood this uses Checkpoint and Restore in Userspace, or [CRIU](https://github.com/checkpoint-restore/criu) in short. We'll have to do a few things to get this working: + +1. Install CRIU + +```bash +sudo apt-get update +sudo apt-get install criu +``` + +2. Tweak the config so we can successfully checkpoint our workloads + +```bash +mkdir /etc/criu + +cat << EOF >/etc/criu/runc.conf +tcp-close +EOF +``` + +3. Make sure everything works + +```bash +sudo criu check +``` + +3. Enable Docker experimental features, by adding the following to `/etc/docker/daemon.json` + +```json +{ + "experimental": true +} +``` + +4. Restart the Docker daemon + +```bash +sudo systemctl restart docker +``` + +5. Uncomment `FORCE_CHECKPOINT_SIMULATION=0` in your `.env` file. Alternatively, run this: + +```bash +echo "FORCE_CHECKPOINT_SIMULATION=0" >> .env +``` + +6. Restart the services + +```bash +# if you're running everything on the same machine +./stop.sh && ./start.sh + +# if you're running the worker on a different machine +./stop.sh worker && ./start.sh worker +``` + +## Telemetry + +By default, the Trigger.dev webapp sends telemetry data to our servers. This data is used to improve the product and is not shared with third parties. If you would like to opt-out of this, you can set the `TRIGGER_TELEMETRY_DISABLED` environment variable in your `.env` file. The value doesn't matter, it just can't be empty. For example: + +```bash +TRIGGER_TELEMETRY_DISABLED=1 +``` diff --git a/packages/cli-v3/src/commands/deploy.ts b/packages/cli-v3/src/commands/deploy.ts index fced3d579..9a2102cee 100644 --- a/packages/cli-v3/src/commands/deploy.ts +++ b/packages/cli-v3/src/commands/deploy.ts @@ -107,7 +107,7 @@ export function configureDeployCommand(program: Command) { .addOption( new CommandOption( "--self-hosted", - "Build and load the image using your local Docker. Use the --registry option to specify the registry to push the image to when using --self-hosted, or just use --push-image to push to the default registry." + "Build and load the image using your local Docker. Use the --registry option to specify the registry to push the image to when using --self-hosted, or just use --push to push to the default registry." ).hideHelp() ) .addOption( diff --git a/packages/cli-v3/src/commands/init.ts b/packages/cli-v3/src/commands/init.ts index 3611b0486..16f794c32 100644 --- a/packages/cli-v3/src/commands/init.ts +++ b/packages/cli-v3/src/commands/init.ts @@ -30,6 +30,8 @@ import { logger } from "../utilities/logger"; import { cliRootPath } from "../utilities/resolveInternalFilePath"; import { login } from "./login"; import { spinner } from "../utilities/windows"; +import { CLOUD_API_URL } from "../consts"; +import * as packageJson from "../../package.json"; const InitCommandOptions = CommonCommandOptions.extend({ projectRef: z.string().optional(), @@ -53,7 +55,7 @@ export function configureInitCommand(program: Command) { .option( "-t, --tag ", "The version of the @trigger.dev/sdk package to install", - "beta" + packageJson.version ) .option("--skip-package-install", "Skip installing the @trigger.dev/sdk package") .option("--override-config", "Override the existing config file if it exists") @@ -160,7 +162,9 @@ async function _initCommand(dir: string, options: InitCommandOptions) { log.info("Next steps:"); log.info( ` 1. To start developing, run ${chalk.green( - `npx trigger.dev@${options.tag} dev` + `npx trigger.dev@${options.tag} dev${ + options.apiUrl === CLOUD_API_URL ? "" : ` -a ${options.apiUrl}` + }` )} in your project directory` ); log.info(` 2. Visit your ${projectDashboard} to view your newly created tasks.`); @@ -401,7 +405,8 @@ async function installPackages(dir: string, options: InitCommandOptions) { case "npm": { installSpinner.start(`Running npm install @trigger.dev/sdk@${options.tag}`); - await execa("npm", ["install", `@trigger.dev/sdk@${options.tag}`], { + // --save-exact: pin version, e.g. 3.0.0-beta.20 instead of ^3.0.0-beta.20 + await execa("npm", ["install", "--save-exact", `@trigger.dev/sdk@${options.tag}`], { cwd: projectDir, stdio: options.logLevel === "debug" ? "inherit" : "ignore", }); @@ -411,6 +416,7 @@ async function installPackages(dir: string, options: InitCommandOptions) { case "pnpm": { installSpinner.start(`Running pnpm add @trigger.dev/sdk@${options.tag}`); + // pins version by default await execa("pnpm", ["add", `@trigger.dev/sdk@${options.tag}`], { cwd: projectDir, stdio: options.logLevel === "debug" ? "inherit" : "ignore", @@ -421,6 +427,7 @@ async function installPackages(dir: string, options: InitCommandOptions) { case "yarn": { installSpinner.start(`Running yarn add @trigger.dev/sdk@${options.tag}`); + // pins version by default await execa("yarn", ["add", `@trigger.dev/sdk@${options.tag}`], { cwd: projectDir, stdio: options.logLevel === "debug" ? "inherit" : "ignore", diff --git a/packages/cli-v3/src/telemetry/tracing.ts b/packages/cli-v3/src/telemetry/tracing.ts index 4df9a3e3b..90364ebdd 100644 --- a/packages/cli-v3/src/telemetry/tracing.ts +++ b/packages/cli-v3/src/telemetry/tracing.ts @@ -9,9 +9,15 @@ import { SEMRESATTRS_SERVICE_NAME, SEMRESATTRS_SERVICE_VERSION, } from "@opentelemetry/semantic-conventions"; +import { logger } from "../utilities/logger"; function initializeTracing(): NodeTracerProvider | undefined { - if (process.argv.includes("--skip-telemetry") || process.env.TRIGGER_DEV_SKIP_TELEMETRY) { + if ( + process.argv.includes("--skip-telemetry") || + process.env.TRIGGER_DEV_SKIP_TELEMETRY || // only for backwards compat + process.env.TRIGGER_TELEMETRY_DISABLED + ) { + logger.debug("📉 Telemetry disabled"); return; } diff --git a/packages/core-apps/package.json b/packages/core-apps/package.json index 037500e7d..fcd278c80 100644 --- a/packages/core-apps/package.json +++ b/packages/core-apps/package.json @@ -28,10 +28,13 @@ "@trigger.dev/core": "workspace:*", "@trigger.dev/tsconfig": "workspace:*", "@types/node": "18", - "typescript": "^5.3.0", - "socket.io-client": "^4.7.4" + "socket.io-client": "^4.7.4", + "typescript": "^5.3.0" }, "engines": { "node": ">=18.0.0" + }, + "dependencies": { + "execa": "^8.0.1" } } \ No newline at end of file diff --git a/packages/core-apps/src/checkpoints.ts b/packages/core-apps/src/checkpoints.ts new file mode 100644 index 000000000..039a0bd16 --- /dev/null +++ b/packages/core-apps/src/checkpoints.ts @@ -0,0 +1,67 @@ +import { randomUUID } from "crypto"; +import { $, type ExecaChildProcess } from "execa"; + +export function isExecaChildProcess(maybeExeca: unknown): maybeExeca is Awaited { + return typeof maybeExeca === "object" && maybeExeca !== null && "escapedCommand" in maybeExeca; +} + +export type CheckpointTestResult = + | { + ok: true; + } + | { + ok: false; + message: string; + error?: unknown; + }; + +export async function testDockerCheckpoint(): Promise { + try { + // Create a dummy container + const container = + await $`docker run -d --rm --name init-dummy-${randomUUID()} docker.io/library/busybox sleep 10`; + + // Checkpoint it + await $`docker checkpoint create ${container} init-check`; + } catch (error) { + if (!isExecaChildProcess(error)) { + return { + ok: false, + message: "No checkpoint support: Unknown error.", + error, + }; + } + + if (error.stderr.includes("criu")) { + if (error.stderr.includes("executable file not found")) { + return { + ok: false, + message: "No checkpoint support: Missing CRIU binary.", + }; + } + + return { + ok: false, + message: "No checkpoint support: Unknown CRIU error.", + error, + }; + } + + if (error.stderr.includes("experimental features enabled")) { + return { + ok: false, + message: "No checkpoint support: Please enable docker experimental features.", + }; + } + + return { + ok: false, + message: "No checkpoint support: Unknown execa error.", + error, + }; + } + + return { + ok: true, + }; +} diff --git a/packages/core-apps/src/index.ts b/packages/core-apps/src/index.ts index 7f18d773e..a4efbc947 100644 --- a/packages/core-apps/src/index.ts +++ b/packages/core-apps/src/index.ts @@ -1,3 +1,4 @@ export * from "./http"; export * from "./logger"; export * from "./provider"; +export * from "./checkpoints"; diff --git a/packages/core-apps/src/provider.ts b/packages/core-apps/src/provider.ts index 159c81dbc..14ed71033 100644 --- a/packages/core-apps/src/provider.ts +++ b/packages/core-apps/src/provider.ts @@ -62,10 +62,14 @@ export interface TaskOperationsRestoreOptions { } export interface TaskOperations { + init: () => Promise; + + // CRUD index: (opts: TaskOperationsIndexOptions) => Promise; create: (opts: TaskOperationsCreateOptions) => Promise; restore: (opts: TaskOperationsRestoreOptions) => Promise; + // unimplemented delete: (...args: any[]) => Promise; get: (...args: any[]) => Promise; } @@ -303,7 +307,8 @@ export class ProviderShell implements Provider { return httpServer; } - listen() { + async listen() { this.#httpServer.listen(this.#httpPort, this.options.host ?? "0.0.0.0"); + await this.tasks.init(); } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9b8642b0e..e483fd136 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1811,6 +1811,10 @@ importers: version: 5.3.2 packages/core-apps: + dependencies: + execa: + specifier: ^8.0.1 + version: 8.0.1 devDependencies: '@trigger.dev/core': specifier: workspace:*