@@ -31,6 +31,8 @@ vi.mock('@/lib/core/async-jobs', () => ({
3131 JOB_STATUS : {
3232 COMPLETED : 'completed' ,
3333 FAILED : 'failed' ,
34+ PENDING : 'pending' ,
35+ PROCESSING : 'processing' ,
3436 } ,
3537} ) )
3638
@@ -142,22 +144,72 @@ describe('newsletter Resend queueing', () => {
142144 )
143145 } )
144146
145- it ( 'moves a newsletter run to failed when its persisted database job failed' , async ( ) => {
146- mocks . getAsyncBackendType . mockReturnValue ( 'database' )
147+ it ( 'starts a new attempt when a persisted Trigger.dev job failed' , async ( ) => {
148+ mocks . claimAttempt
149+ . mockResolvedValueOnce ( {
150+ attempt : 2 ,
151+ jobId : 'trigger-run-failed' ,
152+ run,
153+ shouldEnqueue : false ,
154+ } )
155+ . mockResolvedValueOnce ( {
156+ attempt : 3 ,
157+ jobId : null ,
158+ run : { ...run , resendSyncJobId : null } ,
159+ shouldEnqueue : true ,
160+ } )
161+ mocks . queueGetJob . mockResolvedValue ( {
162+ id : 'trigger-run-failed' ,
163+ status : 'failed' ,
164+ error : 'worker stopped' ,
165+ } )
166+ mocks . queueEnqueue . mockResolvedValue ( 'trigger-run-retry' )
167+ mocks . setJob . mockResolvedValue ( { ...run , resendSyncJobId : 'trigger-run-retry' } )
168+
169+ const result = await enqueueNewsletterResendSync ( 'run-1' , 'admin-1' )
170+
171+ expect ( mocks . markFailed ) . toHaveBeenCalledWith ( 'run-1' , 2 , expect . any ( Error ) )
172+ expect ( mocks . queueEnqueue ) . toHaveBeenCalledWith (
173+ 'newsletter-resend-sync' ,
174+ { runId : 'run-1' , attempt : 3 , requestedById : 'admin-1' } ,
175+ expect . objectContaining ( { jobId : 'newsletter_resend_run-1_3' } )
176+ )
177+ expect ( result . jobId ) . toBe ( 'trigger-run-retry' )
178+ } )
179+
180+ it ( 're-enqueues when a stored Trigger.dev run no longer exists' , async ( ) => {
147181 mocks . claimAttempt . mockResolvedValue ( {
148182 attempt : 2 ,
149- jobId : 'newsletter_resend_run-1_2' ,
183+ jobId : 'trigger-run-missing' ,
184+ run,
185+ shouldEnqueue : false ,
186+ } )
187+ mocks . queueGetJob . mockResolvedValue ( null )
188+
189+ await enqueueNewsletterResendSync ( 'run-1' , 'admin-1' )
190+
191+ expect ( mocks . queueEnqueue ) . toHaveBeenCalledWith (
192+ 'newsletter-resend-sync' ,
193+ { runId : 'run-1' , attempt : 2 , requestedById : 'admin-1' } ,
194+ expect . objectContaining ( { jobId : 'newsletter_resend_run-1_2' } )
195+ )
196+ } )
197+
198+ it ( 'does not duplicate an active Trigger.dev run' , async ( ) => {
199+ mocks . claimAttempt . mockResolvedValue ( {
200+ attempt : 2 ,
201+ jobId : 'trigger-run-active' ,
150202 run,
151203 shouldEnqueue : false ,
152204 } )
153205 mocks . queueGetJob . mockResolvedValue ( {
154- id : 'newsletter_resend_run-1_2' ,
155- status : 'failed' ,
156- error : 'worker stopped' ,
206+ id : 'trigger-run-active' ,
207+ status : 'processing' ,
157208 } )
158209
159- await expect ( enqueueNewsletterResendSync ( 'run-1' , 'admin-1' ) ) . rejects . toThrow ( 'worker stopped' )
160- expect ( mocks . markFailed ) . toHaveBeenCalledWith ( 'run-1' , 2 , expect . any ( Error ) )
210+ const result = await enqueueNewsletterResendSync ( 'run-1' , 'admin-1' )
211+
212+ expect ( result . jobId ) . toBe ( 'trigger-run-active' )
161213 expect ( mocks . queueEnqueue ) . not . toHaveBeenCalled ( )
162214 } )
163215
0 commit comments