mirror of
https://github.com/xtr-dev/payload-mailing.git
synced 2025-12-10 00:03:23 +00:00
Simplify sendEmail to rely on hooks for job creation
🔄 Cleaner Architecture: - sendEmail now just creates the email and lets hooks handle job creation - Hooks automatically create and populate job relationship - For processImmediately, retrieves job from relationship and runs it - Removes duplicate job creation logic from sendEmail 📈 Benefits: - Single source of truth for job creation (hooks) - Consistent behavior across all email creation methods - Simpler, more maintainable code - Better separation of concerns 🔍 Flow: 1. sendEmail creates email document 2. Hooks auto-create job and populate relationship 3. If processImmediately, fetch job from relationship and run it 4. Return email with complete job relationship
This commit is contained in:
@@ -132,6 +132,7 @@ export const sendEmail = async <TEmail extends BaseEmailDocument = BaseEmailDocu
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the email in the collection with proper typing
|
// Create the email in the collection with proper typing
|
||||||
|
// The hooks will automatically create and populate the job relationship
|
||||||
const email = await payload.create({
|
const email = await payload.create({
|
||||||
collection: collectionSlug,
|
collection: collectionSlug,
|
||||||
data: emailData
|
data: emailData
|
||||||
@@ -142,54 +143,34 @@ export const sendEmail = async <TEmail extends BaseEmailDocument = BaseEmailDocu
|
|||||||
throw new Error('Failed to create email: invalid response from database')
|
throw new Error('Failed to create email: invalid response from database')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an individual job for this email
|
// If processImmediately is true, get the job from the relationship and process it now
|
||||||
const queueName = options.queue || mailingConfig.queue || 'default'
|
if (options.processImmediately) {
|
||||||
|
if (!payload.jobs) {
|
||||||
if (!payload.jobs) {
|
|
||||||
if (options.processImmediately) {
|
|
||||||
throw new Error('PayloadCMS jobs not configured - cannot process email immediately')
|
throw new Error('PayloadCMS jobs not configured - cannot process email immediately')
|
||||||
} else {
|
|
||||||
console.warn('PayloadCMS jobs not configured - emails will not be processed automatically')
|
|
||||||
return email as TEmail
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let jobId: string
|
// Wait a bit for hooks to complete and populate the job relationship
|
||||||
try {
|
// This is necessary because hooks might run asynchronously
|
||||||
const job = await payload.jobs.queue({
|
await new Promise(resolve => setTimeout(resolve, 100))
|
||||||
queue: queueName,
|
|
||||||
task: 'process-email',
|
// Refetch the email to get the populated jobs relationship
|
||||||
input: {
|
const emailWithJobs = await payload.findByID({
|
||||||
emailId: String(email.id)
|
collection: collectionSlug,
|
||||||
},
|
id: email.id,
|
||||||
// If scheduled, set the waitUntil date
|
|
||||||
waitUntil: emailData.scheduledAt ? new Date(emailData.scheduledAt) : undefined
|
|
||||||
})
|
})
|
||||||
|
|
||||||
jobId = String(job.id)
|
if (!emailWithJobs.jobs || emailWithJobs.jobs.length === 0) {
|
||||||
} catch (error) {
|
throw new Error(`No processing job found for email ${email.id}. The auto-scheduling may have failed.`)
|
||||||
// Clean up the orphaned email since job creation failed
|
|
||||||
try {
|
|
||||||
await payload.delete({
|
|
||||||
collection: collectionSlug,
|
|
||||||
id: email.id
|
|
||||||
})
|
|
||||||
} catch (deleteError) {
|
|
||||||
console.error(`Failed to clean up orphaned email ${email.id} after job creation failure:`, deleteError)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Throw the original job creation error
|
// Get the first job ID (should only be one for a new email)
|
||||||
const errorMsg = `Failed to create processing job for email ${email.id}: ${String(error)}`
|
const jobId = Array.isArray(emailWithJobs.jobs)
|
||||||
throw new Error(errorMsg)
|
? String(emailWithJobs.jobs[0])
|
||||||
}
|
: String(emailWithJobs.jobs)
|
||||||
|
|
||||||
// If processImmediately is true, process the job now
|
|
||||||
if (options.processImmediately) {
|
|
||||||
try {
|
try {
|
||||||
await processJobById(payload, jobId)
|
await processJobById(payload, jobId)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// For immediate processing failures, we could consider cleanup, but the job exists and could be retried later
|
|
||||||
// So we'll leave the email and job in place for potential retry
|
|
||||||
throw new Error(`Failed to process email ${email.id} immediately: ${String(error)}`)
|
throw new Error(`Failed to process email ${email.id} immediately: ${String(error)}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user