Delayed Background functions

See how to delay the execution of a background function.


Prerequisites


 

 

 

Overview

Given the following background function:

src/defer/importContacts.ts
import { defer } from "@defer.run/client"
 
const importContacts = () => {
  // ...
}
export default defer(importContacts);

Here is how you would trigger a delayed execution of importContacts() in an Express API:

src/api.ts
import express from 'express'
import { delay } from "@defer.run/client"
import importContacts from '../defer/importContacts'
 
// ...
 
app.post('/hubspot/import', async function (req, res) {
  const userId = req.session.userId
 
  const delayedImportContacts = delay(importContacts, '1h')
  await delayedImportContacts(userId)
  
  res.send({ ok: true })
})

 

 

 

Full example: Todo reminder

We want to add to a Todo application the "inline Notion-like reminders" feature:


Notion inline reminders

For this example, we will assume that the front-end calls a POST /todos endpoint on our Express (opens in a new tab) API:

src/api.ts
import express from 'express'
 
const app = express()
 
interface Todo {
  userId: string
  title: string
  assigneeId?: string
  remind?: Date
}
 
app.post('/todos', async function (req, res) {
  const todoRecord: Todo = /* ... */
  
  // ...do some validation...
  
  const todo = await prisma.todo.create({
    data: todoRecord,
  })
 
  res.send({ todo })
})
 
app.listen(3000)

Let's now implement the reminder mail notification as a sendTodoReminder() background function.

 

 

 

The sendTodoReminder() background function

 

As stated in the "Getting started" guide, we create our sendTodoReminder() function in the defer/ folder:

- src/
  - defer/
    - sendTodoReminder.ts ⬅
  - api.ts
- package.json
- .env
- ...

 

Here is our sendTodoReminder() implementation, sending an email using Twilio Sengrid SingleMail API (opens in a new tab):


defer/sendTodoReminder.ts
const sgMail = require('@sendgrid/mail')
sgMail.setApiKey(process.env.SENDGRID_API_KEY)
 
const sendTodoReminder = async (todo: Todo) => {
  const { email } = await prisma.user.findUnique({
    where: {
      id: todo.userId,
    },
  })
  const msg = {
    to: email,
    from: 'test@todo.app',
    subject: 'TodoApp reminder',
    text: todo.title,
    html: todo.title,
  }
 
  return sgMail.send(msg)
}

Why use a Defer background function instead of Twilio Sendgrid scheduled Single Send API?

Mail scheduled with Twilio Sendgrid Single Send API can only be scheduled 3 days in advance.

Also, Defer offers a better developer experience at creating and cancelling scheduled mails.

 

 

 

Schedule reminders when creating a Todo

 

src/api.ts
import express from 'express'
import sendTodoReminder from './defer/sendTodoReminder'
 
const app = express()
 
interface Todo {
  userId: string
  title: string
  assigneeId?: string
  remind?: Date
}
 
app.post('/todos', async function (req, res) {
  const todoRecord: Todo = /* ... */
  
  // ...do some validation...
  
  const todo = await prisma.todo.create({
    data: todoRecord,
  })
 
  await sendTodoReminder.delay(todo, { delay: todo.remind })
 
  res.send({ todo })
})
 
app.listen(3000)

That's it 🎉

Your Todo App now offer resilient reminders sent by email:

  • resilient reminders: reminders will always happen, no matter the failures along the way, thanks to Defer's smart retries.
  • stay in control: Access analytics and logs of your scheduled reminders on the Defer dashboard:

Defer dashboard, scheduled function

This example will be soon updated to showcase how to update existing reminders.