@@ -26,7 +26,7 @@ import { ExpireEnqueuedRunService } from "./expireEnqueuedRun.server";
2626import { guardQueueSizeLimitsForEnv } from "../queueSizeLimits.server" ;
2727import { clampMaxDuration } from "../utils/maxDuration" ;
2828import { resolveIdempotencyKeyTTL } from "~/utils/idempotencyKeys.server" ;
29- import { Prisma } from "@trigger.dev/database" ;
29+ import { Prisma , TaskRun } from "@trigger.dev/database" ;
3030import { sanitizeQueueName } from "~/models/taskQueue.server" ;
3131
3232export type TriggerTaskServiceOptions = {
@@ -49,15 +49,30 @@ export class OutOfEntitlementError extends Error {
4949 }
5050}
5151
52+ export type TriggerTaskServiceResult = {
53+ run : TaskRun ;
54+ isCached : boolean ;
55+ } ;
56+
57+ const MAX_ATTEMPTS = 2 ;
58+
5259export class TriggerTaskService extends BaseService {
5360 public async call (
5461 taskId : string ,
5562 environment : AuthenticatedEnvironment ,
5663 body : TriggerTaskRequestBody ,
57- options : TriggerTaskServiceOptions = { }
58- ) {
64+ options : TriggerTaskServiceOptions = { } ,
65+ attempt : number = 0
66+ ) : Promise < TriggerTaskServiceResult | undefined > {
5967 return await this . traceWithEnv ( "call()" , environment , async ( span ) => {
6068 span . setAttribute ( "taskId" , taskId ) ;
69+ span . setAttribute ( "attempt" , attempt ) ;
70+
71+ if ( attempt > MAX_ATTEMPTS ) {
72+ throw new ServiceValidationError (
73+ `Failed to trigger ${ taskId } after ${ MAX_ATTEMPTS } attempts.`
74+ ) ;
75+ }
6176
6277 // TODO: Add idempotency key expiring here
6378 const idempotencyKey = options . idempotencyKey ?? body . options ?. idempotencyKey ;
@@ -74,13 +89,11 @@ export class TriggerTaskService extends BaseService {
7489 : body . options ?. ttl ?? ( environment . type === "DEVELOPMENT" ? "10m" : undefined ) ;
7590
7691 const existingRun = idempotencyKey
77- ? await this . _prisma . taskRun . findUnique ( {
92+ ? await this . _prisma . taskRun . findFirst ( {
7893 where : {
79- runtimeEnvironmentId_taskIdentifier_idempotencyKey : {
80- runtimeEnvironmentId : environment . id ,
81- idempotencyKey,
82- taskIdentifier : taskId ,
83- } ,
94+ runtimeEnvironmentId : environment . id ,
95+ idempotencyKey,
96+ taskIdentifier : taskId ,
8497 } ,
8598 } )
8699 : undefined ;
@@ -103,7 +116,7 @@ export class TriggerTaskService extends BaseService {
103116 } else {
104117 span . setAttribute ( "runId" , existingRun . friendlyId ) ;
105118
106- return existingRun ;
119+ return { run : existingRun , isCached : true } ;
107120 }
108121 }
109122
@@ -572,7 +585,7 @@ export class TriggerTaskService extends BaseService {
572585 ) ;
573586 }
574587
575- return run ;
588+ return { run, isCached : false } ;
576589 }
577590 ) ;
578591 } catch ( error ) {
@@ -608,6 +621,23 @@ export class TriggerTaskService extends BaseService {
608621 throw new Error (
609622 `Failed to trigger ${ taskId } as the queue could not be created do to a unique constraint error, please try again.`
610623 ) ;
624+ } else if (
625+ Array . isArray ( target ) &&
626+ target . length == 3 &&
627+ typeof target [ 0 ] === "string" &&
628+ typeof target [ 1 ] === "string" &&
629+ typeof target [ 2 ] === "string" &&
630+ target [ 0 ] == "runtimeEnvironmentId" &&
631+ target [ 1 ] == "taskIdentifier" &&
632+ target [ 2 ] == "idempotencyKey"
633+ ) {
634+ logger . debug ( "TriggerTask: Idempotency key violation, retrying..." , {
635+ taskId,
636+ environmentId : environment . id ,
637+ idempotencyKey,
638+ } ) ;
639+ // We need to retry the task run creation as the idempotency key has been used
640+ return await this . call ( taskId , environment , body , options , attempt + 1 ) ;
611641 } else {
612642 throw new ServiceValidationError (
613643 `Cannot trigger ${ taskId } as it has already been triggered with the same idempotency key.`
0 commit comments