Skip to content

Commit 94fb532

Browse files
authored
Add RE2 supervisor (#1769)
* add new core server only export * exit after run if warm starts disabled * add supervisor
1 parent 78194e1 commit 94fb532

25 files changed

+2327
-46
lines changed

apps/coordinator/src/checkpointer.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ExponentialBackoff } from "@trigger.dev/core/v3/apps";
2-
import { testDockerCheckpoint } from "@trigger.dev/core/v3/checkpoints";
2+
import { testDockerCheckpoint } from "@trigger.dev/core/v3/serverOnly";
33
import { nanoid } from "nanoid";
44
import fs from "node:fs/promises";
55
import { ChaosMonkey } from "./chaosMonkey";

apps/supervisor/.env.example

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# This needs to match the token of the worker group you want to connect to
2+
TRIGGER_WORKER_TOKEN=
3+
4+
# This needs to match the MANAGED_WORKER_SECRET env var on the webapp
5+
MANAGED_WORKER_SECRET=managed-secret
6+
7+
# Point this at the webapp in prod
8+
TRIGGER_API_URL=http://localhost:3030
9+
10+
# Point this at the OTel collector in prod
11+
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:3030/otel
12+
# Use this on macOS
13+
# OTEL_EXPORTER_OTLP_ENDPOINT=http://host.docker.internal:3030/otel
14+
15+
# Optional settings
16+
DEBUG=1
17+
ENFORCE_MACHINE_PRESETS=1
18+
TRIGGER_DEQUEUE_INTERVAL_MS=1000

apps/supervisor/.nvmrc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
v22.12.0

apps/supervisor/README.md

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Supervisor
2+
3+
## Dev setup
4+
5+
1. Create a worker group
6+
7+
```sh
8+
api_url=http://localhost:3030
9+
wg_name=my-worker
10+
11+
# edit these
12+
admin_pat=tr_pat_...
13+
project_id=clsw6q8wz...
14+
15+
curl -sS \
16+
-X POST \
17+
"$api_url/admin/api/v1/workers" \
18+
-H "Authorization: Bearer $admin_pat" \
19+
-H "Content-Type: application/json" \
20+
-d "{
21+
\"name\": \"$wg_name\",
22+
\"makeDefault\": true,
23+
\"projectId\": \"$project_id\"
24+
}"
25+
```
26+
27+
2. Create `.env` and set the worker token
28+
29+
```sh
30+
cp .env.example .env
31+
32+
# Then edit your .env and set this to the token.plaintext value
33+
TRIGGER_WORKER_TOKEN=tr_wgt_...
34+
```
35+
36+
3. Start the supervisor
37+
38+
```sh
39+
pnpm dev
40+
```
41+
42+
4. Build CLI, then deploy a reference project
43+
44+
```sh
45+
pnpm exec trigger deploy --self-hosted
46+
47+
# The additional network flag is required on linux
48+
pnpm exec trigger deploy --self-hosted --network host
49+
```

apps/supervisor/package.json

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"name": "supervisor",
3+
"private": true,
4+
"version": "0.0.1",
5+
"main": "dist/index.js",
6+
"type": "module",
7+
"scripts": {
8+
"dev": "tsx --experimental-sqlite --require dotenv/config --watch src/index.ts",
9+
"start": "node --experimental-sqlite dist/index.js",
10+
"typecheck": "tsc --noEmit"
11+
},
12+
"dependencies": {
13+
"@kubernetes/client-node": "^1.0.0",
14+
"@trigger.dev/core": "workspace:*",
15+
"dockerode": "^4.0.3",
16+
"nanoid": "^5.0.9",
17+
"socket.io": "4.7.4",
18+
"std-env": "^3.8.0",
19+
"tinyexec": "^0.3.1",
20+
"zod": "3.23.8"
21+
},
22+
"devDependencies": {
23+
"@types/dockerode": "^3.3.33",
24+
"docker-api-ts": "^0.2.2"
25+
}
26+
}
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import * as k8s from "@kubernetes/client-node";
2+
import { assertExhaustive } from "@trigger.dev/core/utils";
3+
4+
export const RUNTIME_ENV = process.env.KUBERNETES_PORT ? "kubernetes" : "local";
5+
6+
export function createK8sApi() {
7+
const kubeConfig = getKubeConfig();
8+
9+
const api = {
10+
core: kubeConfig.makeApiClient(k8s.CoreV1Api),
11+
batch: kubeConfig.makeApiClient(k8s.BatchV1Api),
12+
apps: kubeConfig.makeApiClient(k8s.AppsV1Api),
13+
};
14+
15+
return api;
16+
}
17+
18+
export type K8sApi = ReturnType<typeof createK8sApi>;
19+
20+
function getKubeConfig() {
21+
console.log("getKubeConfig()", { RUNTIME_ENV });
22+
23+
const kubeConfig = new k8s.KubeConfig();
24+
25+
switch (RUNTIME_ENV) {
26+
case "local":
27+
kubeConfig.loadFromDefault();
28+
break;
29+
case "kubernetes":
30+
kubeConfig.loadFromCluster();
31+
break;
32+
default:
33+
assertExhaustive(RUNTIME_ENV);
34+
}
35+
36+
return kubeConfig;
37+
}
38+
39+
export { k8s };

apps/supervisor/src/env.ts

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { randomUUID } from "crypto";
2+
import { env as stdEnv } from "std-env";
3+
import { z } from "zod";
4+
import { getDockerHostDomain } from "./util.js";
5+
6+
const Env = z.object({
7+
// This will come from `status.hostIP` in k8s
8+
WORKER_HOST_IP: z.string().default(getDockerHostDomain()),
9+
TRIGGER_API_URL: z.string().url(),
10+
TRIGGER_WORKER_TOKEN: z.string(),
11+
// This will come from `spec.nodeName` in k8s
12+
TRIGGER_WORKER_INSTANCE_NAME: z.string().default(randomUUID()),
13+
MANAGED_WORKER_SECRET: z.string(),
14+
TRIGGER_WORKLOAD_API_PORT: z.coerce.number().default(8020),
15+
TRIGGER_WORKLOAD_API_PORT_EXTERNAL: z.coerce.number().default(8020),
16+
TRIGGER_WARM_START_URL: z.string().optional(),
17+
TRIGGER_CHECKPOINT_URL: z.string().optional(),
18+
TRIGGER_DEQUEUE_INTERVAL_MS: z.coerce.number().int().default(1000),
19+
20+
// Used by the workload manager, e.g docker/k8s
21+
DOCKER_NETWORK: z.string().default("host"),
22+
OTEL_EXPORTER_OTLP_ENDPOINT: z.string().url(),
23+
ENFORCE_MACHINE_PRESETS: z.coerce.boolean().default(false),
24+
25+
// Used by the resource monitor
26+
OVERRIDE_CPU_TOTAL: z.coerce.number().optional(),
27+
OVERRIDE_MEMORY_TOTAL_GB: z.coerce.number().optional(),
28+
});
29+
30+
export const env = Env.parse(stdEnv);

0 commit comments

Comments
 (0)