From 2d270ca5278ac87e9405551e64cbcb3f240f7afd Mon Sep 17 00:00:00 2001 From: Bas van den Aakster Date: Sun, 14 Sep 2025 21:03:01 +0200 Subject: [PATCH] Improve job scheduling hooks to populate relationship immediately MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ✨ Enhanced Job Relationship Management: - Use beforeChange to populate existing jobs in relationship field - Use afterChange to create new jobs and add them to relationship - Jobs now appear immediately in the relationship field - Better handling of updates vs new document creation 🔄 Hook Flow: 1. beforeChange: Find existing jobs for updates and populate relationship 2. afterChange: Create missing jobs and update relationship field 3. Result: Jobs relationship is always populated correctly 📈 Benefits: - Immediate job visibility in admin interface - No reliance on dynamic filtering alone - Proper relationship data in database - Handles both new emails and status changes - Prevents duplicate job creation --- src/collections/Emails.ts | 69 +++++++++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/src/collections/Emails.ts b/src/collections/Emails.ts index 172ec67..3b32d5e 100644 --- a/src/collections/Emails.ts +++ b/src/collections/Emails.ts @@ -184,15 +184,63 @@ const Emails: CollectionConfig = { }, ], hooks: { + beforeChange: [ + async ({ data, originalDoc, req, operation }) => { + // Only process if this is a pending email and we have jobs configured + if (data.status !== 'pending' || !req.payload.jobs) { + return data + } + + // For updates, check if status changed to pending or if this was already pending + if (operation === 'update') { + // If it was already pending and still pending, skip (unless jobs field is empty) + if (originalDoc?.status === 'pending' && data.jobs && data.jobs.length > 0) { + return data + } + + // For updates where we need to check existing jobs, we need the document ID + if (originalDoc?.id) { + try { + // Check if a processing job already exists for this email + const existingJobs = await req.payload.find({ + collection: 'payload-jobs', + where: { + 'input.emailId': { + equals: String(originalDoc.id), + }, + task: { + equals: 'process-email', + }, + }, + limit: 10, + }) + + if (existingJobs.totalDocs > 0) { + // Add existing jobs to the relationship + const existingJobIds = existingJobs.docs.map(job => job.id) + data.jobs = [...(data.jobs || []), ...existingJobIds.filter(id => !data.jobs?.includes(id))] + return data + } + } catch (error) { + console.error(`Failed to check existing jobs for email ${originalDoc.id}:`, error) + } + } + } + + // For new emails or updates that need a new job, we'll create it after the document exists + // We'll handle this in afterChange for new documents since we need the ID + return data + } + ], afterChange: [ async ({ doc, previousDoc, req, operation }) => { - // Only process if this is a pending email and we have jobs configured + // Only process if this is a pending email, we have jobs configured, and no job exists yet if (doc.status !== 'pending' || !req.payload.jobs) { return } - // Skip if this is an update and status didn't change to pending - if (operation === 'update' && previousDoc?.status === 'pending') { + // Skip if this is an update and status didn't change to pending, and jobs already exist + if (operation === 'update' && previousDoc?.status === 'pending' && doc.jobs && doc.jobs.length > 0) { return } @@ -211,12 +259,12 @@ const Emails: CollectionConfig = { limit: 1, }) - // If no job exists, create one + // If no job exists, create one and add it to the relationship if (existingJobs.totalDocs === 0) { const mailingContext = (req.payload as any).mailing const queueName = mailingContext?.config?.queue || 'default' - await req.payload.jobs.queue({ + const job = await req.payload.jobs.queue({ queue: queueName, task: 'process-email', input: { @@ -226,7 +274,16 @@ const Emails: CollectionConfig = { waitUntil: doc.scheduledAt ? new Date(doc.scheduledAt) : undefined }) - console.log(`Auto-scheduled processing job for email ${doc.id}`) + // Update the email document to include the job in the relationship + await req.payload.update({ + collection: 'emails', + id: doc.id, + data: { + jobs: [...(doc.jobs || []), job.id] + } + }) + + console.log(`Auto-scheduled processing job ${job.id} for email ${doc.id}`) } } catch (error) { console.error(`Failed to auto-schedule job for email ${doc.id}:`, error)