Delayed reminders
Some background tasks need to run after a specific delay. For example:
- Sending a “Welcome” tips email 24 hours after a user signs up.
- Triggering a billing warning email exactly 3 days before a subscription expires.
- Executing an automatic database clean-up task at a scheduled date and time.
Layeron Queue supports future scheduling via delaySeconds (for relative delays from the moment of sending) and deliverAt (for absolute dates/times).
Code Implementation
Section titled “Code Implementation”This example demonstrates a user sign-up flow where we immediately send a verification email, then schedule a welcome follow-up email to be sent exactly 24 hours (86,400 seconds) later.
import { backend } from "@layeron/core"import { queue } from "@layeron/modules"
const app = backend()
// 1. Declare the notification queueconst notificationQueue = queue({ name: "notifications", retry: { maxAttempts: 3, backoff: "fixed", initialDelaySeconds: 10, },})
app.use(notificationQueue)
// 2. User Sign-up Routeapp.post("/users/signup", async (request) => { const body = await request.json() as { email: string; name: string } const userId = crypto.randomUUID()
// Perform database registration... await registerUserInDb(userId, body.email, body.name)
// A. Immediately enqueue an instant task to send a Verification Email await notificationQueue.send({ userId, type: "verification_email", recipient: body.email, })
// B. Enqueue a task to send a Welcome Email delayed by exactly 24 hours (86,400 seconds) await notificationQueue.send( { userId, type: "welcome_tips", recipient: body.email, }, { delaySeconds: 86400, // 24 hours delay }, )
// C. Alternatively, schedule an action for a specific absolute future Date const billingDate = new Date() billingDate.setDate(billingDate.getDate() + 30) // 30 days from now
await notificationQueue.send( { userId, type: "billing_invoice_generation", recipient: body.email, }, { deliverAt: billingDate, // Absolute time scheduling }, )
return Response.json({ status: "registered", userId, }, { status: 201 })})
// 3. Background Notification HandlernotificationQueue.consume(async (message) => { const { type, recipient, userId } = message.payload
console.log(`[Queue] Executing notification [${type}] for recipient: ${recipient}`)
if (type === "verification_email") { await sendVerificationLink(recipient, userId) } else if (type === "welcome_tips") { await sendWelcomeTips(recipient) } else if (type === "billing_invoice_generation") { await generateAndMailInvoice(recipient, userId) }})
// Mock helper functionsasync function registerUserInDb(id: string, email: string, name: string) {}async function sendVerificationLink(email: string, userId: string) {}async function sendWelcomeTips(email: string) {}async function generateAndMailInvoice(email: string, userId: string) {}How It Works
Section titled “How It Works”- Relative Delays with
delaySeconds: UsingdelaySeconds: 86400keeps the message unavailable to consumers for 24 hours. - Absolute Scheduling with
deliverAt: Passing a standard JavaScriptDateobject under thedeliverAtoption lets you set a precise target time. Layeron converts the date into an absolute UTC timestamp and delivers the message when that time is reached. - Queue Reusability: A single queue can handle different message types. By adding a
typediscriminator (e.g.,"verification_email"vs"welcome_tips") in the payload, your single consumer handler can cleanly route work to specialized services.