Run workers in a separate Docker container
We've outgrown the run-everything-on-one-machine setup. This change moves background jobs to a different Docker image in production. It also adds a `jobKey` to certain jobs so if we try to process the same cell multiple times it'll only actually run the job once.
This commit is contained in:
@@ -10,6 +10,4 @@ pnpm tsx src/promptConstructor/migrate.ts
|
|||||||
|
|
||||||
echo "Starting the server"
|
echo "Starting the server"
|
||||||
|
|
||||||
pnpm concurrently --kill-others \
|
pnpm start
|
||||||
"pnpm start" \
|
|
||||||
"pnpm tsx src/server/tasks/worker.ts"
|
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ export const env = createEnv({
|
|||||||
SMTP_PORT: z.string().default("placeholder"),
|
SMTP_PORT: z.string().default("placeholder"),
|
||||||
SMTP_LOGIN: z.string().default("placeholder"),
|
SMTP_LOGIN: z.string().default("placeholder"),
|
||||||
SMTP_PASSWORD: z.string().default("placeholder"),
|
SMTP_PASSWORD: z.string().default("placeholder"),
|
||||||
|
WORKER_CONCURRENCY: z
|
||||||
|
.string()
|
||||||
|
.default("10")
|
||||||
|
.transform((val) => parseInt(val)),
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -68,6 +72,7 @@ export const env = createEnv({
|
|||||||
SMTP_PORT: process.env.SMTP_PORT,
|
SMTP_PORT: process.env.SMTP_PORT,
|
||||||
SMTP_LOGIN: process.env.SMTP_LOGIN,
|
SMTP_LOGIN: process.env.SMTP_LOGIN,
|
||||||
SMTP_PASSWORD: process.env.SMTP_PASSWORD,
|
SMTP_PASSWORD: process.env.SMTP_PASSWORD,
|
||||||
|
WORKER_CONCURRENCY: process.env.WORKER_CONCURRENCY,
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation.
|
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { type Helpers, type Task, makeWorkerUtils } from "graphile-worker";
|
import { type Helpers, type Task, makeWorkerUtils, TaskSpec } from "graphile-worker";
|
||||||
import { env } from "~/env.mjs";
|
import { env } from "~/env.mjs";
|
||||||
|
|
||||||
let workerUtilsPromise: ReturnType<typeof makeWorkerUtils> | null = null;
|
let workerUtilsPromise: ReturnType<typeof makeWorkerUtils> | null = null;
|
||||||
@@ -16,9 +16,11 @@ function defineTask<TPayload>(
|
|||||||
taskIdentifier: string,
|
taskIdentifier: string,
|
||||||
taskHandler: (payload: TPayload, helpers: Helpers) => Promise<void>,
|
taskHandler: (payload: TPayload, helpers: Helpers) => Promise<void>,
|
||||||
) {
|
) {
|
||||||
const enqueue = async (payload: TPayload, runAt?: Date) => {
|
const enqueue = async (payload: TPayload, spec?: TaskSpec) => {
|
||||||
console.log("Enqueuing task", taskIdentifier, payload);
|
console.log("Enqueuing task", taskIdentifier, payload);
|
||||||
await (await workerUtils()).addJob(taskIdentifier, payload, { runAt });
|
|
||||||
|
const utils = await workerUtils();
|
||||||
|
return await utils.addJob(taskIdentifier, payload, spec);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handler = (payload: TPayload, helpers: Helpers) => {
|
const handler = (payload: TPayload, helpers: Helpers) => {
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ export const queryModel = defineTask<QueryModelJob>("queryModel", async (task) =
|
|||||||
stream,
|
stream,
|
||||||
numPreviousTries: numPreviousTries + 1,
|
numPreviousTries: numPreviousTries + 1,
|
||||||
},
|
},
|
||||||
retryTime,
|
{ runAt: retryTime, jobKey: cellId },
|
||||||
);
|
);
|
||||||
await prisma.scenarioVariantCell.update({
|
await prisma.scenarioVariantCell.update({
|
||||||
where: { id: cellId },
|
where: { id: cellId },
|
||||||
@@ -184,6 +184,6 @@ export const queueQueryModel = async (cellId: string, stream: boolean) => {
|
|||||||
jobQueuedAt: new Date(),
|
jobQueuedAt: new Date(),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
queryModel.enqueue({ cellId, stream, numPreviousTries: 0 }),
|
queryModel.enqueue({ cellId, stream, numPreviousTries: 0 }, { jobKey: cellId }),
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const taskList = registeredTasks.reduce((acc, task) => {
|
|||||||
// Run a worker to execute jobs:
|
// Run a worker to execute jobs:
|
||||||
const runner = await run({
|
const runner = await run({
|
||||||
connectionString: env.DATABASE_URL,
|
connectionString: env.DATABASE_URL,
|
||||||
concurrency: 10,
|
concurrency: env.WORKER_CONCURRENCY,
|
||||||
// Install signal handlers for graceful shutdown on SIGINT, SIGTERM, etc
|
// Install signal handlers for graceful shutdown on SIGINT, SIGTERM, etc
|
||||||
noHandleSignals: false,
|
noHandleSignals: false,
|
||||||
pollInterval: 1000,
|
pollInterval: 1000,
|
||||||
|
|||||||
14
render.yaml
14
render.yaml
@@ -7,7 +7,7 @@ databases:
|
|||||||
services:
|
services:
|
||||||
- type: web
|
- type: web
|
||||||
name: querykey-prod-web
|
name: querykey-prod-web
|
||||||
env: docker
|
runtime: docker
|
||||||
dockerfilePath: ./app/Dockerfile
|
dockerfilePath: ./app/Dockerfile
|
||||||
dockerContext: .
|
dockerContext: .
|
||||||
plan: standard
|
plan: standard
|
||||||
@@ -21,8 +21,6 @@ services:
|
|||||||
name: querykey-prod
|
name: querykey-prod
|
||||||
property: connectionString
|
property: connectionString
|
||||||
- fromGroup: querykey-prod
|
- fromGroup: querykey-prod
|
||||||
- key: NEXT_PUBLIC_SOCKET_URL
|
|
||||||
value: https://querykey-prod-wss.onrender.com
|
|
||||||
# Render support says we need to manually set this because otherwise
|
# Render support says we need to manually set this because otherwise
|
||||||
# sometimes it checks a different random port that NextJS opens for
|
# sometimes it checks a different random port that NextJS opens for
|
||||||
# liveness and the liveness check fails.
|
# liveness and the liveness check fails.
|
||||||
@@ -31,8 +29,16 @@ services:
|
|||||||
|
|
||||||
- type: web
|
- type: web
|
||||||
name: querykey-prod-wss
|
name: querykey-prod-wss
|
||||||
env: docker
|
runtime: docker
|
||||||
dockerfilePath: ./app/Dockerfile
|
dockerfilePath: ./app/Dockerfile
|
||||||
dockerContext: .
|
dockerContext: .
|
||||||
plan: free
|
plan: free
|
||||||
dockerCommand: pnpm tsx src/wss-server.ts
|
dockerCommand: pnpm tsx src/wss-server.ts
|
||||||
|
|
||||||
|
- type: worker
|
||||||
|
name: querykey-prod-worker
|
||||||
|
runtime: docker
|
||||||
|
dockerfilePath: ./app/Dockerfile
|
||||||
|
dockerContext: .
|
||||||
|
plan: starter
|
||||||
|
dockerCommand: pnpm tsx src/server/tasks/worker.ts
|
||||||
|
|||||||
Reference in New Issue
Block a user