12 thg 8, 2025·8 phút đọc

Triggers vs background job workers cho thông báo đáng tin

Tìm hiểu khi nào trigger hay background worker an toàn hơn để gửi thông báo: hướng dẫn thực tế về retry, transaction và ngăn trùng lặp.

Triggers vs background job workers cho thông báo đáng tin

Tại sao việc gửi thông báo bị gián đoạn trong ứng dụng thực tế

Thông báo nghe có vẻ đơn giản: người dùng làm gì đó, sau đó một email hoặc SMS được gửi. Hầu hết thất bại thực tế đều về thời điểm và trùng lặp. Tin nhắn có thể được gửi trước khi dữ liệu thực sự được lưu, hoặc bị gửi hai lần sau khi xảy ra lỗi một phần.

“Một thông báo” có thể là nhiều thứ: email biên nhận, mã một lần qua SMS, cảnh báo push, tin nhắn trong ứng dụng, ping Slack hoặc Telegram, hoặc webhook đến hệ thống khác. Vấn đề chung luôn giống nhau: bạn cố gắng phối hợp một thay đổi cơ sở dữ liệu với thứ nằm ngoài ứng dụng của bạn.

Thế giới bên ngoài lộn xộn. Nhà cung cấp có thể chậm, trả về timeout, hoặc chấp nhận một yêu cầu trong khi ứng dụng của bạn không nhận được phản hồi thành công. Ứng dụng của bạn có thể crash hoặc khởi động lại giữa chừng. Ngay cả những lần gửi “thành công” cũng có thể bị chạy lại vì retry của hạ tầng, worker khởi động lại, hoặc người dùng bấm nút lần nữa.

Nguyên nhân phổ biến khiến việc gửi thông báo bị hỏng gồm timeout mạng, nhà cung cấp ngừng hoạt động hoặc giới hạn tần suất, app khởi động lại vào thời điểm bất lợi, retry tái thực hiện cùng logic gửi mà không có rào chắn duy nhất, và thiết kế nơi việc ghi vào DB và gửi ra ngoài được thực hiện như một bước hợp nhất.

Khi mọi người yêu cầu “thông báo đáng tin cậy”, họ thường có ý một trong hai điều:

  • giao đúng một lần, hoặc
  • ít nhất không trùng lặp (thông báo trùng thường tệ hơn chậm trễ).

Đạt được cả nhanh và hoàn toàn an toàn rất khó, nên bạn phải đánh đổi giữa tốc độ, an toàn và độ phức tạp.

Đó là lý do lựa chọn giữa triggers và background job workers không chỉ là tranh luận kiến trúc. Đó là về khi nào được phép gửi, cách xử lý retry khi thất bại, và làm sao ngăn email hay SMS trùng lặp khi có sự cố xảy ra.

Trigger và background worker: nghĩa là gì

Khi so sánh triggers với background job workers, thực ra họ đang so sánh nơi chạy logic thông báo và mức độ gắn chặt với hành động gây ra nó.

Trigger là “làm ngay khi X xảy ra.” Trong nhiều ứng dụng, điều đó có nghĩa là gửi email hoặc SMS ngay sau hành động của người dùng, bên trong cùng một request web. Trigger cũng có thể ở cấp cơ sở dữ liệu: trigger DB chạy tự động khi một hàng được chèn hoặc cập nhật. Cả hai kiểu đều có cảm giác tức thời, nhưng thừa hưởng thời điểm và giới hạn của thứ đã kích hoạt chúng.

Background worker là “làm sớm nhưng không ở foreground.” Đó là một tiến trình riêng lấy job từ hàng đợi và cố hoàn thành chúng. Ứng dụng chính của bạn ghi lại những gì cần xảy ra rồi trả về nhanh, trong khi worker xử lý phần chậm hơn, dễ lỗi hơn như gọi nhà cung cấp email hoặc SMS.

“Một job” là đơn vị công việc worker xử lý. Thường bao gồm ai cần thông báo, template nào, dữ liệu để điền, trạng thái hiện tại (queued, processing, sent, failed), số lần thử đã thực hiện, và đôi khi cả thời gian lên lịch.

Luồng thông báo điển hình: bạn chuẩn bị chi tiết tin nhắn, đưa job vào hàng đợi, gửi qua nhà cung cấp, ghi kết quả, rồi quyết định retry, dừng hay cảnh báo ai đó.

Ranh giới transaction: khi nào thực sự an toàn để gửi

Ranh giới transaction là đường ranh giữa “chúng tôi đã cố lưu” và “nó thực sự được lưu.” Cho đến khi database commit, thay đổi vẫn có thể rollback. Điều đó quan trọng vì thông báo rất khó thu hồi.

Nếu bạn gửi email hoặc SMS trước khi commit, bạn có thể thông báo ai đó về điều chưa từng xảy ra. Khách hàng có thể nhận “Mật khẩu của bạn đã được đổi” hoặc “Đơn hàng của bạn đã được xác nhận”, rồi sau đó việc ghi bị lỗi do constraint hoặc timeout. Giờ người dùng bối rối và support phải giải quyết.

Gửi từ trong trigger cơ sở dữ liệu trông hấp dẫn vì nó chạy tự động khi dữ liệu thay đổi. Nhưng điểm rắc rối là trigger chạy trong cùng transaction. Nếu transaction rollback, bạn có thể đã gọi nhà cung cấp email hoặc SMS rồi.

Trigger DB cũng khó quan sát, kiểm thử và retry an toàn hơn. Khi chúng thực hiện cuộc gọi ngoài chậm, chúng có thể giữ khóa lâu hơn dự kiến và làm cho vấn đề DB khó chẩn đoán hơn.

Một cách an toàn hơn là ý tưởng outbox: ghi lại ý định thông báo dưới dạng dữ liệu, commit nó, rồi gửi sau.

Bạn thực hiện thay đổi nghiệp vụ và, trong cùng transaction, chèn một hàng outbox mô tả tin nhắn (người nhận, nội dung, kênh, cộng một khóa duy nhất). Sau khi commit, một worker nền đọc các hàng outbox đang chờ, gửi tin nhắn, rồi đánh dấu chúng là đã gửi.

Gửi ngay lập tức vẫn có thể chấp nhận được cho các thông báo ít hệ quả, mang tính thông tin, nơi sai lầm được chấp nhận, như “Chúng tôi đang xử lý yêu cầu của bạn.” Với bất cứ thứ gì phải khớp với trạng thái cuối cùng, hãy đợi sau commit.

Retry và xử lý lỗi: đâu là lợi thế của từng cách

Retry thường là yếu tố quyết định.

Triggers: nhanh nhưng mong manh khi lỗi xảy ra

Hầu hết thiết kế dựa trên trigger không có câu chuyện retry tốt.

Nếu trigger gọi nhà cung cấp email/SMS và cuộc gọi thất bại, bạn thường kết thúc với hai lựa chọn tồi:

  • khiến transaction thất bại (và chặn cập nhật ban đầu), hoặc
  • nuốt lỗi (và im lặng mất thông báo).

Cả hai đều không chấp nhận được khi độ tin cậy quan trọng.

Cố lặp hoặc trì hoãn bên trong trigger có thể làm tệ hơn bằng cách giữ transactions mở lâu hơn, tăng thời gian giữ khóa và làm chậm DB. Và nếu DB hoặc app chết giữa lúc gửi, bạn thường không biết liệu nhà cung cấp có nhận yêu cầu hay không.

Background workers: thiết kế cho retry

Worker xem gửi như một task riêng với trạng thái riêng. Điều đó khiến retry trở nên tự nhiên.

Quy tắc thực tế: bạn thường retry các lỗi tạm thời (timeout, sự cố mạng thoáng qua, lỗi server, bị giới hạn tần suất với thời gian chờ dài hơn). Bạn không retry các vấn đề vĩnh viễn (số điện thoại không hợp lệ, email sai định dạng, từ chối cứng như đã hủy đăng ký). Với lỗi “không rõ”, giới hạn số lần thử và hiển thị trạng thái.

Backoff giúp retry không làm tệ thêm tình hình. Bắt đầu với khoảng chờ ngắn, rồi tăng dần (ví dụ 10s, 30s, 2m, 10m) và dừng sau số lần thử cố định.

Để sống sót qua deploy và restart, lưu trạng thái retry cùng mỗi job: số lần thử, thời gian thử tiếp theo, lỗi cuối (ngắn và dễ đọc), thời gian thử cuối cùng, và trạng thái rõ ràng như pending, sending, sent, failed.

Nếu app khởi động lại giữa chừng khi đang gửi, worker có thể kiểm tra lại các job kẹt (ví dụ trạng thái = sending với timestamp cũ) và retry an toàn. Đây là nơi idempotency trở nên thiết yếu để retry không gửi trùng.

Ngăn email và SMS trùng lặp bằng idempotency

Triển khai worker gửi
Triển khai worker gửi của bạn lên AppMaster Cloud hoặc cloud riêng khi sẵn sàng.
Bắt đầu Xây dựng

Idempotency nghĩa là bạn có thể chạy lại cùng một hành động “gửi thông báo” nhiều lần và người dùng vẫn chỉ nhận một lần.

Trường hợp trùng lặp cổ điển là timeout: app gọi nhà cung cấp email hoặc SMS, request timeout, và code của bạn retry. Yêu cầu đầu tiên có thể đã thực sự thành công, nên lần retry tạo bản sao.

Cách khắc phục thực tế là cấp cho mỗi tin nhắn một khóa ổn định và xem khóa đó như nguồn sự thật duy nhất. Khóa tốt mô tả ý nghĩa của tin nhắn, không phải khi bạn cố gửi.

Các cách phổ biến bao gồm:

  • một notification_id sinh ra khi bạn quyết định “tin nhắn này phải tồn tại”, hoặc
  • một khóa lấy từ nghiệp vụ như order_id + template + recipient (chỉ khi thực sự định nghĩa tính duy nhất).

Sau đó lưu một sổ cái gửi (thường là chính bảng outbox) và bắt mọi retry phải tham khảo trước khi gửi. Giữ trạng thái đơn giản và hiển thị: created (đã quyết định), queued (sẵn sàng), sent (xác nhận đã gửi), failed (xác nhận thất bại), canceled (không còn cần). Quy tắc quan trọng là chỉ cho phép một bản ghi hoạt động cho mỗi khóa idempotency.

Idempotency phía nhà cung cấp có thể hữu ích khi được hỗ trợ, nhưng không thay thế sổ cái của bạn. Bạn vẫn cần xử lý retry, deploy và restart worker của chính mình.

Cũng coi các kết quả “không rõ” là hàng ghế đầu. Nếu request timeout, đừng gửi lại ngay. Đánh dấu là đang chờ xác nhận và retry an toàn bằng cách kiểm tra trạng thái giao hàng từ nhà cung cấp khi có thể. Nếu không thể xác nhận, trì hoãn và cảnh báo thay vì gửi trùng.

Mẫu mặc định an toàn: outbox + background worker (từng bước)

Nếu bạn muốn một mặc định an toàn, mô hình outbox cộng worker khó bị đánh bại. Nó giữ việc gửi ra ngoài transaction nghiệp vụ, trong khi vẫn đảm bảo ý định gửi được lưu.

Luồng

Xem “gửi thông báo” như dữ liệu bạn lưu, không phải hành động bạn phóng ngay.

Bạn lưu thay đổi nghiệp vụ (ví dụ cập nhật trạng thái đơn hàng) vào bảng chính. Trong cùng transaction, bạn cũng chèn một hàng outbox với người nhận, kênh (email/SMS), template, payload và khóa idempotency. Bạn commit transaction. Chỉ sau thời điểm đó mới có thể gửi bất cứ thứ gì.

Worker nền định kỳ lấy các hàng outbox chờ, gửi chúng, và ghi kết quả.

Thêm bước claim đơn giản để hai worker không lấy cùng một hàng. Đây có thể là chuyển trạng thái sang processing hoặc một timestamp khóa.

Ngăn trùng lặp và xử lý lỗi

Trùng lặp thường xảy ra khi gửi thành công nhưng app của bạn crash trước khi ghi “sent.” Bạn giải quyết bằng cách làm cho thao tác “đánh dấu đã gửi” có thể lặp lại an toàn.

Dùng quy tắc duy nhất (ví dụ ràng buộc unique trên khóa idempotency và kênh). Retry với quy tắc rõ ràng: số lần thử hạn chế, độ trễ tăng dần, và chỉ với các lỗi có thể retry. Sau lần thử cuối cùng, chuyển job vào trạng thái dead-letter (như failed_permanent) để ai đó xem xét và xử lý thủ công.

Giám sát có thể đơn giản: đếm số pending, processing, sent, retrying, và failed_permanent, cộng với timestamp của hàng chờ lâu nhất.

Ví dụ cụ thể: khi đơn hàng chuyển từ “Đóng gói” sang “Đã gửi”, bạn cập nhật hàng orders và tạo một hàng outbox với khóa idempotency order-4815-shipped. Dù worker crash giữa chừng, chạy lại cũng không gửi đôi vì thao tác ghi “sent” được bảo vệ bởi khóa duy nhất đó.

Khi nào nên chọn background workers

Xây luồng sẵn sàng cho production
Sinh mã backend và app thực tế trong khi giữ logic thông báo nhất quán.
Xây dựng với AppMaster

Trigger DB phản ứng ngay khi dữ liệu thay đổi. Nhưng nếu công việc là “giao thông báo đáng tin cậy trong điều kiện thế giới thực lộn xộn”, worker nền thường cho bạn nhiều quyền kiểm soát hơn.

Worker phù hợp hơn khi bạn cần gửi theo thời gian (nhắc nhở, digest), khối lượng lớn với giới hạn tần suất và backpressure, dung nạp biến động nhà cung cấp (giới hạn 429, phản hồi chậm, gián đoạn ngắn), workflows nhiều bước (gửi, chờ giao hàng, rồi follow-up), hoặc sự kiện xuyên hệ thống cần đối chiếu.

Ví dụ đơn giản: bạn thu tiền khách, rồi gửi biên nhận SMS, rồi email hóa đơn. Nếu SMS fail do gateway, bạn vẫn muốn đơn được ghi nhận thanh toán và muốn retry an toàn sau. Đặt logic đó trong trigger làm tăng rủi ro trộn lẫn “dữ liệu đúng” với “bên thứ ba khả dụng ngay bây giờ”.

Worker cũng giúp vận hành dễ dàng hơn. Bạn có thể tạm dừng queue khi sự cố, kiểm tra lỗi và retry có trì hoãn.

Sai lầm phổ biến gây mất hoặc trùng thông báo

Theo dõi mọi lần thử
Tạo một sổ cái đơn giản với trạng thái như pending, processing, sent, và failed.
Bắt đầu Ngay

Cách nhanh nhất để có thông báo không đáng tin là “gửi ngay” ở bất cứ chỗ nào thuận tiện, rồi hy vọng retry sẽ cứu vãn. Dù bạn dùng trigger hay worker, chi tiết về thất bại và trạng thái quyết định người dùng nhận một, hai hay không nhận tin nào cả.

Bẫy phổ biến là gửi từ trigger DB và giả định nó không thể lỗi. Trigger chạy trong transaction, nên bất kỳ cuộc gọi nhà cung cấp chậm nào có thể làm treo ghi, gặp timeout hoặc giữ khóa lâu hơn bạn mong. Tệ hơn, nếu gửi thất bại và bạn rollback, bạn có thể retry sau và gửi đôi nếu nhà cung cấp thực tế đã chấp nhận lần gọi đầu.

Những lỗi lặp lại xuất hiện:

  • Retry mọi thứ theo cùng một cách, kể cả lỗi vĩnh viễn (email sai, số bị chặn).
  • Không tách queued khỏi sent, nên bạn không biết cái nào an toàn để retry sau khi crash.
  • Dùng timestamp làm khóa dedupe, nên retry dễ dàng vượt qua tính duy nhất.
  • Gọi nhà cung cấp trong đường dẫn request của người dùng (checkout và submit form không nên chờ gateways).
  • Xử lý timeout của nhà cung cấp như “chưa gửi”, trong khi nhiều trường hợp thực ra là “không rõ”.

Ví dụ đơn giản: bạn gửi SMS, nhà cung cấp timeout, và bạn retry. Nếu yêu cầu đầu đã thành công, người dùng nhận hai mã. Cách sửa là ghi khóa idempotency ổn định (ví dụ notification_id), đánh dấu tin nhắn là queued trước khi gửi, rồi chỉ đánh dấu sent sau khi có phản hồi thành công rõ ràng.

Kiểm tra nhanh trước khi phát hành thông báo

Hầu hết lỗi thông báo không phải do công cụ. Là do thời điểm, retry và thiếu bản ghi.

Xác nhận bạn chỉ gửi sau khi ghi DB đã commit an toàn. Nếu gửi trong cùng transaction và nó sau này rollback, người dùng có thể nhận thông báo về điều chưa xảy ra.

Tiếp theo, làm cho mỗi thông báo có thể nhận dạng duy nhất. Cấp cho mỗi tin một khóa idempotency ổn định (ví dụ order_id + event_type + channel) và thực thi ràng buộc trong lưu trữ để retry không tạo thông báo thứ hai.

Trước khi release, kiểm tra các cơ bản sau:

  • Gửi xảy ra sau commit, không trong khi viết.
  • Mỗi thông báo có khóa idempotency duy nhất và duplicate bị từ chối.
  • Retry an toàn: hệ thống có thể chạy lại cùng job và vẫn tối đa gửi một lần.
  • Mỗi lần thử được ghi lại (trạng thái, last_error, timestamps).
  • Số lần thử bị giới hạn, và các item kẹt có chỗ rõ ràng để xem và xử lý lại.

Thử hành vi restart có chủ đích. Kill worker giữa lúc gửi, khởi động lại, và xác minh không có gì gửi đôi. Làm tương tự khi DB bị tải cao.

Kịch bản đơn giản để kiểm tra: người dùng thay đổi số điện thoại, rồi bạn gửi SMS xác thực. Nếu nhà cung cấp SMS timeout, app của bạn retry. Với khóa idempotency tốt và nhật ký lần thử, bạn sẽ hoặc gửi một lần, hoặc thử lại an toàn sau, nhưng không spam.

Ví dụ cụ thể: cập nhật đơn hàng không gửi đôi

Triển khai mặc định an toàn
Prototype mẫu đầy đủ nhanh: mô hình dữ liệu, logic nghiệp vụ và UI để giám sát.
Thử AppMaster

Một cửa hàng gửi hai loại tin: (1) email xác nhận đơn ngay sau khi thanh toán, và (2) SMS cập nhật khi kiện hàng "đang giao" và "đã giao".

Điều gì sai khi bạn gửi quá sớm (ví dụ, trong trigger DB): bước thanh toán ghi một hàng orders, trigger kích hoạt và gửi email khách, rồi việc capture tiền thất bại sau đó. Giờ bạn có email “Cảm ơn đơn hàng của bạn” cho một đơn không thành thật.

Ngược lại: trạng thái giao hàng chuyển thành "Đang giao", bạn gọi nhà cung cấp SMS, và nhà cung cấp timeout. Bạn không biết nó đã gửi hay chưa. Nếu bạn retry ngay, có nguy cơ gửi hai SMS. Nếu bạn không retry, có nguy cơ không gửi gì.

Luồng an toàn hơn dùng outbox + worker nền. App commit đơn hoặc thay đổi trạng thái, và trong cùng transaction ghi một hàng outbox như “gửi template X tới user Y, kênh SMS, khóa idempotency Z.” Chỉ sau commit worker mới giao tin.

Thời gian đơn giản như sau:

  • Thanh toán thành công, transaction commit, outbox cho email xác nhận được lưu.
  • Worker gửi email, rồi đánh dấu outbox là sent kèm ID tin nhắn nhà cung cấp.
  • Trạng thái giao hàng thay đổi, transaction commit, outbox cho cập nhật SMS được lưu.
  • Nhà cung cấp timeout, worker đánh dấu outbox có thể retry và thử lại sau bằng cùng khóa idempotency.

Khi retry, hàng outbox là nguồn sự thật duy nhất. Bạn không tạo một yêu cầu gửi thứ hai, bạn hoàn tất yêu cầu đầu.

Với support, điều này cũng rõ ràng hơn. Họ có thể thấy tin nhắn bị kẹt ở failed với lỗi cuối (timeout, số sai, email bị chặn), số lần thử đã làm và liệu có an toàn để retry mà không gửi đôi hay không.

Bước tiếp theo: chọn một mô hình và triển khai sạch sẽ

Chọn một mặc định và viết nó ra. Hành vi không nhất quán thường đến từ việc trộn triggers và workers một cách ngẫu nhiên.

Bắt đầu nhỏ với một bảng outbox và một vòng lặp worker. Mục tiêu đầu tiên không phải tốc độ, mà là đúng: lưu những gì bạn định gửi, gửi sau commit, và chỉ đánh dấu đã gửi khi nhà cung cấp xác nhận.

Kế hoạch triển khai đơn giản:

  • Định nghĩa các event (order_paid, ticket_assigned) và kênh có thể dùng.
  • Thêm bảng outbox với event_id, recipient, payload, status, attempts, next_retry_at, sent_at.
  • Xây một worker duy nhất poll các hàng chờ, gửi và cập nhật trạng thái ở một nơi.
  • Thêm idempotency với khóa duy nhất cho mỗi tin nhắn và “không làm gì nếu đã gửi”.
  • Phân loại lỗi thành retryable (timeout, 5xx) và không retryable (số sai, email bị chặn).

Trước khi mở rộng khối lượng, thêm khả năng hiển thị cơ bản. Theo dõi số pending, tỷ lệ lỗi và tuổi của tin pending cũ nhất. Nếu bản tin pending cũ nhất ngày càng lớn, có lẽ worker kẹt, provider outage, hoặc lỗi logic.

Nếu bạn xây trong AppMaster (appmaster.io), mẫu này map rất sạch: mô hình hóa outbox trong Data Designer, ghi thay đổi nghiệp vụ và hàng outbox trong một transaction, rồi chạy logic gửi-và-retry trong một tiến trình nền riêng. Sự tách bạch đó giữ việc gửi thông báo đáng tin ngay cả khi nhà cung cấp hoặc deploy gặp sự cố.

Câu hỏi thường gặp

Should I use triggers or background workers for notifications?

Background worker thường là lựa chọn an toàn hơn vì việc gửi tin nhắn chậm và dễ lỗi, và worker được thiết kế để retry và hiển thị trạng thái. Triggers có thể nhanh, nhưng chúng gắn chặt với transaction hoặc request đã kích hoạt, khiến thất bại và trùng lặp khó xử lý rõ ràng.

Why is it risky to send a notification before the database commit?

Rủi ro là vì ghi vào cơ sở dữ liệu có thể bị rollback. Bạn có thể thông báo người dùng về đơn hàng, thay đổi mật khẩu hoặc thanh toán mà cuối cùng không được commit, và bạn không thể thu hồi một email hay SMS đã gửi đi.

What’s the biggest problem with sending from a database trigger?

Trigger cơ sở dữ liệu chạy trong cùng transaction với thay đổi hàng. Nếu nó gọi nhà cung cấp email/SMS và transaction sau đó thất bại, bạn có thể đã gửi một tin nhắn thực về một thay đổi không được lưu, hoặc transaction có thể bị treo do cuộc gọi ra ngoài chậm.

What is the outbox pattern in plain terms?

Mô hình outbox lưu ý định gửi như một hàng trong cơ sở dữ liệu, trong cùng transaction với thay đổi nghiệp vụ. Sau khi commit, một worker đọc các hàng outbox đang chờ, gửi tin nhắn và đánh dấu là đã gửi, khiến thời điểm gửi và retry an toàn hơn nhiều.

What should I do when an email/SMS provider request times out?

Khi request tới nhà cung cấp timeout, kết quả thực tế thường là “không rõ”, chứ không phải “thất bại”. Hệ thống tốt sẽ ghi lại lần thử, trì hoãn và retry an toàn dùng cùng định danh thông điệp thay vì gửi lại ngay lập tức và có nguy cơ trùng lặp.

How do I prevent duplicate emails or SMS when retries happen?

Dùng idempotency: cấp cho mỗi thông báo một khóa ổn định thể hiện ý nghĩa của tin nhắn (không phải thời điểm bạn thử gửi). Lưu khóa đó trong sổ cái (thường là bảng outbox) và đảm bảo chỉ có một bản ghi hoạt động cho mỗi khóa, để retry hoàn tất cùng một tin nhắn thay vì tạo tin mới.

Which errors should I retry vs treat as permanent?

Retry các lỗi tạm thời như timeout, phản hồi 5xx hoặc giới hạn tần suất (với thời gian chờ). Không retry các lỗi vĩnh viễn như địa chỉ không hợp lệ, số bị chặn hoặc hard bounce; đánh dấu chúng là failed và hiển thị để ai đó sửa dữ liệu thay vì spam retry.

How do background workers handle restarts or crashes mid-send?

Worker nền có thể quét các job bị kẹt ở trạng thái sending quá ngưỡng thời gian hợp lý, chuyển chúng về trạng thái có thể retry và thử lại với backoff. Điều này chỉ an toàn nếu mỗi job ghi rõ trạng thái (số lần thử, timestamps, lỗi gần nhất) và idempotency ngăn gửi trùng.

What job data do I need to make notification delivery observable?

Bạn cần trạng thái rõ ràng để trả lời câu hỏi “có an toàn để retry không?” Lưu các trạng thái như pending, processing, sent, failed, cùng số lần thử và lỗi gần nhất. Điều này giúp support và debug thực tế, và hệ thống phục hồi mà không phải đoán.

How would I implement this pattern in AppMaster?

Mô hình hóa một bảng outbox trong Data Designer, ghi cập nhật nghiệp vụ và hàng outbox trong một transaction, rồi chạy logic gửi và retry trong một tiến trình nền riêng. Giữ một khóa idempotency mỗi thông điệp và ghi lại các lần thử, để deploy, retry và restart worker không tạo trùng lặp.

Dễ dàng bắt đầu
Tạo thứ gì đó tuyệt vời

Thử nghiệm với AppMaster với gói miễn phí.
Khi bạn sẵn sàng, bạn có thể chọn đăng ký phù hợp.

Bắt đầu