From d4eac626ec66c6e896204b81139d17dc5e7909a4 Mon Sep 17 00:00:00 2001 From: Eric Allam Date: Fri, 31 Mar 2023 16:38:30 +0100 Subject: [PATCH] =?UTF-8?q?Removed=20ts=20in=20favor=20of=20ulid=E2=80=99s?= =?UTF-8?q?,=20and=20starting=20to=20implement=20the=20task=20list=20api?= =?UTF-8?q?=20#117?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/v3/executions.$executionId.tasks.ts | 62 ++++++++++++++++++- .../services/executions/resumeTask.server.ts | 1 + apps/webapp/app/services/ulid.server.ts | 7 +++ .../migration.sql | 8 +++ apps/webapp/prisma/schema.prisma | 3 +- packages/internal/src/schemas/api.ts | 1 - packages/internal/src/schemas/tasks.ts | 2 - packages/trigger-sdk/src/io.ts | 1 - 8 files changed, 77 insertions(+), 8 deletions(-) create mode 100644 apps/webapp/app/services/ulid.server.ts create mode 100644 apps/webapp/prisma/migrations/20230331150231_use_ulid_instead_of_cuid_and_ts_for_tasks/migration.sql diff --git a/apps/webapp/app/routes/api/v3/executions.$executionId.tasks.ts b/apps/webapp/app/routes/api/v3/executions.$executionId.tasks.ts index d6449830b..472819e55 100644 --- a/apps/webapp/app/routes/api/v3/executions.$executionId.tasks.ts +++ b/apps/webapp/app/routes/api/v3/executions.$executionId.tasks.ts @@ -1,4 +1,4 @@ -import type { ActionArgs } from "@remix-run/server-runtime"; +import type { ActionArgs, LoaderArgs } from "@remix-run/server-runtime"; import { json } from "@remix-run/server-runtime"; import type { RunTaskBodyOutput } from "@trigger.dev/internal"; import { RunTaskBodyOutputSchema } from "@trigger.dev/internal"; @@ -7,6 +7,7 @@ import type { PrismaClient } from "~/db.server"; import { prisma } from "~/db.server"; import { authenticateApiRequest } from "~/services/apiAuth.server"; import { logger } from "~/services/logger"; +import { ulid } from "~/services/ulid.server"; const ParamsSchema = z.object({ executionId: z.string(), @@ -16,6 +17,61 @@ const HeadersSchema = z.object({ "idempotency-key": z.string(), }); +const SearchQuerySchema = z.object({ + cursor: z.string().optional(), + take: z.coerce.number().default(50), +}); + +export async function loader({ request, params }: LoaderArgs) { + // Next authenticate the request + const authenticatedEnv = await authenticateApiRequest(request); + + if (!authenticatedEnv) { + return json({ error: "Invalid or Missing API key" }, { status: 401 }); + } + + const { executionId } = ParamsSchema.parse(params); + + const url = new URL(request.url); + const query = SearchQuerySchema.parse(Object.fromEntries(url.searchParams)); + + const execution = await prisma.execution.findUnique({ + where: { + id: executionId, + }, + include: { + tasks: { + orderBy: { + id: "asc", + }, + take: query.take, + skip: query.cursor ? 1 : 0, + cursor: query.cursor + ? { + id: query.cursor, + } + : undefined, + }, + }, + }); + + if (!execution) { + return json({ error: "Execution not found" }, { status: 404 }); + } + + if (execution.environmentId !== authenticatedEnv.id) { + return json({ error: "Execution not found" }, { status: 404 }); + } + + return json({ + data: execution.tasks, + nextCursor: + execution.tasks.length > 0 + ? execution.tasks[execution.tasks.length - 1]?.id + : undefined, + }); +} + export async function action({ request, params }: ActionArgs) { // Ensure this is a POST request if (request.method.toUpperCase() !== "POST") { @@ -116,6 +172,7 @@ export class RunExecutionTaskService { const task = await prisma.task.create({ data: { + id: ulid(), idempotencyKey, execution: { connect: { @@ -125,7 +182,8 @@ export class RunExecutionTaskService { name: taskBody.name, description: taskBody.description, status, - ts: taskBody.ts, + startedAt: new Date(), + completedAt: status === "COMPLETED" ? new Date() : undefined, noop: taskBody.noop, delayUntil: taskBody.delayUntil, params: taskBody.params ?? undefined, diff --git a/apps/webapp/app/services/executions/resumeTask.server.ts b/apps/webapp/app/services/executions/resumeTask.server.ts index c134e1f9d..c7728d995 100644 --- a/apps/webapp/app/services/executions/resumeTask.server.ts +++ b/apps/webapp/app/services/executions/resumeTask.server.ts @@ -46,6 +46,7 @@ export class ResumeTaskService { }, data: { status: task.noop ? "COMPLETED" : "RUNNING", + completedAt: task.noop ? new Date() : undefined, }, }); diff --git a/apps/webapp/app/services/ulid.server.ts b/apps/webapp/app/services/ulid.server.ts new file mode 100644 index 000000000..19675e6be --- /dev/null +++ b/apps/webapp/app/services/ulid.server.ts @@ -0,0 +1,7 @@ +import { monotonicFactory } from "ulid"; + +const factory = monotonicFactory(); + +export function ulid(): ReturnType { + return factory().toLowerCase(); +} diff --git a/apps/webapp/prisma/migrations/20230331150231_use_ulid_instead_of_cuid_and_ts_for_tasks/migration.sql b/apps/webapp/prisma/migrations/20230331150231_use_ulid_instead_of_cuid_and_ts_for_tasks/migration.sql new file mode 100644 index 000000000..8065a22a0 --- /dev/null +++ b/apps/webapp/prisma/migrations/20230331150231_use_ulid_instead_of_cuid_and_ts_for_tasks/migration.sql @@ -0,0 +1,8 @@ +/* + Warnings: + + - You are about to drop the column `ts` on the `Task` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "Task" DROP COLUMN "ts"; diff --git a/apps/webapp/prisma/schema.prisma b/apps/webapp/prisma/schema.prisma index 98031bc74..b99a184df 100644 --- a/apps/webapp/prisma/schema.prisma +++ b/apps/webapp/prisma/schema.prisma @@ -992,10 +992,9 @@ enum ExecutionStatus { } model Task { - id String @id @default(cuid()) + id String @id idempotencyKey String name String - ts String status TaskStatus @default(PENDING) delayUntil DateTime? diff --git a/packages/internal/src/schemas/api.ts b/packages/internal/src/schemas/api.ts index 0a502aa3a..e73f07a1b 100644 --- a/packages/internal/src/schemas/api.ts +++ b/packages/internal/src/schemas/api.ts @@ -127,7 +127,6 @@ export type CachedTask = z.infer; export const IOTaskSchema = z.object({ name: z.string(), - ts: z.string().default(() => String(Date.now())), noop: z.boolean().default(false), delayUntil: z.coerce.date().optional(), description: z.string().optional(), diff --git a/packages/internal/src/schemas/tasks.ts b/packages/internal/src/schemas/tasks.ts index 923c9d103..531645b6c 100644 --- a/packages/internal/src/schemas/tasks.ts +++ b/packages/internal/src/schemas/tasks.ts @@ -21,7 +21,6 @@ export type TaskStatus = z.infer; export const TaskSchema = z.object({ id: z.string(), name: z.string(), - ts: z.string(), noop: z.boolean().default(false), startedAt: z.coerce.date().optional().nullable(), completedAt: z.coerce.date().optional().nullable(), @@ -49,7 +48,6 @@ export const ServerTaskSchema = TaskSchema.extend({ export const CachedTaskSchema = z.object({ id: z.string(), idempotencyKey: z.string(), - ts: z.string(), status: TaskStatusSchema, noop: z.boolean().default(false), output: DeserializedJsonSchema.optional().nullable(), diff --git a/packages/trigger-sdk/src/io.ts b/packages/trigger-sdk/src/io.ts index 7f3996c55..db73d9c91 100644 --- a/packages/trigger-sdk/src/io.ts +++ b/packages/trigger-sdk/src/io.ts @@ -63,7 +63,6 @@ export class IO { idempotencyKey, noop: false, ...options, - ts: options.ts ?? String(Date.now()), }); if (task.status === "COMPLETED") {