昨天我們讓系統具備錯誤處理與 Logging 功能,能更穩定地記錄與除錯。
今天要讓整個訂單流程「活起來」:當訂單完成後,店家不再需要手動通知顧客,而是讓系統自動透過 Messaging API 的 Push API 發送訊息給顧客。
這樣不但能延續 LINE Notify 的功能,還能支援更多互動式推播與自動化邏輯。
先跟各位抱歉...在昨日的預告中有告訴大家今天會整合 LINE Notify,在較之前的文章也曾經提及過 LINE Notify 的整合,當時我還在大學確實也是使用 LINE Notify 沒錯,但我沒有及時更新到資訊,非常抱歉!但這著實也代表,我真的是在這 30 天中跟大家一起每天開發一點再馬上分享出來 ~(>_<。)\
LINE 官方已宣布將於 2025 年 3 月 31 日終止 LINE Notify 服務。
若要實現同樣的推播功能,官方建議改用 Messaging API。
Messaging API 能以 Bot 的身分主動推播訊息給特定使用者或群組,功能更強大且長期支援。
當訂單狀態從 Pending → Completed 時,自動通知顧客。
使用 Messaging API 的 Push API(取代 LINE Notify)。
支援個人與群組推播,延伸性更高。
// src/lib/lineClient.js
const line = require("@line/bot-sdk");
const client = new line.Client({
channelAccessToken: process.env.CHANNEL_ACCESS_TOKEN,
channelSecret: process.env.CHANNEL_SECRET,
});
module.exports = client;
.env
:
CHANNEL_ACCESS_TOKEN=你的MessagingAPIToken
CHANNEL_SECRET=你的ChannelSecret
// src/utils/notifyUser.js
const client = require("../lib/lineClient");
const logger = require("../lib/logger");
async function notifyOrderCompleted(userId, orderId) {
const message = {
type: "text",
text: `🎉 您的訂單已完成!\n訂單編號:${orderId}\n感謝您的購買 🙌`,
};
try {
await client.pushMessage(userId, message);
logger.info(`推播成功:通知用戶 ${userId} 訂單完成`);
} catch (err) {
logger.error(`推播失敗 (${userId}):${err.message}`);
}
}
module.exports = { notifyOrderCompleted };
// worker/notify-worker.js
require("dotenv").config();
const { ensureConnected } = require("../src/lib/redis");
const { QUEUE_KEY } = require("../src/queues/notify");
const { notifyOrderCompleted } = require("../src/utils/notifyUser");
const logger = require("../src/lib/logger");
(async () => {
const redis = await ensureConnected();
logger.info("📡 Messaging API Worker 已啟動...");
while (true) {
const res = await redis.blPop(QUEUE_KEY, 5);
if (!res) continue;
const [, job] = res;
try {
const payload = JSON.parse(job);
if (payload.type === "order_completed") {
await notifyOrderCompleted(payload.userId, payload.orderId);
}
} catch (err) {
logger.error(`通知任務錯誤:${err.message}`);
}
}
})();
前置作業:
記得要先將 worker 起起來
!
讓使用者先與 Bot 聊天一次(取得 userId
)。
當訂單狀態更新為 Completed 時,推入佇列:
enqueueNotify({
type: "order_completed",
userId: "Uxxxxxxxxxx",
orderId: order._id,
});
3. Worker 取出任務後使用 Push API 傳送訊息。
目前有遇到通知失敗的問題,但礙於篇幅,明天會再向大家說明該如何解決這個問題,初步分析原因是 userId 沒有正確帶入!
4. 顧客會收到:
```
🎉 您的訂單已完成!
訂單編號:6654aef...
感謝您的購買 🙌
```
在實作過程中,許多人會遇到:「佇列有資料,但 Worker 沒反應」或「顧客沒有收到推播」。
這通常不是 LINE API 壞掉,而是 Worker 沒正確啟動 或 Redis 客戶端型別不符。
Worker 是一支獨立的 Node 程式,不會自動啟動。
你必須開一個新終端機、手動啟動它。
node worker/notify-worker.js
看到這行就代表啟動成功:
📡 Messaging API Worker 已啟動...
建議把指令寫入 package.json
方便啟動:
"scripts": {
"worker:notify": "node worker/notify-worker.js"
}
之後只要輸入:
npm run worker:notify
TypeError: res is not iterable
這是因為我們使用的 Redis 驅動是 node-redis v4,
它的 blPop()
回傳型別是 物件 { key, element }
,而不是陣列。
因此舊版寫法:
const [, job] = res; // ❌ 在 node-redis v4 會報錯
要改成:
const jobStr = res.element; // ✅ 正確
// worker/notify-worker.js
require("dotenv").config();
const { ensureConnected } = require("../src/lib/redis");
const { QUEUE_KEY } = require("../src/queues/notify");
const { notifyOrderCompleted } = require("../src/utils/notifyUser");
const logger = require("../src/lib/logger");
(async () => {
const redis = await ensureConnected();
console.log("Notify worker started.");
while (true) {
try {
const res = await redis.blPop(QUEUE_KEY, 5);
if (!res) continue; // timeout 繼續 loop
const jobStr = res.element; // ✅ node-redis v4 正確寫法
if (!jobStr) continue;
let payload;
try {
payload = JSON.parse(jobStr);
} catch (e) {
logger.error(`Job JSON 解析失敗:${jobStr}`);
continue;
}
if (payload.type === "order_completed") {
await notifyOrderCompleted(payload.userId, payload.orderId);
}
} catch (err) {
const detail =
err?.originalError?.response?.data || err?.response?.data || err.message;
logger.error(`通知任務錯誤:${JSON.stringify(detail)}`);
}
}
})();
功能 | Day 12 | Day 23 |
---|---|---|
對象 | 管理者群組 | 顧客(個人 userId) |
通知觸發點 | 新訂單建立 | 訂單完成 |
實作位置 | /orders API | Redis Worker |
API 類型 | pushMessage(groupId) | pushMessage(userId) |
改為 Flex Message 通知卡片(顯示商品明細、取貨方式)。
訂單狀態不同可發送不同模板(如製作中、出貨中)。
使用 Redis Pub/Sub 實現多 Worker 通知同步。
LINE Notify 終止服務後,建議全面改用 Messaging API。
Push API 可主動推播訊息給個人或群組,功能更彈性。
搭配 Redis Worker,即可建立穩定、自動化的通知機制。
明天(Day 24)我們將探討「多取貨方式與通知邏輯優化」,讓系統更貼近實際營運場景,並修正通知失敗,未帶入 userId 的問題。