14 ธ.ค. 2567·อ่าน 3 นาที

ระบบแจ้งเตือนหลายช่องทาง: แม่แบบ การลองใหม่ และความชอบผู้ใช้

ออกแบบระบบแจ้งเตือนหลายช่องทางสำหรับอีเมล, SMS และ Telegram ที่มีแม่แบบ, สถานะการส่ง, การลองใหม่ และการตั้งค่าผู้ใช้ให้สอดคล้องกัน

ระบบแจ้งเตือนหลายช่องทาง: แม่แบบ การลองใหม่ และความชอบผู้ใช้

สิ่งที่ระบบแจ้งเตือนแบบรวมช่วยแก้ไขได้

เมื่ออีเมล, SMS และ Telegram ถูกสร้างเป็นฟีเจอร์แยกจากกัน ช่องว่างจะปรากฏอย่างรวดเร็ว การแจ้งเตือน "เดียวกัน" อาจมีถ้อยคำ เวลา และกฎของผู้รับต่างกัน ทีมซัพพอร์ตจึงต้องตามหาความจริงสามเวอร์ชัน: ในผู้ให้บริการอีเมล ในเกตเวย์ SMS และในบันทึกบอท

ระบบแจ้งเตือนหลายช่องทางจึงแก้ปัญหานี้ด้วยการมองการแจ้งเตือนเป็นผลิตภัณฑ์เดียว ไม่ใช่การเชื่อมต่อสามอย่าง เหตุการณ์หนึ่งเกิดขึ้น (รีเซ็ตรหัสผ่าน, ใบแจ้งหนี้ชำระแล้ว, เซิร์ฟเวอร์ล่ม) และระบบตัดสินใจจะส่งอย่างไรข้ามช่องทางโดยอิงจากแม่แบบ ความชอบของผู้ใช้ และกฎการส่ง ข้อความยังสามารถจัดรูปแบบต่างกันตามช่องทางได้ แต่ความหมาย ข้อมูล และการติดตามต้องสอดคล้องกัน

ทีมส่วนใหญ่ต้องการพื้นฐานเดียวกันไม่ว่าจะเริ่มจากช่องทางใด: แม่แบบมีเวอร์ชันและตัวแปร การติดตามสถานะการส่ง ("ส่งแล้ว, ส่งถึงปลายทาง, ล้มเหลว, ทำไม"), นโยบายการลองใหม่และการสำรองที่เหมาะสม, การตั้งค่าผู้ใช้ที่มีการยินยอมและชั่วโมงเงียบ และเส้นทางตรวจสอบเพื่อให้ซัพพอร์ตเห็นสิ่งที่เกิดขึ้นโดยไม่ต้องเดา

ความสำเร็จมักจะเรียบง่ายในแบบที่ดี ข้อความคาดเดาได้: คนที่ถูกต้องได้รับเนื้อหาที่ถูกต้อง ณ เวลาที่เหมาะสม ผ่านช่องทางที่พวกเขาอนุญาต เมื่อมีปัญหา การแก้ปัญหาก็ตรงไปตรงมาจากการที่ทุกความพยายามถูกบันทึกพร้อมสถานะและรหัสเหตุผลที่ชัดเจน

ตัวอย่างเช่นการแจ้งเตือน "การเข้าสู่ระบบใหม่" สร้างครั้งเดียว ใส่ข้อมูลผู้ใช้ อุปกรณ์ และตำแหน่งชุดเดียวกัน แล้วส่งเป็นอีเมลสำหรับรายละเอียด, SMS สำหรับความเร่งด่วน, และ Telegram สำหรับการยืนยันอย่างรวดเร็ว หากผู้ให้บริการ SMS เวลาหมด ระบบจะลองใหม่ตามตาราง บันทึกเวลา timeout และสามารถสำรองไปช่องทางอื่นแทนที่จะทิ้งการแจ้งเตือน

แนวคิดหลักและโมเดลข้อมูลง่าย ๆ

ระบบแจ้งเตือนหลายช่องทางจะจัดการได้เมื่อคุณแยก "เหตุผลที่เราต้องแจ้ง" ออกจาก "วิธีที่เราส่ง" นั่นหมายถึงวัตถุร่วมชุดเล็ก ๆ บวกข้อมูลเฉพาะช่องทางเฉพาะเมื่อจำเป็นจริง ๆ

เริ่มจาก event เหตุการณ์คือทริกเกอร์ที่มีชื่อ เช่น order_shipped หรือ password_reset เก็บชื่อให้สม่ำเสมอ: ตัวพิมพ์เล็ก ขีดล่าง และใช้กาลอดีตเมื่อตรงตาม บริหารเหตุการณ์เป็นสัญญาที่มั่นคงซึ่งแม่แบบและกฎความชอบพึ่งพา

จากเหตุการณ์หนึ่ง สร้างระเบียน notification นี่คือความตั้งใจต่อผู้ใช้: ใครได้รับ อะไรเกิดขึ้น และข้อมูลใดจำเป็นเพื่อเรนเดอร์เนื้อหา (หมายเลขคำสั่ง, วันที่จัดส่ง, รหัสรีเซ็ต) เก็บฟิลด์ร่วมที่นี่ เช่น user_id, event_name, locale, priority, และ scheduled_at

จากนั้นแยกเป็น messages ต่อช่องทาง การแจ้งเตือนหนึ่งรายการอาจสร้าง 0 ถึง 3 ข้อความ (อีเมล, SMS, Telegram) ข้อความเก็บฟิลด์เฉพาะช่องทาง เช่น ปลายทาง (ที่อยู่อีเมล เบอร์โทร chat_id ของ Telegram), template_id และเนื้อหาที่เรนเดอร์แล้ว (หัวเรื่อง/เนื้อหา HTML สำหรับอีเมล ข้อความสั้นสำหรับ SMS)

สุดท้าย ติดตามแต่ละครั้งที่ส่งเป็น delivery attempt ความพยายามรวม provider request_id, เวลาต่าง ๆ, รหัสดีตอบกลับ และสถานะที่ปรับให้เป็นมาตรฐาน นี่คือสิ่งที่คุณตรวจเมื่อผู้ใช้บอกว่า "ฉันไม่ได้รับ"

โมเดลง่าย ๆ มักพอในสี่ตารางหรือคอลเลกชัน:

  • Event (แคตาล็อกชื่อเหตุการณ์ที่อนุญาตและค่าเริ่มต้น)
  • Notification (หนึ่งรายการต่อความตั้งใจของผู้ใช้)
  • Message (หนึ่งรายการต่อช่องทาง)
  • DeliveryAttempt (หนึ่งรายการต่อความพยายาม)

วางแผน idempotency ตั้งแต่ต้น ให้ notification แต่ละรายการมีคีย์เช่น (event_name, user_id, external_ref) เพื่อที่การลองใหม่จากระบบภายนอกจะไม่สร้างสำเนาซ้ำ หากขั้นตอนเวิร์กโฟลว์ทำซ้ำ คีย์ idempotency จะป้องกันไม่ให้ผู้ใช้ได้รับ SMS สองครั้ง

เก็บข้อมูลระยะยาวเฉพาะสิ่งที่คุณต้องใช้เพื่อตรวจสอบ (event, notification, สถานะสุดท้าย, เวลาตราประทับ) เก็บคิวการส่งระยะสั้นและ payload ดิบจากผู้ให้บริการไว้เท่าที่จำเป็นสำหรับการดำเนินงานและแก้ปัญหา

กระบวนการจากต้นจนจบที่ใช้งานได้จริง (ทีละขั้น)

ระบบจะทำงานได้ดีที่สุดเมื่อแยกการ "ตัดสินใจว่าจะส่งอะไร" ออกจากการ "ส่งจริง" นั่นทำให้แอปของคุณเร็วและการจัดการความล้มเหลวง่ายขึ้น

กระบวนการปฏิบัติหน้าตาแบบนี้:

  1. An event producer สร้างคำขอ notification. อาจเป็น "รีเซ็ตรหัสผ่าน", "ใบแจ้งหนี้ชำระแล้ว" หรือ "ตั๋วอัปเดต" คำขอรวม user ID, ประเภทข้อความ และข้อมูลบริบท (หมายเลขคำสั่ง, ยอดเงิน, ชื่อเจ้าหน้าที่สนับสนุน) บันทึกคำขอทันทีเพื่อมีเส้นทางตรวจสอบ

  2. A router โหลดกฎผู้ใช้และข้อความ มันดึงความชอบผู้ใช้ (ช่องทางที่อนุญาต, การยินยอม, ชั่วโมงเงียบ) และกฎข้อความ (เช่น: การแจ้งเตือนด้านความปลอดภัยต้องพยายามส่งอีเมลก่อน) ตัว router ตัดสินแผนช่องทาง เช่น Telegram, แล้ว SMS, แล้วอีเมล

  3. ระบบเข้าคิวงานส่งต่อช่องทางแต่ละรายการ งานแต่ละชิ้นมีคีย์แม่แบบ ช่องทาง และตัวแปร งานเข้าไปที่คิวเพื่อไม่ให้การกระทำของผู้ใช้ถูกบล็อกโดยการส่ง

  4. Worker ของช่องทางส่งผ่านผู้ให้บริการ อีเมลไปยัง SMTP หรือ API อีเมล, SMS ไปยังเกตเวย์ SMS, Telegram ผ่านบอทของคุณ Worker ควรรองรับ idempotency เพื่อให้การลองใหม่ของงานเดิมไม่ส่งซ้ำ

  5. การอัปเดตสถานะไหลกลับมารวมที่เดียว Worker บันทึกสถานะ queued, sent, failed และเมื่อมีข้อมูล available ก็ delivered หากผู้ให้บริการยืนยันเพียง "accepted" ให้บันทึกด้วยและจัดการต่างจาก delivered

  6. Fallback และ retries ทำงานจากสถานะเดียวกัน หาก Telegram ล้มเหลว router (หรือ retry worker) สามารถกำหนดเวลาให้ SMS ถัดไปโดยไม่สูญเสียบริบท

ตัวอย่าง: ผู้ใช้เปลี่ยนรหัสผ่าน backend ของคุณส่งคำขอเดียวพร้อม IP router เห็นว่าผู้ใช้ชอบ Telegram แต่ถูกบล็อกโดยชั่วโมงเงียบตอนกลางคืน จึงตั้งอีเมลให้ตอนนี้และ Telegram ตอนเช้า โดยติดตามทั้งคู่ภายใต้ notification record เดียวกัน

หากคุณกำลังนำไปใช้งานใน AppMaster ให้เก็บตารางคำขอ งาน และสถานะใน Data Designer และแสดงตรรกะการกำหนดเส้นทางและการลองใหม่ใน Business Process Editor โดยให้การส่งเป็นแบบอะซิงโครนัสเพื่อให้ UI ตอบสนอง

โครงสร้างแม่แบบที่ใช้งานได้ข้ามช่องทาง

ระบบแม่แบบที่ดีเริ่มจากแนวคิดเดียว: คุณกำลังแจ้งเตือนเกี่ยวกับเหตุการณ์ ไม่ใช่ "ส่งอีเมล" หรือ "ส่ง SMS" สร้างแม่แบบหนึ่งชุดต่อเหตุการณ์ (Password reset, Order shipped, Payment failed) แล้วเก็บตัวแปรเวอร์ชันช่องทางเฉพาะไว้ภายใต้เหตุการณ์เดียวกัน

รักษาชื่อและตัวแปรให้เหมือนกันข้ามทุกรูปแบบของช่องทาง หากอีเมลใช้ first_name และ order_id SMS และ Telegram ก็ต้องใช้ชื่อตัวแปรเดียวกัน นี่ป้องกันบั๊กที่ข้อความช่องทางหนึ่งแสดงได้แต่ช่องทางอื่นว่างเปล่า

รูปร่างแม่แบบง่าย ๆ ที่ทำซ้ำได้

สำหรับแต่ละเหตุการณ์ กำหนดชุดฟิลด์ขนาดเล็กต่อช่องทาง:

  • Email: subject, preheader (อาจมี), HTML body, text fallback
  • SMS: ข้อความตัวอักษรล้วน
  • Telegram: ข้อความตัวอักษรล้วน และปุ่มหรือเมตาดาต้าสั้น ๆ (ออปชัน)

สิ่งที่เปลี่ยนแปลงได้ตามช่องทางคือรูปแบบ ไม่ใช่ความหมาย

SMS ต้องมีกฎพิเศษเพราะสั้น ตัดสินใจตั้งแต่ต้นเมื่อเนื้อหายาวเกินไป ให้สอดคล้อง: กำหนดขีดจำกัดตัวอักษร เลือกกฎการตัด (ตัดและเติม ... หรือปลดบรรทัดที่เป็นทางเลือกก่อน) หลีกเลี่ยง URL ยาวและเครื่องหมายวรรคตอนเกินจำเป็น และวางการกระทำสำคัญไว้ตอนต้น (รหัส กำหนดเวลา ขั้นตอนต่อไป)

ภาษา (locale) โดยไม่คัดลอกตรรกะธุรกิจ

มองภาษาว่าเป็นพารามิเตอร์ เก็บการแปลต่อเหตุการณ์และช่องทาง แล้วเรนเดอร์ด้วยตัวแปรเดียวกัน ตรรกะ "Order shipped" ยังคงเหมือนเดิม ขณะที่หัวเรื่องและเนื้อหาเปลี่ยนตาม locale

โหมดพรีวิวคุ้มค่ากับการลงทุน เรนเดอร์แม่แบบด้วยตัวอย่างข้อมูล (รวมกรณีขอบเช่นชื่อยาว) เพื่อให้ซัพพอร์ตตรวจสอบอีเมล, SMS และ Telegram ก่อนเปิดใช้จริง

สถานะการส่งที่เชื่อถือได้และดีบักได้

หลีกเลี่ยงเทคนิคัลเดบต์ขณะพัฒนา
ได้แอปที่พร้อมผลิตด้วยซอร์สโค้ดจริงเมื่อเวิร์กโฟลว์ของคุณพร้อม
สร้างโค้ด

การแจ้งเตือนมีประโยชน์ก็ต่อเมื่อคุณสามารถตอบคำถามนี้ได้ในภายหลัง: เกิดอะไรขึ้นกับมัน? ระบบที่ดีจะแยกข้อความที่คุณตั้งใจส่งออกจากแต่ละครั้งที่พยายามส่ง

เริ่มจากชุดสถานะร่วมขนาดเล็กที่มีความหมายเดียวกันข้ามอีเมล, SMS และ Telegram:

  • queued: รับโดยระบบของคุณ รอ worker
  • sending: กำลังพยายามส่ง
  • sent: ส่งไปยัง API ของผู้ให้บริการเรียบร้อย
  • failed: ความพยายามจบลงด้วยความผิดพลาดที่ต้องดำเนินการ
  • delivered: มีหลักฐานว่าไปถึงผู้ใช้แล้ว (เมื่อเป็นไปได้)

เก็บสถานะเหล่านี้บนเรคอร์ดข้อความหลัก แต่ติดตามทุกความพยายามในตารางประวัติ นี่คือสิ่งที่ทำให้การดีบักง่าย: ความพยายามที่ #1 ล้มเหลว (timeout), #2 สำเร็จ, หรือ SMS ส่งได้ในขณะที่อีเมลเด้งต่อเนื่อง

ควรเก็บอะไรต่อความพยายามแต่ละครั้ง

ปรับคำตอบของผู้ให้บริการให้เป็นมาตรฐานเพื่อให้ค้นหาและจัดกลุ่มปัญหาได้แม้ว่าผู้ให้บริการจะใช้คำต่างกัน

  • provider_name และ provider_message_id
  • response_code (โค้ดมาตรฐานเช่น TIMEOUT, INVALID_NUMBER, BOUNCED)
  • raw_provider_code และ raw_error_text (สำหรับกรณีซัพพอร์ต)
  • started_at, finished_at, duration_ms
  • channel (email, sms, telegram) และ destination (มาสก์ส่วนหนึ่ง)

วางแผนสำหรับความสำเร็จแบบบางส่วน การแจ้งเตือนหนึ่งรายการอาจสร้างข้อความสามช่องทางที่แชร์ parent_id และบริบทธุรกิจเดียวกัน (order_id, ticket_id, alert_type) ถ้า SMS ส่งได้แต่เมลล้มเหลว คุณยังต้องการเรื่องราวเต็มที่อยู่ในที่เดียว ไม่ใช่สามเหตุการณ์ที่ไม่เกี่ยวข้อง

"delivered" แท้จริงหมายความว่าอย่างไร

"sent" ไม่เท่ากับ "delivered" สำหรับ Telegram คุณอาจรู้เพียงว่า API ยอมรับข้อความ สำหรับ SMS และอีเมล การส่งมักขึ้นกับ webhook หรือ callback ของผู้ให้บริการ และผู้ให้บริการแต่ละรายมีความน่าเชื่อถือไม่เท่ากัน

กำหนดความหมายของ delivered ต่อช่องทางตั้งแต่ต้น ใช้การยืนยันจาก webhook เมื่อมี มิฉะนั้นให้ถือว่า delivered เป็นไม่ทราบและรายงานเป็น sent แทน นี่ทำให้รายงานซื่อสัตย์และคำตอบของซัพพอร์ตสอดคล้อง

การลองใหม่ การสำรอง และเมื่อจะหยุดลอง

การลองใหม่มักเป็นจุดที่ระบบแจ้งเตือนพลาด รีทรีเร็วเกินไปจะสร้างภาวะพายุ รีทรีตลอดไปจะสร้างความซ้ำซ้อนและปวดหัวให้ซัพพอร์ต เป้าหมายคือ: ลองอีกเมื่อมีโอกาสจริงที่จะสำเร็จ และหยุดเมื่อไม่มี

เริ่มจากการจำแนกความล้มเหลว Timeout จากผู้ให้บริการอีเมล, 502 จากเกตเวย์ SMS, หรือข้อผิดพลาดชั่วคราวของ Telegram มักลองใหม่ได้ ที่อยู่อีเมลผิดรูป, เบอร์โทรไม่ผ่านการตรวจสอบ, หรือ chat ที่บล็อกบอทของคุณไม่ควรลองใหม่ การปฏิบัติเหล่านี้เหมือนกันจะเสียเงินและทำให้ล็อกอัด

แผนการลองใหม่ปฏิบัติได้ควรมีขอบเขตและใช้ backoff:

  • Attempt 1: ส่งทันที
  • Attempt 2: หลัง 30 วินาที
  • Attempt 3: หลัง 2 นาที
  • Attempt 4: หลัง 10 นาที
  • หยุดหลังอายุสูงสุด (ตัวอย่าง: 30-60 นาทีสำหรับการแจ้งเตือนสำคัญ)

การหยุดต้องมีที่จริงจังในโมเดลข้อมูลของคุณ ทำเครื่องหมายข้อความเป็น dead-letter (หรือ failed-permanently) เมื่อเกินขีดจำกัดการลอง เก็บรหัสข้อผิดพลาดสุดท้ายและข้อความสั้น ๆ เพื่อให้ซัพพอร์ตสามารถดำเนินการโดยไม่ต้องเดา

ป้องกันการส่งซ้ำหลังจากสำเร็จด้วย idempotency สร้างคีย์ idempotency ต่อข้อความเชิงตรรกะ (มักเป็น notification_id + user_id + channel) หากผู้ให้บริการตอบช้าและคุณลองใหม่ ความพยายามครั้งที่สองควรถูกจดจำเป็นสำเนาและถูกข้าม

Fallback ควรเป็นไปอย่างมีนัยยะ ไม่ใช่ตื่นตระหนกอัตโนมัติ กำหนดกฎการยกระดับตามความร้ายแรงและเวลา ตัวอย่าง: การรีเซ็ตรหัสผ่านไม่ควร fallback ไปช่องทางอื่น (ความเสี่ยงด้านความเป็นส่วนตัว) แต่เหตุการณ์ฉุกเฉินในโปรดักชันอาจลอง SMS หลังจาก Telegram ล้มเหลวสองครั้ง แล้วค่อยเป็นอีเมลหลัง 10 นาที

ความชอบผู้ใช้ การยินยอม และชั่วโมงเงียบ

จากการสร้างสู่การปรับใช้
ปรับใช้บน AppMaster Cloud หรือคลาวด์ของคุณเองเมื่อพร้อมใช้งาน
ปรับใช้แอป

ระบบจะฉลาดเมื่อมันเคารพผู้คน วิธีง่ายที่สุดคือให้ผู้ใช้เลือกช่องทางต่อประเภทการแจ้งเตือน หลายทีมแบ่งประเภทเป็น security, account, product, marketing เพราะกฎและข้อกำหนดทางกฎหมายต่างกัน

เริ่มจากโมเดลความชอบที่ใช้งานได้แม้ช่องทางไม่พร้อม ผู้ใช้อาจมีอีเมลแต่ไม่มีเบอร์โทร หรือยังไม่ได้เชื่อม Telegram ระบบควรยอมรับสถานะนี้เป็นปกติ ไม่ใช่ข้อผิดพลาด

ระบบมักต้องการชุดฟิลด์กะทัดรัด: ประเภทการแจ้งเตือน (security, marketing, billing), ช่องทางที่อนุญาตต่อประเภท (email, SMS, Telegram), การยินยอมต่อช่องทาง (วันที่/เวลา, แหล่งที่มา, หลักฐานถ้าจำเป็น), เหตุผลการยกเลิกต่อช่องทาง (ผู้ใช้เลือก, อีเมลเด้ง, ตอบว่า "STOP"), และกฎชั่วโมงเงียบ (เริ่ม/สิ้นสุดบวกเขตเวลา ของผู้ใช้)

ชั่วโมงเงียบมักเป็นจุดที่ระบบพัง เก็บเขตเวลาของผู้ใช้ (ไม่ใช่แค่ออฟเซ็ต) เพื่อให้การเปลี่ยนเวลาออมแสงไม่สร้างความประหลาดใจ เมื่อข้อความถูกกำหนดเวลาในชั่วโมงเงียบ อย่าให้มันล้มเหลว ให้มาร์กเป็น deferred และเลือกเวลาที่อนุญาตถัดไป

ค่าเริ่มต้นสำคัญ โดยเฉพาะการแจ้งเตือนสำคัญ แนวทางทั่วไปคือ: การแจ้งเตือนด้านความปลอดภัยไม่สนชั่วโมงเงียบ (แต่ยังเคารพการยกเลิกแบบถาวรเมื่อกฎหมายบังคับ) ในขณะที่การอัปเดตที่ไม่สำคัญให้รอชั่วโมงเช้าและไม่ส่ง SMS เว้นแต่ผู้ใช้เปิดใช้งาน

ตัวอย่าง: การรีเซ็ตรหัสผ่านควรส่งทันทีไปยังช่องทางที่เร็วที่สุดที่อนุญาต แจ้งเตือนสรุปรายสัปดาห์ควรรอจนเช้าและข้าม SMS เว้นแต่ผู้ใช้เปิดใช้โดยเฉพาะ

การปฏิบัติการ: มอนิเตอร์ ล็อก และเวิร์กโฟลว์ซัพพอร์ต

ทำให้สถานะตรวจสอบง่ายสำหรับดีบัก
มอบมุมมองค้นหาได้ให้ทีมซัพพอร์ตเกี่ยวกับทุกความพยายาม สถานะ และรหัสดีเลอร์
สร้างแดชบอร์ด

เมื่อการแจ้งเตือนแตะทั้งอีเมล, SMS และ Telegram ทีมซัพพอร์ตต้องการคำตอบเร็ว: เราส่งมันหรือไม่ มันถึงหรือยัง และอะไรล้มเหลว? ระบบแจ้งเตือนหลายช่องทางควรรู้สึกเหมือนจุดเดียวสำหรับการสืบสวน แม้ว่าจะใช้ผู้ให้บริการหลายรายด้านหลัง

เริ่มจากมุมมองแอดมินง่าย ๆ ที่ทุกคนใช้ได้ ให้ค้นหาได้ตามผู้ใช้ ประเภทเหตุการณ์ สถานะ และช่วงเวลา และแสดงความพยายามล่าสุดขึ้นก่อน แต่ละแถวควรเปิดเผยช่องทาง การตอบของผู้ให้บริการ และการกระทำถัดไปที่วางแผนไว้ (ลองใหม่, fallback, หรือหยุด)

เมตริกที่จับปัญหาได้ตั้งแต่ต้น

การล่มมักไม่แสดงออกมาเป็นข้อผิดพลาดเดียวที่ชัดเจน ติดตามตัวเลขชุดเล็กและทบทวนเป็นประจำ:

  • อัตราการส่งต่อช่องทาง (ข้อความต่อนาที)
  • อัตราความล้มเหลวต่อผู้ให้บริการและรหัสดล้มเหลว
  • อัตราการลองใหม่ (กี่ข้อความที่ต้องพยายามครั้งที่สอง)
  • เวลาในการส่ง (queued ถึง delivered, p50 และ p95)
  • อัตราการทิ้ง (หยุดเพราะความชอบผู้ใช้ การยินยอม หรือเกินลองใหม่)

เชื่อมโยงทุกอย่าง สร้าง correlation ID เมื่อเหตุการณ์เกิด (เช่น "invoice overdue") และส่งต่อผ่านการเทมเพลต คิว การเรียกผู้ให้บริการ และการอัปเดตสถานะ ในล็อก ID นี้จะเป็นเธรดที่ตามเมื่อตัวเหตุการณ์แตกไปหลายช่องทาง

การเล่นซ้ำที่เป็นมิตรต่อซัพพอร์ตโดยไม่สร้างความประหลาดใจ

การเล่นซ้ำจำเป็น แต่ต้องมีการป้องกันไม่ให้สแปมผู้ใช้หรือคิดค่าใช้จ่ายซ้ำ แนวทางการเล่นซ้ำที่ปลอดภัยมักรวมว่า: ส่งซ้ำเฉพาะ message ID ที่ระบุ (ไม่ใช่ทั้งชุดเหตุการณ์), แสดงเวอร์ชันแม่แบบและเนื้อหาที่เรนเดอร์ก่อนส่ง, ต้องระบุเหตุผลและบันทึกผู้ทำการเล่นซ้ำ, บล็อกการเล่นซ้ำหากข้อความถูกส่งถึงแล้วเว้นแต่บังคับจริง ๆ, และบังคับจำกัดอัตราต่อผู้ใช้และต่อช่องทาง

พื้นฐานความปลอดภัยและความเป็นส่วนตัวสำหรับการแจ้งเตือน

ระบบแจ้งเตือนหลายช่องทางแตะข้อมูลส่วนบุคคล (อีเมล, เบอร์โทร, chat ID) และบ่อยครั้งครอบคลุมช่วงเวลาสำคัญ (การเข้าสู่ระบบ การชำระเงิน การสนับสนุน) ถือว่าทุกข้อความและทุกบรรทัดล็อกอาจถูกเห็นในภายหลัง แล้วออกแบบเพื่อจำกัดสิ่งที่เก็บและคนที่เห็น

หลีกเลี่ยงการใส่ข้อมูลละเอียดในแม่แบบเท่าที่เป็นไปได้ แม่แบบควรใช้งานซ้ำได้และเรียบง่าย: "Your code is {{code}}" พอใช้ แต่หลีกเลี่ยงการฝังรายละเอียดบัญชีเต็มรูปแบบ โทเคนยาว หรือสิ่งที่จะใช้ยึดบัญชีได้ หากข้อความต้องมีรหัสใช้ครั้งเดียวหรือโทเคนรีเซ็ต ให้เก็บเฉพาะสิ่งที่ต้องตรวจสอบเช่นแฮชและวันหมดอายุ ไม่เก็บค่าดิบ

เมื่อคุณเก็บหรือบันทึกเหตุการณ์การแจ้งเตือน ให้มาสก์อย่างเข้มงวด เจ้าหน้าที่ซัพพอร์ตมักต้องรู้ว่าโค้ดถูกส่ง ไม่ใช่โค้ดตัวจริงเดียวกัน ใช้กับเบอร์โทรและอีเมลเช่นกัน: เก็บค่าฉบับเต็มสำหรับการส่ง แต่แสดงเวอร์ชันมาสก์ในหน้าจอส่วนใหญ่

การควบคุมขั้นต่ำที่ป้องกันเหตุการณ์ส่วนใหญ่

  • การเข้าถึงตามบทบาท: มีเพียงบทบาทจำนวนน้อยที่ดูเนื้อหาข้อความและข้อมูลผู้รับเต็มรูปแบบ
  • แยกการเข้าถึงสำหรับดีบักและซัพพอร์ตเพื่อลดการรั่วไหลของความเป็นส่วนตัว
  • ปกป้อง endpoint webhook: ใช้การเซ็นต์ callback หรือความลับร่วม ตรวจสอบเวลาส่ง และปฏิเสธแหล่งที่ไม่รู้จัก
  • เข้ารหัสฟิลด์ที่ไวต่อการเก็บ และใช้ TLS ระหว่างทาง
  • กำหนดกฎการเก็บรักษา: เก็บล็อกรายละเอียดระยะสั้น แล้วเก็บเฉพาะสรุปหรือไอดีแฮช

ตัวอย่างปฏิบัติ: หาก SMS รีเซ็ตรหัสผ่านล้มเหลวแล้วคุณสำรองไป Telegram เก็บความพยายาม สถานะผู้ให้บริการ และผู้รับแบบมาสก์ แต่หลีกเลี่ยงการเก็บลิงก์รีเซ็ตในฐานข้อมูลหรือล็อก

สถานการณ์ตัวอย่าง: การแจ้งเตือนหนึ่งรายการ สามช่องทาง ผลลัพธ์จริง

ตั้งค่าแบบแปรผันของแม่แบบอย่างรวดเร็ว
รักษาตัวแปรให้สอดคล้องกันข้ามช่องทางด้วยโครงสร้างแม่แบบต่อเหตุการณ์หนึ่งชุด
สร้างแม่แบบ

ลูกค้า Maya มีการตั้งค่าแจ้งเตือนสองประเภท: การรีเซ็ตรหัสผ่าน และการเข้าสู่ระบบใหม่ เธอชอบ Telegram ก่อน แล้วอีเมล เธออนุญาต SMS เป็น fallback เฉพาะการรีเซ็ตรหัสผ่าน

ค่ำหนึ่ง Maya ขอรีเซ็ตรหัสผ่าน ระบบสร้าง notification record เดียวที่มี ID มั่นคง แล้วขยายเป็นความพยายามต่อช่องทางตามความชอบปัจจุบันของเธอ

สิ่งที่ Maya เห็นเรียบง่าย: ข้อความ Telegram มาถึงในไม่กี่วินาทีพร้อมรหัสรีเซ็ตสั้นและเวลาหมดอายุ ไม่มีอย่างอื่นมาเพราะ Telegram สำเร็จและไม่ต้อง fallback

สิ่งที่ระบบบันทึกรายละเอียดมากขึ้น:

  • Notification: type=PASSWORD_RESET, user_id=Maya, template_version=v4
  • Attempt #1: channel=TELEGRAM, status=SENT แล้ว DELIVERED
  • ไม่มีการสร้างความพยายามอีเมลหรือ SMS (นโยบาย: หยุดหลังสำเร็จครั้งแรก)

ปลายสัปดาห์นั้น มีการแจ้งเตือนการเข้าสู่ระบบใหม่จากอุปกรณ์ใหม่ ความชอบของ Maya สำหรับการแจ้งเตือนการล็อกอินคือ Telegram เท่านั้น ระบบส่ง Telegram แต่ผู้ให้บริการ Telegram คืนข้อผิดพลาดชั่วคราว ระบบลองใหม่สองครั้งด้วย backoff แล้วทำเครื่องหมายความพยายามเป็น FAILED และหยุด (ไม่มี fallback สำหรับประเภทนี้)

สถานการณ์ล้มเหลวจริง: Maya ขอรีเซ็ตรหัสผ่านอีกครั้งขณะเดินทาง Telegram ส่ง แต่การตั้งค่า SMS เป็น fallback หาก Telegram ไม่ส่งภายใน 60 วินาที SMS provider เกิด timeout ระบบบันทึก timeout ลองใหม่หนึ่งครั้ง และความพยายามที่สองสำเร็จ Maya ได้รับรหัสทาง SMS หนึ่งนาทีต่อมา

เมื่อ Maya ติดต่อซัพพอร์ต พวกเขาค้นหาตามผู้ใช้และช่วงเวลา และเห็นประวัติความพยายามทันที: ตราประทับเวลา รหัสดีตอบกลับของผู้ให้บริการ จำนวนการลอง และผลลัพธ์สุดท้าย

เช็คลิสต์ด่วน ข้อผิดพลาดทั่วไป และขั้นตอนต่อไป

ระบบแจ้งเตือนหลายช่องทางง่ายขึ้นเมื่อคุณสามารถตอบสองคำถามได้เร็ว: "เราได้พยายามส่งอะไรบ้างแน่ ๆ?" และ "เกิดอะไรขึ้นหลังจากนั้น?" ใช้เช็คลิสต์นี้ก่อนเพิ่มช่องทางหรือเหตุการณ์ใหม่

เช็คลิสต์ด่วน

  • ชื่อเหตุการณ์ชัดเจนและมีความรับผิดชอบ (เช่น invoice.overdue เป็นของ billing)
  • ตัวแปรแม่แบบกำหนดครั้งเดียว (จำเป็น vs ทางเลือก, ค่าเริ่มต้น, กฎการฟอร์แมต)
  • สถานะตกลงกันล่วงหน้า (created, queued, sent, delivered, failed, suppressed) และความหมายของแต่ละสถานะ
  • ขีดจำกัดการลองใหม่และ backoff (จำนวนครั้งสูงสุด ระยะห่าง กฎการหยุด)
  • กฎการเก็บรักษา (เก็บเนื้อหาข้อความ ผู้ตอบกลับจากผู้ให้บริการ และประวัติสถานะนานเท่าใด)

ถ้าทำได้เพียงอย่างเดียว ให้เขียนความแตกต่างระหว่าง sent และ delivered เป็นคำง่าย ๆ Sent คือสิ่งที่ระบบของคุณทำ Delivered คือสิ่งที่ผู้ให้บริการรายงาน (และอาจล่าช้าหรือขาดหาย) การผสมทั้งสองจะสับสนทีมซัพพอร์ตและผู้มีส่วนได้ส่วนเสีย

ข้อผิดพลาดทั่วไปที่ควรหลีกเลี่ยง

  • ถือว่า sent = สำเร็จ และรายงานอัตราการส่งเกินจริง
  • ให้แม่แบบเฉพาะช่องทางเบี้ยวจนอีเมล SMS และ Telegram ขัดแย้งกัน
  • ลองใหม่โดยไม่มี idempotency ทำให้เกิดข้อความซ้ำเมื่อผู้ให้บริการ timeout แต่ยอมรับในภายหลัง
  • ลองใหม่ตลอดไป เปลี่ยนการล่มชั่วคราวให้เป็นเหตุการณ์ดัง
  • เก็บข้อมูลส่วนบุคคลมากเกินไปในล็อกและประวัติสถานะ "เผื่อไว้"

เริ่มจากเหตุการณ์หนึ่งและช่องทางหลักหนึ่งช่องทาง แล้วเพิ่มช่องทางที่สองเป็น fallback (ไม่ใช่การส่งพร้อมกัน) เมื่อโฟลว์เสถียร ขยายทีละเหตุการณ์ รักษาแม่แบบและตัวแปรให้แชร์กันเพื่อให้ข้อความคงที่

หากคุณต้องการสร้างสิ่งนี้โดยไม่เขียนโค้ดท้งหมด AppMaster (appmaster.io) เหมาะสำหรับส่วนหลัก: ทำโมเดล events, templates, และ delivery attempts ใน Data Designer, ติดตั้งการกำหนดเส้นทางและการลองใหม่ใน Business Process Editor, และเชื่อมต่ออีเมล, SMS, และ Telegram เป็นการผสานงานพร้อมเก็บการติดตามไว้จุดเดียว.

ง่ายต่อการเริ่มต้น
สร้างบางสิ่งที่ น่าทึ่ง

ทดลองกับ AppMaster ด้วยแผนฟรี
เมื่อคุณพร้อม คุณสามารถเลือกการสมัครที่เหมาะสมได้

เริ่ม
ระบบแจ้งเตือนหลายช่องทาง: แม่แบบ การลองใหม่ และความชอบผู้ใช้ | AppMaster