Adding support for trigger source in the run context

This commit is contained in:
Eric Allam
2023-06-28 12:06:58 +01:00
parent b975125af5
commit 24542d4e21
19 changed files with 204 additions and 376 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"@trigger.dev/sdk": patch
---
Adding support for trigger source in the run context, and make sure dynamic trigger runs are preprocessed so they have a chance of populating run properties
+1 -1
View File
@@ -11,7 +11,7 @@ const BodySchema = z.object({
}); });
export async function action({ request }: ActionArgs) { export async function action({ request }: ActionArgs) {
logger.info("Creating endpoint", { url: request.url }); logger.info("action", { url: request.url });
// Ensure this is a POST request // Ensure this is a POST request
if (request.method.toUpperCase() !== "POST") { if (request.method.toUpperCase() !== "POST") {
@@ -1,10 +1,10 @@
import type { RawEvent, SendEventOptions } from "@trigger.dev/internal"; import type { RawEvent, SendEventOptions } from "@trigger.dev/internal";
import { import {
$transaction, $transaction,
PrismaClient,
PrismaClientOrTransaction, PrismaClientOrTransaction,
PrismaErrorSchema,
prisma,
} from "~/db.server"; } from "~/db.server";
import { PrismaErrorSchema, prisma } from "~/db.server";
import type { AuthenticatedEnvironment } from "~/services/apiAuth.server"; import type { AuthenticatedEnvironment } from "~/services/apiAuth.server";
import { workerQueue } from "~/services/worker.server"; import { workerQueue } from "~/services/worker.server";
@@ -39,7 +39,8 @@ export class IngestSendEvent {
public async call( public async call(
environment: AuthenticatedEnvironment, environment: AuthenticatedEnvironment,
event: RawEvent, event: RawEvent,
options?: SendEventOptions options?: SendEventOptions,
sourceContext?: { id: string; metadata?: any }
) { ) {
try { try {
const deliverAt = this.#calculateDeliverAt(options); const deliverAt = this.#calculateDeliverAt(options);
@@ -80,6 +81,7 @@ export class IngestSendEvent {
payload: event.payload ?? {}, payload: event.payload ?? {},
context: event.context ?? {}, context: event.context ?? {},
source: event.source ?? "trigger.dev", source: event.source ?? "trigger.dev",
sourceContext,
deliverAt: deliverAt, deliverAt: deliverAt,
externalAccount: externalAccount externalAccount: externalAccount
? { ? {
@@ -6,6 +6,7 @@ import {
RunJobResumeWithTask, RunJobResumeWithTask,
RunJobRetryWithTask, RunJobRetryWithTask,
RunJobSuccess, RunJobSuccess,
RunSourceContextSchema,
} from "@trigger.dev/internal"; } from "@trigger.dev/internal";
import { generateErrorMessage } from "zod-error"; import { generateErrorMessage } from "zod-error";
import { EXECUTE_JOB_RETRY_LIMIT } from "~/consts"; import { EXECUTE_JOB_RETRY_LIMIT } from "~/consts";
@@ -242,6 +243,10 @@ export class PerformRunExecutionService {
} }
} }
const sourceContext = RunSourceContextSchema.safeParse(
run.event.sourceContext
);
const { response, parser } = await client.executeJobRequest({ const { response, parser } = await client.executeJobRequest({
event, event,
job: { job: {
@@ -270,6 +275,7 @@ export class PerformRunExecutionService {
} }
: undefined, : undefined,
connections: connections.auth, connections: connections.auth,
source: sourceContext.success ? sourceContext.data : undefined,
tasks: [run.tasks, resumedTask] tasks: [run.tasks, resumedTask]
.flat() .flat()
.filter(Boolean) .filter(Boolean)
@@ -47,14 +47,12 @@ export class DeliverScheduledEventService {
id: eventId, id: eventId,
name: SCHEDULED_EVENT, name: SCHEDULED_EVENT,
payload, payload,
context: {
source: {
id: scheduleSource.key,
metadata: scheduleSource.metadata,
},
},
}, },
{ accountId: scheduleSource.externalAccount?.identifier } { accountId: scheduleSource.externalAccount?.identifier },
{
id: scheduleSource.key,
metadata: scheduleSource.metadata,
}
); );
const invokeDispatcherService = new InvokeDispatcherService(tx); const invokeDispatcherService = new InvokeDispatcherService(tx);
@@ -88,9 +88,19 @@ export class DeliverHttpSourceRequestService {
const ingestService = new IngestSendEvent(); const ingestService = new IngestSendEvent();
for (const event of events) { for (const event of events) {
await ingestService.call(httpSourceRequest.environment, event, { await ingestService.call(
accountId: httpSourceRequest.source.externalAccount?.identifier, httpSourceRequest.environment,
}); event,
{
accountId: httpSourceRequest.source.externalAccount?.identifier,
},
httpSourceRequest.source.dynamicSourceId
? {
id: httpSourceRequest.source.dynamicSourceId,
metadata: httpSourceRequest.source.dynamicSourceMetadata,
}
: undefined
);
} }
return response; return response;
@@ -18,7 +18,8 @@ export class RegisterSourceService {
endpointId: string, endpointId: string,
metadata: SourceMetadata, metadata: SourceMetadata,
dynamicTriggerId?: string, dynamicTriggerId?: string,
accountId?: string accountId?: string,
dynamicSource?: { id: string; metadata: any }
) { ) {
const endpoint = await this.#prismaClient.endpoint.findUniqueOrThrow({ const endpoint = await this.#prismaClient.endpoint.findUniqueOrThrow({
where: { where: {
@@ -39,7 +40,8 @@ export class RegisterSourceService {
endpoint.environment, endpoint.environment,
metadata, metadata,
dynamicTriggerId, dynamicTriggerId,
accountId accountId,
dynamicSource
); );
} }
@@ -48,7 +50,8 @@ export class RegisterSourceService {
environment: AuthenticatedEnvironment, environment: AuthenticatedEnvironment,
metadata: SourceMetadata, metadata: SourceMetadata,
dynamicTriggerId?: string, dynamicTriggerId?: string,
accountId?: string accountId?: string,
dynamicSource?: { id: string; metadata: any }
) { ) {
logger.debug("Upserting source", { logger.debug("Upserting source", {
endpoint, endpoint,
@@ -57,9 +60,9 @@ export class RegisterSourceService {
accountId, accountId,
}); });
const key = dynamicTriggerId const key = [dynamicTriggerId, dynamicSource?.id, metadata.key]
? `${dynamicTriggerId}:${metadata.key}` .filter(Boolean)
: metadata.key; .join(":");
const { id, orphanedEvents } = await $transaction( const { id, orphanedEvents } = await $transaction(
this.#prismaClient, this.#prismaClient,
@@ -143,6 +146,8 @@ export class RegisterSourceService {
}, },
}, },
}, },
dynamicSourceId: dynamicSource?.id,
dynamicSourceMetadata: dynamicSource?.metadata,
}, },
update: { update: {
endpoint: { endpoint: {
@@ -151,6 +156,8 @@ export class RegisterSourceService {
}, },
}, },
integration: { connect: { id: integration.id } }, integration: { connect: { id: integration.id } },
dynamicSourceId: dynamicSource?.id,
dynamicSourceMetadata: dynamicSource?.metadata,
}, },
include: { include: {
events: true, events: true,
@@ -71,6 +71,7 @@ export class InitializeTriggerService {
endpointSlug, endpointSlug,
key: payload.id, key: payload.id,
accountId: payload.accountId, accountId: payload.accountId,
registrationMetadata: payload.metadata,
}); });
await this.#sendEvent.call( await this.#sendEvent.call(
@@ -23,6 +23,7 @@ export class RegisterTriggerSourceService {
id, id,
key, key,
accountId, accountId,
registrationMetadata,
}: { }: {
environment: AuthenticatedEnvironment; environment: AuthenticatedEnvironment;
payload: RegisterTriggerBody; payload: RegisterTriggerBody;
@@ -30,6 +31,7 @@ export class RegisterTriggerSourceService {
endpointSlug: string; endpointSlug: string;
key: string; key: string;
accountId?: string; accountId?: string;
registrationMetadata?: any;
}): Promise<RegisterSourceEvent> { }): Promise<RegisterSourceEvent> {
const endpoint = await this.#prismaClient.endpoint.findUniqueOrThrow({ const endpoint = await this.#prismaClient.endpoint.findUniqueOrThrow({
where: { where: {
@@ -58,7 +60,8 @@ export class RegisterTriggerSourceService {
endpoint.id, endpoint.id,
payload.source, payload.source,
dynamicTrigger.id, dynamicTrigger.id,
accountId accountId,
{ id: key, metadata: registrationMetadata }
); );
const eventDispatcher = await tx.eventDispatcher.upsert({ const eventDispatcher = await tx.eventDispatcher.upsert({
@@ -104,8 +107,11 @@ export class RegisterTriggerSourceService {
dynamicTriggerId: dynamicTrigger.id, dynamicTriggerId: dynamicTrigger.id,
sourceId: triggerSource.id, sourceId: triggerSource.id,
eventDispatcherId: eventDispatcher.id, eventDispatcherId: eventDispatcher.id,
metadata: registrationMetadata,
},
update: {
metadata: registrationMetadata,
}, },
update: {},
}); });
const secretStore = getSecretStore( const secretStore = getSecretStore(
+2
View File
@@ -245,6 +245,8 @@ new Job(client, {
github: githubUser, github: githubUser,
}, },
run: async (payload, io, ctx) => { run: async (payload, io, ctx) => {
await io.logger.info("user-on-issue-opened", { ctx });
return await io.github.getRepo("get.repo", { return await io.github.getRepo("get.repo", {
owner: payload.repository.owner.login, owner: payload.repository.owner.login,
repo: payload.repository.name, repo: payload.repository.name,
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "EventRecord" ADD COLUMN "sourceContext" JSONB;
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "DynamicTriggerRegistration" ADD COLUMN "metadata" JSONB;
@@ -0,0 +1,3 @@
-- AlterTable
ALTER TABLE "TriggerSource" ADD COLUMN "dynamicSourceId" TEXT,
ADD COLUMN "dynamicSourceMetadata" JSONB;
+12 -6
View File
@@ -577,12 +577,13 @@ enum JobStartPosition {
} }
model EventRecord { model EventRecord {
id String @id @default(cuid()) id String @id @default(cuid())
eventId String eventId String
name String name String
timestamp DateTime @default(now()) timestamp DateTime @default(now())
payload Json payload Json
context Json? context Json?
sourceContext Json?
source String @default("trigger.dev") source String @default("trigger.dev")
@@ -853,6 +854,9 @@ model TriggerSource {
externalAccount ExternalAccount? @relation(fields: [externalAccountId], references: [id], onDelete: Cascade, onUpdate: Cascade) externalAccount ExternalAccount? @relation(fields: [externalAccountId], references: [id], onDelete: Cascade, onUpdate: Cascade)
externalAccountId String? externalAccountId String?
dynamicSourceId String?
dynamicSourceMetadata Json?
active Boolean @default(false) active Boolean @default(false)
interactive Boolean @default(false) interactive Boolean @default(false)
@@ -900,6 +904,8 @@ model DynamicTriggerRegistration {
source TriggerSource @relation(fields: [sourceId], references: [id], onDelete: Cascade, onUpdate: Cascade) source TriggerSource @relation(fields: [sourceId], references: [id], onDelete: Cascade, onUpdate: Cascade)
sourceId String sourceId String
metadata Json?
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
+7
View File
@@ -238,6 +238,11 @@ export type RuntimeEnvironmentType = z.infer<
typeof RuntimeEnvironmentTypeSchema typeof RuntimeEnvironmentTypeSchema
>; >;
export const RunSourceContextSchema = z.object({
id: z.string(),
metadata: z.any(),
});
export const RunJobBodySchema = z.object({ export const RunJobBodySchema = z.object({
event: ApiEventLogSchema, event: ApiEventLogSchema,
job: z.object({ job: z.object({
@@ -265,6 +270,7 @@ export const RunJobBodySchema = z.object({
metadata: z.any(), metadata: z.any(),
}) })
.optional(), .optional(),
source: RunSourceContextSchema.optional(),
tasks: z.array(CachedTaskSchema).optional(), tasks: z.array(CachedTaskSchema).optional(),
connections: z.record(ConnectionAuthSchema).optional(), connections: z.record(ConnectionAuthSchema).optional(),
}); });
@@ -496,6 +502,7 @@ export const InitializeTriggerBodySchema = z.object({
id: z.string(), id: z.string(),
params: z.any(), params: z.any(),
accountId: z.string().optional(), accountId: z.string().optional(),
metadata: z.any().optional()
}); });
export type InitializeTriggerBody = z.infer<typeof InitializeTriggerBodySchema>; export type InitializeTriggerBody = z.infer<typeof InitializeTriggerBodySchema>;
+2 -1
View File
@@ -638,7 +638,7 @@ export class TriggerClient {
} }
#createRunContext(execution: RunJobBody): TriggerContext { #createRunContext(execution: RunJobBody): TriggerContext {
const { event, organization, environment, job, run } = execution; const { event, organization, environment, job, run, source } = execution;
return { return {
event: { event: {
@@ -652,6 +652,7 @@ export class TriggerClient {
job, job,
run, run,
account: execution.account, account: execution.account,
source,
}; };
} }
+1 -1
View File
@@ -101,6 +101,6 @@ export class DynamicTrigger<
} }
get preprocessRuns() { get preprocessRuns() {
return false; return true;
} }
} }
+1
View File
@@ -18,6 +18,7 @@ export interface TriggerContext {
run: { id: string; isTest: boolean; startedAt: Date }; run: { id: string; isTest: boolean; startedAt: Date };
event: { id: string; name: string; context: any; timestamp: Date }; event: { id: string; name: string; context: any; timestamp: Date };
account?: { id: string; metadata?: any }; account?: { id: string; metadata?: any };
source?: { id: string; metadata?: any };
} }
export interface TriggerPreprocessContext { export interface TriggerPreprocessContext {
+115 -346
View File
File diff suppressed because it is too large Load Diff