跳至主要內容

排程未來日期的通知

佇列的一個常見使用案例是將工作排程在將來的某個時間點完成。
為了說明這是如何運作的,我們提供了一個範例應用程式 (如下所述),它排程透過 Courier API 傳送的通知訊息。此應用程式在 Deno Deploy 上執行,使用內建的 KV 和佇列 API 實作,且無需任何設定即可使用。

下載並設定範例

⬇️ 在此處下載或複製完整的範例應用程式.

你可以使用 GitHub 儲存庫的 README 檔案 中的說明,自行執行並部署此範例應用程式。

若要執行上述範例應用程式,你還需要 註冊 Courier。當然,你將在應用程式中看到的技術同樣適用於任何通知服務,從 Amazon SNSTwilio,但 Courier 提供了一個易於使用的通知 API,你可以使用個人 GMail 帳戶進行測試 (除了它可以執行的所有其他事項之外)。

主要功能

在設定並執行專案後,我們想將您的注意力導向實作排程機制的程式碼中幾個關鍵部分。

在應用程式啟動時連線至 KV 並加入監聽器

範例應用程式的多數功能存在於頂層目錄中的 server.tsx。當 Deno 應用程式程序啟動時,它會建立與 Deno KV 執行個體的連線,並附加一個事件處理常式,它會在從佇列收到訊息時處理這些訊息。

server.tsx
// Create a Deno KV database reference
const kv = await Deno.openKv();

// Create a queue listener that will process enqueued messages
kv.listenQueue(async (message) => {
/* ... implementation of listener here ... */
});

建立並排程通知

在這個示範應用程式中,透過表單提交新訂單後,會呼叫 enqueue 函式,並在寄出通知電子郵件前延遲五秒鐘。

server.tsx
app.post("/order", async (c) => {
const { email, order } = await c.req.parseBody();
const n: Notification = {
email: email as string,
body: `Order received for: "${order as string}"`,
};

// Select a time in the future - for now, just wait 5 seconds
const delay = 1000 * 5;

// Enqueue the message for processing!
kv.enqueue(n, { delay });

// Redirect back home with a success message!
setCookie(c, "flash_message", "Order created!");
return c.redirect("/");
});

在 TypeScript 中定義通知資料類型

在將資料推入或拉出佇列時,通常希望使用強類型物件。雖然佇列訊息最初是 unknown TypeScript 類型,但我們可以使用 類型防護 來告知編譯器我們預期的資料形狀。

以下是 notification 模組 的原始程式碼,我們使用它來描述系統中通知的屬性。

notification.ts
// Shape of a notification object
export default interface Notification {
email: string;
body: string;
}

// Type guard for a notification object
export function isNotification(o: unknown): o is Notification {
return (
((o as Notification)?.email !== undefined &&
typeof (o as Notification).email === "string") &&
((o as Notification)?.body !== undefined &&
typeof (o as Notification).body === "string")
);
}

server.tsx 中,我們使用導出的類型防護來確保我們回應正確的訊息類型。

server.tsx
kv.listenQueue(async (message) => {
// Use type guard to short circuit early if the message is of the wrong type
if (!isNotification(message)) return;

// Grab the relevant data from the message, which TypeScript now knows
// is a Notification interface
const { email, body } = message;

// Create an email notification with Courier
// ...
});

傳送 Courier API 要求

若要按預定時間傳送電子郵件,我們使用 Courier REST API。更多關於 Courier REST API 的資訊可以在 他們的參考文件 中找到。

server.tsx
const response = await fetch("https://api.courier.com/send", {
method: "POST",
headers: {
Authorization: `Bearer ${COURIER_API_TOKEN}`,
},
body: JSON.stringify({
message: {
to: { email },
content: {
title: "New order placed by Deno!",
body: "notification body goes here",
},
},
}),
});