From 32dd68f76efb0aa490f86c695ab175f58b145f85 Mon Sep 17 00:00:00 2001 From: nicktrn <55853254+nicktrn@users.noreply.github.com> Date: Fri, 10 May 2024 17:10:57 +0100 Subject: [PATCH 1/3] migrate to graphile worker v0.16.6 --- apps/webapp/app/entry.server.tsx | 7 + apps/webapp/app/platform/zodWorker.server.ts | 81 ++++++-- .../db/graphileMigrationHelper.server.ts | 95 +++++++++ apps/webapp/app/services/worker.server.ts | 12 +- apps/webapp/package.json | 2 +- pnpm-lock.yaml | 192 ++++++++++++------ 6 files changed, 301 insertions(+), 88 deletions(-) create mode 100644 apps/webapp/app/services/db/graphileMigrationHelper.server.ts diff --git a/apps/webapp/app/entry.server.tsx b/apps/webapp/app/entry.server.tsx index 7893f01ab2..d1219ca587 100644 --- a/apps/webapp/app/entry.server.tsx +++ b/apps/webapp/app/entry.server.tsx @@ -174,6 +174,13 @@ Worker.init().catch((error) => { function logError(error: unknown, request?: Request) { console.error(error); + + if (error instanceof Error && error.message.startsWith("There are locked jobs present")) { + console.log("⚠️ graphile-worker migration issue detected!"); + console.log( + "⚠️ see: https://trigger.dev/docs/documentation/guides/self-hosting/graphile-migration" + ); + } } const sqsEventConsumer = singleton("sqsEventConsumer", getSharedSqsEventConsumer); diff --git a/apps/webapp/app/platform/zodWorker.server.ts b/apps/webapp/app/platform/zodWorker.server.ts index 6c94d41873..d8b35ef3da 100644 --- a/apps/webapp/app/platform/zodWorker.server.ts +++ b/apps/webapp/app/platform/zodWorker.server.ts @@ -1,20 +1,21 @@ import type { CronItem, CronItemOptions, - Job as GraphileJob, + DbJob as GraphileJob, Runner as GraphileRunner, JobHelpers, RunnerOptions, Task, TaskList, TaskSpec, + WorkerUtils, } from "graphile-worker"; -import { run as graphileRun, parseCronItems } from "graphile-worker"; +import { run as graphileRun, makeWorkerUtils, parseCronItems } from "graphile-worker"; import { SpanKind, trace } from "@opentelemetry/api"; import omit from "lodash.omit"; import { z } from "zod"; -import { PrismaClient, PrismaClientOrTransaction } from "~/db.server"; +import { $replica, PrismaClient, PrismaClientOrTransaction } from "~/db.server"; import { PgListenService } from "~/services/db/pgListen.server"; import { workerLogger as logger } from "~/services/logger.server"; import { flattenAttributes } from "@trigger.dev/core/v3"; @@ -34,8 +35,8 @@ const RawCronPayloadSchema = z.object({ const GraphileJobSchema = z.object({ id: z.coerce.string(), - queue_name: z.string().nullable(), - task_identifier: z.string(), + job_queue_id: z.number().nullable(), + task_id: z.number(), payload: z.unknown(), priority: z.number(), run_at: z.coerce.date(), @@ -72,7 +73,7 @@ type RecurringTaskPayload = { export type ZodRecurringTasks = { [key: string]: { - pattern: string; + match: string; options?: CronItemOptions; handler: (payload: RecurringTaskPayload, job: GraphileJob) => Promise; }; @@ -129,6 +130,7 @@ export class ZodWorker { #rateLimiter?: ZodWorkerRateLimiter; #shutdownTimeoutInMs?: number; #shuttingDown = false; + #workerUtils?: WorkerUtils; constructor(options: ZodWorkerOptions) { this.#name = options.name; @@ -158,6 +160,8 @@ export class ZodWorker { const parsedCronItems = parseCronItems(this.#createCronItemsFromRecurringTasks()); + this.#workerUtils = await makeWorkerUtils(this.#runnerOptions); + this.#runner = await graphileRun({ ...this.#runnerOptions, noHandleSignals: true, @@ -188,7 +192,7 @@ export class ZodWorker { this.#logDebug("Detected incoming migration", { latestMigration }); if (latestMigration > 10) { - // already migrated past v0.14 - nothing to do + this.#logDebug("Already migrated past v0.14 - nothing to do", { latestMigration }); return; } @@ -263,6 +267,7 @@ export class ZodWorker { public async stop() { await this.#runner?.stop(); + await this.#workerUtils?.release(); } public async enqueue( @@ -442,12 +447,29 @@ export class ZodWorker { return taskList; } + async #getQueueName(queueId: number | null) { + if (queueId === null) { + return; + } + + const schema = z.array(z.object({ queue_name: z.string() })); + + const rawQueueNameResults = await $replica.$queryRawUnsafe( + `SELECT queue_name FROM ${this.graphileWorkerSchema}._private_job_queues WHERE id = $1`, + queueId + ); + + const queueNameResults = schema.parse(rawQueueNameResults); + + return queueNameResults[0]?.queue_name; + } + async #rescheduleTask(payload: unknown, helpers: JobHelpers) { this.#logDebug("Rescheduling task", { payload, job: helpers.job }); await this.enqueue(helpers.job.task_identifier, payload, { runAt: helpers.job.run_at, - queueName: helpers.job.queue_name ?? undefined, + queueName: await this.#getQueueName(helpers.job.job_queue_id), priority: helpers.job.priority, jobKey: helpers.job.key ?? undefined, flags: Object.keys(helpers.job.flags ?? []), @@ -460,7 +482,7 @@ export class ZodWorker { if (this.#cleanup) { cronItems.push({ - pattern: this.#cleanup.frequencyExpression, + match: this.#cleanup.frequencyExpression, identifier: CLEANUP_TASK_NAME, task: CLEANUP_TASK_NAME, options: this.#cleanup.taskOptions, @@ -469,7 +491,7 @@ export class ZodWorker { if (this.#reporter) { cronItems.push({ - pattern: "50 * * * *", // Every hour at 50 minutes past the hour + match: "50 * * * *", // Every hour at 50 minutes past the hour identifier: REPORTER_TASK_NAME, task: REPORTER_TASK_NAME, }); @@ -481,7 +503,7 @@ export class ZodWorker { for (const [key, task] of Object.entries(this.#recurringTasks)) { const cronItem: CronItem = { - pattern: task.pattern, + match: task.match, identifier: key, task: key, options: task.options, @@ -529,7 +551,7 @@ export class ZodWorker { attributes: { "job.task_identifier": job.task_identifier, "job.id": job.id, - ...(job.queue_name ? { "job.queue_name": job.queue_name } : {}), + ...(job.job_queue_id ? { "job.queue_id": job.job_queue_id } : {}), ...flattenAttributes(job.payload as Record, "job.payload"), "job.priority": job.priority, "job.run_at": job.run_at.toISOString(), @@ -599,7 +621,7 @@ export class ZodWorker { attributes: { "job.task_identifier": job.task_identifier, "job.id": job.id, - ...(job.queue_name ? { "job.queue_name": job.queue_name } : {}), + ...(job.job_queue_id ? { "job.queue_id": job.job_queue_id } : {}), ...flattenAttributes(job.payload as Record, "job.payload"), "job.priority": job.priority, "job.run_at": job.run_at.toISOString(), @@ -638,6 +660,10 @@ export class ZodWorker { return; } + if (!this.#workerUtils) { + throw new Error("WorkerUtils need to be initialized before running job cleanup."); + } + const job = helpers.job; logger.debug("Received cleanup task", { @@ -663,23 +689,38 @@ export class ZodWorker { payload, }); - const rawResults = await this.#prisma.$queryRawUnsafe( - `WITH rows AS (SELECT id FROM ${this.graphileWorkerSchema}.jobs WHERE run_at < $1 AND locked_at IS NULL AND max_attempts = attempts LIMIT $2 FOR UPDATE) DELETE FROM ${this.graphileWorkerSchema}.jobs WHERE id IN (SELECT id FROM rows) RETURNING id`, + const rawResults = await $replica.$queryRawUnsafe( + `SELECT id + FROM ${this.graphileWorkerSchema}.jobs + WHERE run_at > $1 + AND locked_at IS NULL + AND max_attempts = attempts + LIMIT $2`, expirationDate, this.#cleanup.maxCount ); - const results = Array.isArray(rawResults) ? rawResults : []; + const results = z + .array( + z.object({ + id: z.coerce.string(), + }) + ) + .parse(rawResults); + + const completedJobs = await this.#workerUtils.completeJobs(results.map((job) => job.id)); logger.debug("Cleaned up old jobs", { - count: results.length, + found: results.length, + deleted: completedJobs.length, expirationDate, payload, }); if (this.#reporter) { await this.#reporter("cleanup_stats", { - count: results.length, + found: results.length, + deleted: completedJobs.length, expirationDate, ts: payload._cron.ts, }); @@ -711,7 +752,7 @@ export class ZodWorker { const schema = z.array(z.object({ count: z.coerce.number() })); // Count the number of jobs that have been added since the startAt date and before the payload._cron.ts date - const rawAddedResults = await this.#prisma.$queryRawUnsafe( + const rawAddedResults = await $replica.$queryRawUnsafe( `SELECT COUNT(*) FROM ${this.graphileWorkerSchema}.jobs WHERE created_at > $1 AND created_at < $2`, startAt, payload._cron.ts @@ -720,7 +761,7 @@ export class ZodWorker { const addedCountResults = schema.parse(rawAddedResults)[0]; // Count the total number of jobs in the jobs table - const rawTotalResults = await this.#prisma.$queryRawUnsafe( + const rawTotalResults = await $replica.$queryRawUnsafe( `SELECT COUNT(*) FROM ${this.graphileWorkerSchema}.jobs` ); diff --git a/apps/webapp/app/services/db/graphileMigrationHelper.server.ts b/apps/webapp/app/services/db/graphileMigrationHelper.server.ts new file mode 100644 index 0000000000..0fe54df864 --- /dev/null +++ b/apps/webapp/app/services/db/graphileMigrationHelper.server.ts @@ -0,0 +1,95 @@ +import { runMigrations } from "graphile-worker"; +import { PrismaClient, prisma } from "~/db.server"; +import { env } from "~/env.server"; +import { logger } from "~/services/logger.server"; +import { PgNotifyService } from "./pgNotify.server"; +import { z } from "zod"; + +export class GraphileMigrationHelperService { + #prismaClient: PrismaClient; + + constructor(prismaClient: PrismaClient = prisma) { + this.#prismaClient = prismaClient; + } + + public async call() { + this.#logDebug("GraphileMigrationHelperService.call"); + + await this.#detectAndPrepareForMigrations(); + + await runMigrations({ + connectionString: env.DATABASE_URL, + schema: env.WORKER_SCHEMA, + }); + } + + #logDebug(message: string, args?: any) { + logger.debug(`[migrationHelper] ${message}`, args); + } + + async #getLatestMigration() { + const migrationQueryResult = await this.#prismaClient.$queryRawUnsafe(` + SELECT id FROM ${env.WORKER_SCHEMA}.migrations + ORDER BY id DESC LIMIT 1 + `); + + const MigrationQueryResultSchema = z.array(z.object({ id: z.number() })); + + const migrationResults = MigrationQueryResultSchema.parse(migrationQueryResult); + + if (!migrationResults.length) { + // no migrations applied yet + return -1; + } + + return migrationResults[0].id; + } + + async #graphileSchemaExists() { + const schemaCount = await this.#prismaClient.$executeRaw` + SELECT schema_name FROM information_schema.schemata + WHERE schema_name = ${env.WORKER_SCHEMA} + `; + + return schemaCount === 1; + } + + /** Helper for graphile-worker v0.14.0 migration. No-op if already migrated. */ + async #detectAndPrepareForMigrations() { + if (!(await this.#graphileSchemaExists())) { + // no schema yet, likely first start + return; + } + + const latestMigration = await this.#getLatestMigration(); + + if (latestMigration < 0) { + // no migrations found + return; + } + + // the first v0.14.0 migration has ID 11 + if (latestMigration > 10) { + // already migrated + return; + } + + // add 15s to graceful shutdown timeout, just to be safe + const migrationDelayInMs = env.GRACEFUL_SHUTDOWN_TIMEOUT + 15000; + + this.#logDebug("Delaying worker startup due to pending migration", { + latestMigration, + migrationDelayInMs, + }); + + console.log(`⚠️ detected pending graphile migration`); + console.log(`⚠️ notifying running workers`); + + const pgNotify = new PgNotifyService(); + await pgNotify.call("trigger:graphile:migrate", { latestMigration }); + + console.log(`⚠️ delaying worker startup by ${migrationDelayInMs}ms`); + + await new Promise((resolve) => setTimeout(resolve, migrationDelayInMs)); + } +} diff --git a/apps/webapp/app/services/worker.server.ts b/apps/webapp/app/services/worker.server.ts index d7952a5a22..1137533c05 100644 --- a/apps/webapp/app/services/worker.server.ts +++ b/apps/webapp/app/services/worker.server.ts @@ -40,6 +40,7 @@ import { TriggerScheduledTaskService } from "~/v3/services/triggerScheduledTask. import { PerformTaskAttemptAlertsService } from "~/v3/services/alerts/performTaskAttemptAlerts.server"; import { DeliverAlertService } from "~/v3/services/alerts/deliverAlert.server"; import { PerformDeploymentAlertsService } from "~/v3/services/alerts/performDeploymentAlerts.server"; +import { GraphileMigrationHelperService } from "./db/graphileMigrationHelper.server"; const workerCatalog = { indexEndpoint: z.object({ @@ -211,9 +212,8 @@ if (env.NODE_ENV === "production") { } export async function init() { - // const pgNotify = new PgNotifyService(); - // await pgNotify.call("trigger:graphile:migrate", { latestMigration: 10 }); - // await new Promise((resolve) => setTimeout(resolve, 10000)) + const migrationHelper = new GraphileMigrationHelperService(); + await migrationHelper.call(); if (env.WORKER_ENABLED === "true") { await workerQueue.initialize(); @@ -250,7 +250,7 @@ function getWorkerQueue() { recurringTasks: { // Run this every 5 minutes autoIndexProductionEndpoints: { - pattern: "*/5 * * * *", + match: "*/5 * * * *", handler: async (payload, job) => { const service = new RecurringEndpointIndexService(); @@ -259,7 +259,7 @@ function getWorkerQueue() { }, // Run this every hour purgeOldIndexings: { - pattern: "0 * * * *", + match: "0 * * * *", handler: async (payload, job) => { // Delete indexings that are older than 7 days await prisma.endpointIndex.deleteMany({ @@ -273,7 +273,7 @@ function getWorkerQueue() { }, // Run this every hour at the 13 minute mark purgeOldTaskEvents: { - pattern: "47 * * * *", + match: "47 * * * *", handler: async (payload, job) => { await eventRepository.truncateEvents(); }, diff --git a/apps/webapp/package.json b/apps/webapp/package.json index fb7cc4bc7e..5e335b8f38 100644 --- a/apps/webapp/package.json +++ b/apps/webapp/package.json @@ -116,7 +116,7 @@ "evt": "^2.4.13", "express": "^4.18.1", "framer-motion": "^10.12.11", - "graphile-worker": "^0.13.0", + "graphile-worker": "0.16.6", "highlight.run": "^7.3.4", "humanize-duration": "^3.27.3", "intl-parse-accept-language": "^1.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d92578b448..5e9777ab64 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -460,8 +460,8 @@ importers: specifier: ^10.12.11 version: 10.12.11(react-dom@18.2.0)(react@18.2.0) graphile-worker: - specifier: ^0.13.0 - version: 0.13.0 + specifier: 0.16.6 + version: 0.16.6(typescript@5.2.2) highlight.run: specifier: ^7.3.4 version: 7.3.4 @@ -8363,7 +8363,7 @@ packages: tsconfig-paths: 4.2.0 tsconfig-paths-webpack-plugin: 4.1.0 typescript: 5.2.2 - webpack: 5.88.2 + webpack: 5.88.2(@swc/core@1.3.101)(esbuild@0.19.11) webpack-node-externals: 3.0.0 transitivePeerDependencies: - esbuild @@ -15084,10 +15084,16 @@ packages: resolution: {integrity: sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g==} dev: false + /@types/debug@4.1.12: + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + dependencies: + '@types/ms': 0.7.31 + /@types/debug@4.1.7: resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==} dependencies: '@types/ms': 0.7.31 + dev: true /@types/degit@2.8.3: resolution: {integrity: sha512-CL7y71j2zaDmtPLD5Xq5S1Gv2dFoHl0/GBZm6s39Mj/ls28L3NzAOqf7H4H0/2TNVMgMjMVf9CAFYSjmXhi3bw==} @@ -15097,7 +15103,7 @@ packages: resolution: {integrity: sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==} dependencies: '@types/eslint': 8.4.10 - '@types/estree': 1.0.2 + '@types/estree': 1.0.5 /@types/eslint@8.4.10: resolution: {integrity: sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==} @@ -15125,7 +15131,6 @@ packages: /@types/estree@1.0.5: resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} - dev: true /@types/express-serve-static-core@4.17.32: resolution: {integrity: sha512-aI5h/VOkxOF2Z1saPy0Zsxs5avets/iaiAJYznQFm5By/pamU31xWKL//epiF4OfUA2qTOc9PV6tCUjhO8wlZA==} @@ -15199,6 +15204,12 @@ packages: rxjs: 7.8.0 dev: true + /@types/interpret@1.1.3: + resolution: {integrity: sha512-uBaBhj/BhilG58r64mtDb/BEdH51HIQLgP5bmWzc5qCtFMja8dCk/IOJmk36j0lbi9QHwI6sbtUNGuqXdKCAtQ==} + dependencies: + '@types/node': 18.19.20 + dev: false + /@types/is-ci@3.0.0: resolution: {integrity: sha512-Q0Op0hdWbYd1iahB+IFNQcWXFq4O0Q5MwQP7uN0souuQ4rPg1vEYcnIOfr1gY+M+6rc8FGoRaBO1mOOvL29sEQ==} dependencies: @@ -15430,10 +15441,19 @@ packages: /@types/parse-json@4.0.0: resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==} + dev: true /@types/parse5@6.0.3: resolution: {integrity: sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==} + /@types/pg@8.11.6: + resolution: {integrity: sha512-/2WmmBXHLsfRqzfHW7BNZ8SbYzE8OSk7i3WjFYvfgRHj7S1xj+16Je5fUKv3lVdVzk/zn9TXOqf+avFCFIE0yQ==} + dependencies: + '@types/node': 18.19.20 + pg-protocol: 1.6.1 + pg-types: 4.0.2 + dev: false + /@types/pg@8.6.6: resolution: {integrity: sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==} dependencies: @@ -15629,7 +15649,7 @@ packages: dependencies: '@types/node': 18.19.20 tapable: 2.2.1 - webpack: 5.88.2 + webpack: 5.88.2(@swc/core@1.3.101)(esbuild@0.19.11) transitivePeerDependencies: - '@swc/core' - esbuild @@ -17874,11 +17894,6 @@ packages: engines: {node: '>=0.10'} dev: false - /buffer-writer@2.0.0: - resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==} - engines: {node: '>=4'} - dev: false - /buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} dependencies: @@ -18777,6 +18792,7 @@ packages: parse-json: 5.2.0 path-type: 4.0.0 yaml: 1.10.2 + dev: true /cosmiconfig@8.1.3: resolution: {integrity: sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==} @@ -18788,6 +18804,22 @@ packages: path-type: 4.0.0 dev: true + /cosmiconfig@8.3.6(typescript@5.2.2): + resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + path-type: 4.0.0 + typescript: 5.2.2 + dev: false + /cosmiconfig@9.0.0(typescript@5.2.2): resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} engines: {node: '>=14'} @@ -22247,7 +22279,7 @@ packages: semver: 7.5.4 tapable: 2.2.1 typescript: 5.2.2 - webpack: 5.88.2 + webpack: 5.88.2(@swc/core@1.3.101)(esbuild@0.19.11) dev: true /form-data-encoder@1.7.2: @@ -22875,7 +22907,6 @@ packages: /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - dev: false /gradient-string@2.0.2: resolution: {integrity: sha512-rEDCuqUQ4tbD78TpzsMtt5OIf0cBCSDWSJtUDaF6JsAh+k0v9r++NzxNEG87oDZx9ZwGhD8DaezR2L/yrw0Jdw==} @@ -22891,22 +22922,41 @@ packages: /graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - /graphile-worker@0.13.0: - resolution: {integrity: sha512-8Hl5XV6hkabZRhYzvbUfvjJfPFR5EPxYRVWlzQC2rqYHrjULTLBgBYZna5R9ukbnsbWSvn4vVrzOBIOgIC1jjw==} - engines: {node: '>=10.0.0'} + /graphile-config@0.0.1-beta.8: + resolution: {integrity: sha512-H8MinryZewvUigVLnkVDhKJgHrcNYGcLvgYWfSnR1d6l76iV9E8m4ZfN9estSHKVm6cyHhRfHBfL1G5QfXmS5A==} + engines: {node: '>=16'} + dependencies: + '@types/interpret': 1.1.3 + '@types/node': 20.12.7 + '@types/semver': 7.5.1 + chalk: 4.1.2 + debug: 4.3.4(supports-color@8.1.1) + interpret: 3.1.1 + semver: 7.5.4 + tslib: 2.6.2 + yargs: 17.7.2 + transitivePeerDependencies: + - supports-color + dev: false + + /graphile-worker@0.16.6(typescript@5.2.2): + resolution: {integrity: sha512-e7gGYDmGqzju2l83MpzX8vNG/lOtVJiSzI3eZpAFubSxh/cxs7sRrRGBGjzBP1kNG0H+c95etPpNRNlH65PYhw==} + engines: {node: '>=14.0.0'} hasBin: true dependencies: '@graphile/logger': 0.2.0 - '@types/debug': 4.1.7 - '@types/pg': 8.6.6 - chokidar: 3.5.3 - cosmiconfig: 7.1.0 + '@types/debug': 4.1.12 + '@types/pg': 8.11.6 + cosmiconfig: 8.3.6(typescript@5.2.2) + graphile-config: 0.0.1-beta.8 json5: 2.2.3 - pg: 8.10.0 - tslib: 2.4.1 - yargs: 16.2.0 + pg: 8.11.5 + tslib: 2.6.2 + yargs: 17.7.2 transitivePeerDependencies: - pg-native + - supports-color + - typescript dev: false /graphql@15.8.0: @@ -23641,6 +23691,11 @@ packages: resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} engines: {node: '>= 0.10'} + /interpret@3.1.1: + resolution: {integrity: sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==} + engines: {node: '>=10.13.0'} + dev: false + /intl-messageformat@10.5.8: resolution: {integrity: sha512-NRf0jpBWV0vd671G5b06wNofAN8tp7WWDogMZyaU8GUAsmbouyvgwmFJI7zLjfAMpm3zK+vSwRP3jzaoIcMbaA==} dependencies: @@ -25058,14 +25113,14 @@ packages: /jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} optionalDependencies: - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 /jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} dependencies: universalify: 2.0.0 optionalDependencies: - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 dev: true /jsonlines@0.1.1: @@ -26227,7 +26282,7 @@ packages: /micromark@3.1.0: resolution: {integrity: sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA==} dependencies: - '@types/debug': 4.1.7 + '@types/debug': 4.1.12 debug: 4.3.4(supports-color@8.1.1) decode-named-character-reference: 1.0.2 micromark-core-commonmark: 1.0.6 @@ -27532,6 +27587,10 @@ packages: resolution: {integrity: sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==} dev: false + /obuf@1.1.2: + resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + dev: false + /octokit@3.1.2: resolution: {integrity: sha512-MG5qmrTL5y8KYwFgE1A4JWmgfQBaIETE/lOlfwNYx1QOtCQHGVxkRJmdUJltFc1HVn73d61TlMhMyNTOtMl+ng==} engines: {node: '>= 18'} @@ -28034,10 +28093,6 @@ packages: semver: 7.5.4 dev: false - /packet-reader@1.0.0: - resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==} - dev: false - /pacote@15.2.0: resolution: {integrity: sha512-rJVZeIwHTUta23sIZgEIM62WYwbmGbThdbnkt81ravBplQv+HjyroqnLRNH2+sLJHcGZmLRmhPwACqhfTcOmnA==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -28278,10 +28333,6 @@ packages: dev: false optional: true - /pg-connection-string@2.5.0: - resolution: {integrity: sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==} - dev: false - /pg-connection-string@2.6.4: resolution: {integrity: sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==} dev: false @@ -28291,12 +28342,9 @@ packages: engines: {node: '>=4.0.0'} dev: false - /pg-pool@3.6.0(pg@8.10.0): - resolution: {integrity: sha512-clFRf2ksqd+F497kWFyM21tMjeikn60oGDmqMT8UBrynEwVEX/5R5xd2sdvdo1cZCFlguORNpVuqxIj+aK4cfQ==} - peerDependencies: - pg: '>=8.0' - dependencies: - pg: 8.10.0 + /pg-numeric@1.0.2: + resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} + engines: {node: '>=4'} dev: false /pg-pool@3.6.2(pg@8.11.5): @@ -28326,22 +28374,17 @@ packages: postgres-interval: 1.2.0 dev: false - /pg@8.10.0: - resolution: {integrity: sha512-ke7o7qSTMb47iwzOSaZMfeR7xToFdkE71ifIipOAAaLIM0DYzfOAXlgFFmYUIE2BcJtvnVlGCID84ZzCegE8CQ==} - engines: {node: '>= 8.0.0'} - peerDependencies: - pg-native: '>=3.0.1' - peerDependenciesMeta: - pg-native: - optional: true + /pg-types@4.0.2: + resolution: {integrity: sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==} + engines: {node: '>=10'} dependencies: - buffer-writer: 2.0.0 - packet-reader: 1.0.0 - pg-connection-string: 2.5.0 - pg-pool: 3.6.0(pg@8.10.0) - pg-protocol: 1.6.0 - pg-types: 2.2.0 - pgpass: 1.0.5 + pg-int8: 1.0.1 + pg-numeric: 1.0.2 + postgres-array: 3.0.2 + postgres-bytea: 3.0.0 + postgres-date: 2.1.0 + postgres-interval: 3.0.0 + postgres-range: 1.1.4 dev: false /pg@8.11.5: @@ -28933,16 +28976,33 @@ packages: engines: {node: '>=4'} dev: false + /postgres-array@3.0.2: + resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==} + engines: {node: '>=12'} + dev: false + /postgres-bytea@1.0.0: resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} engines: {node: '>=0.10.0'} dev: false + /postgres-bytea@3.0.0: + resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==} + engines: {node: '>= 6'} + dependencies: + obuf: 1.1.2 + dev: false + /postgres-date@1.0.7: resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} engines: {node: '>=0.10.0'} dev: false + /postgres-date@2.1.0: + resolution: {integrity: sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==} + engines: {node: '>=12'} + dev: false + /postgres-interval@1.2.0: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} engines: {node: '>=0.10.0'} @@ -28950,6 +29010,15 @@ packages: xtend: 4.0.2 dev: false + /postgres-interval@3.0.0: + resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==} + engines: {node: '>=12'} + dev: false + + /postgres-range@1.1.4: + resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==} + dev: false + /posthog-js@1.93.3: resolution: {integrity: sha512-jEOWwaQpTRbqLPrDLY6eZr7t95h+LyXqN7Yq1/K6u3V0Y1C9xHtYhpuGzYamirVnCDTbVq22RM++OBUaIpp9Wg==} dependencies: @@ -32499,7 +32568,7 @@ packages: schema-utils: 3.3.0 serialize-javascript: 6.0.1 terser: 5.17.1 - webpack: 5.88.2 + webpack: 5.88.2(@swc/core@1.3.101)(esbuild@0.19.11) /terser-webpack-plugin@5.3.7(@swc/core@1.3.26)(esbuild@0.15.18)(webpack@5.88.2): resolution: {integrity: sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==} @@ -32862,7 +32931,7 @@ packages: micromatch: 4.0.5 semver: 7.5.4 typescript: 5.0.4 - webpack: 5.88.2 + webpack: 5.88.2(@swc/core@1.3.101)(esbuild@0.19.11) dev: true /ts-loader@9.4.4(typescript@5.2.2)(webpack@5.88.2): @@ -32877,7 +32946,7 @@ packages: micromatch: 4.0.5 semver: 7.5.4 typescript: 5.2.2 - webpack: 5.88.2 + webpack: 5.88.2(@swc/core@1.3.101)(esbuild@0.19.11) dev: true /ts-node@10.9.1(@swc/core@1.3.26)(@types/node@18.11.18)(typescript@5.2.2): @@ -34885,7 +34954,7 @@ packages: engines: {node: '>=10.13.0'} dependencies: glob-to-regexp: 0.4.1 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 /wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} @@ -34936,7 +35005,7 @@ packages: resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} engines: {node: '>=10.13.0'} - /webpack@5.88.2: + /webpack@5.88.2(@swc/core@1.3.101)(esbuild@0.19.11): resolution: {integrity: sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==} engines: {node: '>=10.13.0'} hasBin: true @@ -34986,7 +35055,7 @@ packages: optional: true dependencies: '@types/eslint-scope': 3.7.4 - '@types/estree': 1.0.5 + '@types/estree': 1.0.2 '@webassemblyjs/ast': 1.11.5 '@webassemblyjs/wasm-edit': 1.11.5 '@webassemblyjs/wasm-parser': 1.11.5 @@ -35427,6 +35496,7 @@ packages: /yaml@1.10.2: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} + dev: true /yaml@2.3.1: resolution: {integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==} From f7b3af379447573d8028a3038951b351f6e9b050 Mon Sep 17 00:00:00 2001 From: nicktrn <55853254+nicktrn@users.noreply.github.com> Date: Fri, 10 May 2024 17:23:23 +0100 Subject: [PATCH 2/3] remove stale docs link --- apps/webapp/app/entry.server.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/webapp/app/entry.server.tsx b/apps/webapp/app/entry.server.tsx index d1219ca587..f19d8f83ad 100644 --- a/apps/webapp/app/entry.server.tsx +++ b/apps/webapp/app/entry.server.tsx @@ -177,9 +177,6 @@ function logError(error: unknown, request?: Request) { if (error instanceof Error && error.message.startsWith("There are locked jobs present")) { console.log("⚠️ graphile-worker migration issue detected!"); - console.log( - "⚠️ see: https://trigger.dev/docs/documentation/guides/self-hosting/graphile-migration" - ); } } From e0c463bdb1da32ba280c1c5ca29a3d3aa39d07cd Mon Sep 17 00:00:00 2001 From: nicktrn <55853254+nicktrn@users.noreply.github.com> Date: Fri, 10 May 2024 18:01:39 +0100 Subject: [PATCH 3/3] fix jobs cleanup query --- apps/webapp/app/platform/zodWorker.server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/webapp/app/platform/zodWorker.server.ts b/apps/webapp/app/platform/zodWorker.server.ts index d8b35ef3da..f116b2a8f6 100644 --- a/apps/webapp/app/platform/zodWorker.server.ts +++ b/apps/webapp/app/platform/zodWorker.server.ts @@ -692,7 +692,7 @@ export class ZodWorker { const rawResults = await $replica.$queryRawUnsafe( `SELECT id FROM ${this.graphileWorkerSchema}.jobs - WHERE run_at > $1 + WHERE run_at < $1 AND locked_at IS NULL AND max_attempts = attempts LIMIT $2`,