pg_notify และ Event Outbox
ภาพรวม
Domain นี้มีตารางเดียวคือ event_outbox ซึ่งไม่ได้ประกาศไว้ใน Prisma schema แต่สร้างด้วย
manual SQL (manual-sql/5.sql) ทำหน้าที่เป็น outbox สำรองของกลไก pg_notify — ทุกครั้งที่
trigger function ยิง pg_notify จะ insert payload เดียวกันลงตารางนี้ด้วย เพื่อให้ consumer
ที่หลุดการเชื่อมต่อไปสามารถ catch-up ย้อนหลังได้ (pg_notify ไม่เก็บข้อความที่ส่งไปแล้ว)
ตาราง event_outbox
| Column | Type | Nullable | Default | คำอธิบาย |
|---|---|---|---|---|
id | BIGSERIAL | NO | nextval(...) | Primary key |
channel | VARCHAR(100) | NO | - | ชื่อ channel ของ pg_notify ที่ event นี้ถูกส่งไป |
payload | JSONB | NO | - | payload ของ event (เนื้อหาเดียวกับที่ส่งผ่าน pg_notify) |
created_at | TIMESTAMPTZ | NO | NOW() | วันเวลาที่ event ถูกบันทึกลง outbox |
processed | BOOLEAN | NO | FALSE | consumer ประมวลผล event นี้แล้วหรือยัง |
processed_at | TIMESTAMPTZ | YES | - | วันเวลาที่ event ถูกประมวลผลเสร็จ |
หมายเหตุ
pg_notify channel ทั้งหมดในระบบ
| Channel | Trigger function | ตารางต้นทาง | เงื่อนไขที่ยิง |
|---|---|---|---|
attribute_changed | notify_attribute_change() | line_user | มีการเปลี่ยนค่าใน column หลัก (display_name, firstname, lastname, email, mobile_no, language, follow) หรือ key ใด ๆ ใน custom_attribute |
friend_track_event_inserted | notify_friend_track_event_insert() | friend_track_event | มีการ INSERT แถวใหม่ |
form_submitted | notify_form_submitted() | form_submission | is_submitted เปลี่ยนจาก false เป็น true |
campaign_click | notify_campaign_click() | tracking_log | INSERT ที่มี action_type = 'click', content_type = 'campaign' และมี campaign_id กับ line_uid |
Trigger ที่ผูกกับ function เหล่านี้
trg_line_user_attribute_change— AFTER UPDATE ONline_userfriend_track_event_insert_notify— AFTER INSERT ONfriend_track_eventform_submission_notify— AFTER INSERT OR UPDATE ONform_submissiontracking_log_campaign_click_notify— AFTER INSERT ONtracking_log
ข้อสังเกตอื่น ๆ
event_outboxไม่มีอยู่ในprisma/schema.prisma— ถ้าใช้ Prisma migrate ต้องรันmanual-sql/5.sqlแยกต่างหาก- มี partial index 2 ตัวเพื่อรองรับรูปแบบการใช้งานหลัก:
idx_event_outbox_catchupบนcreated_atโดยกรองWHERE processed = FALSE— ใช้ดึง event ที่ยังไม่ถูกประมวลผลตอน consumer กลับมาเชื่อมต่อidx_event_outbox_cleanupบนprocessed_atโดยกรองWHERE processed = TRUE— ใช้ลบ event เก่าที่ประมวลผลไปแล้ว
notify_attribute_change()จะข้ามการทำงานทั้งหมดเมื่อ session ตั้งค่าapp.skip_triggers = 'true'(ใช้กับงาน bulk update และเป็น transaction-scoped จึงปลอดภัย ในระบบ multi-tenant)notify_form_submitted()ต้อง JOINform_builderและline_oaเพื่อหาlineOaIdและorganizationIdก่อนประกอบ payload เพราะform_submissionไม่ได้เก็บสองค่านี้ไว้- payload ทั้งหมดถูกสร้างด้วย
json_build_object(...)::textแล้วแปลงเป็นjsonbตอน insert ลง outbox ดังนั้นค่าในpayloadจึงตรงกับที่ส่งผ่านpg_notifyทุกประการ