A day after an order is delivered, ask for a review. If the delivery is late, move the reminder. If the guest already wrote a review, cancel it. The usual answer is a cron job that scans a table every minute.
A timer is a message that waits. It is named by its queue and a key: scheduling the same key again moves it, and cancelling the key removes it. When it is due, it arrives in its queue as a normal message, through the log.
// When an order is delivered, ask for a review in 24 hours.
await queen.timer('review-reminders').key('review-2001').delay('24h')
.payload({ orderId: 2001 }).schedule() // status: 'scheduled'
// The delivery was late: schedule the same key again, and the reminder moves.
await queen.timer('review-reminders').key('review-2001').delay('48h')
.payload({ orderId: 2001 }).schedule() // status: 'rescheduled'
// The guest wrote a review already: no reminder at all.
await queen.timer('review-reminders').key('review-2001').cancel()# When an order is delivered, ask for a review in 24 hours.
await (
queen.timer("review-reminders").key("review-2001").after(timedelta(hours=24))
.payload({"orderId": 2001}).schedule() # status: 'scheduled'
)
# The delivery was late: schedule the same key again, and the reminder moves.
await (
queen.timer("review-reminders").key("review-2001").after(timedelta(hours=48))
.payload({"orderId": 2001}).schedule() # status: 'rescheduled'
)
# The guest wrote a review already: no reminder at all.
await queen.timer("review-reminders").key("review-2001").cancel()// When an order is delivered, ask for a review in 24 hours.
r, err := client.Timers().Schedule(ctx, queen.TimerSchedule{
Queue: "review-reminders", TimerKey: "review-2001", Delay: 24 * time.Hour,
Payload: map[string]interface{}{"orderId": 2001},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(r.Status) // scheduled
// The delivery was late: schedule the same key again, and the reminder moves.
r, err = client.Timers().Schedule(ctx, queen.TimerSchedule{
Queue: "review-reminders", TimerKey: "review-2001", Delay: 48 * time.Hour,
Payload: map[string]interface{}{"orderId": 2001},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(r.Status) // rescheduled
// The guest wrote a review already: no reminder at all.
_, err = client.Timers().Cancel(ctx, "review-reminders", "review-2001")
if err != nil {
log.Fatal(err)
}// When an order is delivered, ask for a review in 24 hours.
let scheduled = queen
.timers()
.schedule("review-reminders", "review-2001", Duration::from_secs(24 * 3600))
.payload_json(&json!({ "orderId": 2001 }))?
.send()
.await?; // status: Scheduled
// The delivery was late: schedule the same key again, and the reminder moves.
let moved = queen
.timers()
.schedule("review-reminders", "review-2001", Duration::from_secs(48 * 3600))
.payload_json(&json!({ "orderId": 2001 }))?
.send()
.await?; // status: Rescheduled
// The guest wrote a review already: no reminder at all.
queen.timers().cancel("review-reminders", "review-2001").await?;// When an order is delivered, ask for a review in 24 hours.
$timer = $queen->timers()->schedule('review-reminders', 'review-2001', 24 * 3600 * 1000,
['orderId' => 2001]); // $timer['status']: 'scheduled'
// The delivery was late: schedule the same key again, and the reminder moves.
$timer = $queen->timers()->schedule('review-reminders', 'review-2001', 48 * 3600 * 1000,
['orderId' => 2001]); // $timer['status']: 'rescheduled'
// The guest wrote a review already: no reminder at all.
$queen->timers()->cancel('review-reminders', 'review-2001');// When an order is delivered, ask for a review in 24 hours.
queen::TimerSchedule reminder;
reminder.queue = "review-reminders";
reminder.timer_key = "review-2001";
reminder.payload = {{"orderId", 2001}};
reminder.delay_millis = 24 * 60 * 60 * 1000;
json first = client.timers().schedule(reminder); // status: "scheduled"
// The delivery was late: schedule the same key again, and the reminder moves.
reminder.delay_millis = 48 * 60 * 60 * 1000;
json moved = client.timers().schedule(reminder); // status: "rescheduled"
// The guest wrote a review already: no reminder at all.
client.timers().cancel("review-reminders", "review-2001");The first call answered scheduled and the second rescheduled; after the cancel, no reminder was left. A short timer of the same queue arrived as a message, with its payload as data.
One thing to know: a cancel can arrive just after the timer fired. The consumer of the reminder should check the order’s state before it sends anything.
Built from: KV, locks and timers.