Skip to main content

การประมวลผล LINE Webhook

ภาพรวม

เมื่อผู้ใช้ทักแชท กดติดตาม เลิกติดตาม หรือกดปุ่ม postback บน LINE ระบบจะได้รับ webhook เข้ามาที่ line-management-webhook-go ซึ่งทำหน้าที่ตรวจสอบเบื้องต้นแล้วส่งเข้าคิว line_webhook ทันที การประมวลผลจริงทั้งหมดเกิดขึ้นที่ worker ตัวนี้ จึงถือได้ว่าเป็น จุดเข้าหลักของทุก interaction ที่มาจากผู้ใช้

ความรับผิดชอบของงานนี้มี 5 ส่วน คือ ตรวจลายเซ็น resolve ว่าเป็น OA ใด อุ่น cache ให้ edge upsert แถว line_user และกระจาย event แต่ละตัวไปยังคิวหรือฟีเจอร์ปลายทาง

Business Flow

  1. รับ payload ที่ประกอบด้วย webhookId, headers และ body โดย body คือ LINE webhook request แบบดิบ

  2. อ่าน header x-line-signature หากไม่มีจะคืนค่า error ทำให้ข้อความถูก nack และไหลลง DLQ

  3. getLineOAByWebhookId(webhookId) resolve หา OA ที่เกี่ยวข้อง โดยมี Redis cache ช่วยลดภาระฐานข้อมูล

  4. ตรวจลายเซ็นด้วยการคำนวณ HMAC-SHA256 บน body ด้วย oa.channelSecretId แล้วเข้ารหัส base64 เทียบกับค่าใน header หากไม่ตรงจะคืนค่า error และข้อความไหลลง DLQ

  5. อุ่น cache แบบ best-effort คือหากล้มเหลวก็ไม่กระทบงานหลัก โดยเขียน Redis hash ที่ key webhook_config:<webhookId> เก็บ lineOaId, forwardWebhookUrl และค่าตั้งค่า mbox ทั้งชุด (สถานะเปิดใช้งาน คำสำคัญ และข้อความ greeting / warning / end / timeout) ตั้ง TTL ไว้ 1 ชั่วโมง พร้อมเขียน mapping mbox_inbox:<inboxId> เพื่อให้ webhook-go อ่าน config ได้เร็วโดยไม่ต้องแตะฐานข้อมูล

  6. ค้นหาหรือสร้างแถว line_user จาก userId ของ event แรก หากยังไม่มีผู้ใช้รายนี้ ระบบจะตรวจ access token ดึงโปรไฟล์จาก LINE แล้วเรียก createLineUser

  7. วนกระจาย event ทุกตัวตามชนิด

    ข้อความตัวอักษร — routing ตามค่า line_oa.message_handling_config.priority

    • auto_response_only ซึ่งเป็นค่าเริ่มต้น จะ publish เข้าคิว line_auto_response
    • ai_classifier_only จะ publish เข้าคิว message_received_trigger
    • auto_response_first จะ publish เข้าคิว line_auto_response พร้อมตั้งค่า fallbackToAi เป็น true

    ข้อความพิเศษ

    • ข้อความ member จะ publish เข้าคิว line_change_richmenu ชนิด member เพื่อเปลี่ยน rich menu เป็นเมนูสมาชิก
    • ข้อความ guest จะเปลี่ยนค่า user_type เป็น guest

    ทุกกรณีของ event ชนิดข้อความจะอัปเดต last_activity_type เป็น message และ last_activity_status เป็น active

    event ชนิดอื่น

    • postback จะตั้ง logEventType เป็น webhook แล้ว publish payload ทั้งก้อนเข้าคิว tracking_log
    • follow จะรีเฟรชโปรไฟล์ อัปเดตข้อมูลผู้ใช้ ตั้ง rich menu สำหรับสมาชิก แล้วรันกระบวนการ friend-track attribution
    • unfollow จะทำเครื่องหมาย follow เป็น no และบันทึก unfollow event
  8. การ publish ในสายข้อความเป็นแบบ fire-and-forget หากการ publish ล้มเหลวระบบจะบันทึก log แล้วประมวลผล event ถัดไปต่อ ซึ่งตรงกับพฤติกรรมของระบบ NestJS เดิมที่ไม่รอผลลัพธ์

  9. ข้อผิดพลาดในระดับ event จะถูกจัดการโดย handleWebhookError ซึ่งบันทึก log ไว้ ส่วนฟังก์ชัน ProcessLineWebhook จะคืนค่า nil เสมอเพื่อ ack ข้อความ

ไฟล์และฟังก์ชันหลัก

  • internal/lineoa/webhook.go
    • Service.ProcessLineWebhook(ctx, payload) — entry point
    • warmWebhookConfigCache(), processEvents(), handleMessageEvent(), handleFollowEvent(), handleUnfollowEvent(), runFriendTrackAttribution(), handleWebhookError()
  • internal/lineoa/consumer.goConsumer.HandleLineWebhook ผูกกับคิว line_webhook
  • internal/lineoa/service.gogetLineOAByWebhookId(), findById(), issueAccessToken() และ verifyAccessToken() โดย token ถูก cache ไว้ 1 ชั่วโมงใน Redis key ที่ขึ้นต้นด้วย LINE_OA:
  • internal/lineoa/lineuser.gofindByLineUserId(), createLineUser(), updateLineUser()
  • internal/lineoa/types.goLineForwardWebhookPayload, WebhookEvent และ enum ของชนิด event กับ priority
  • คิวที่เกี่ยวข้อง: consume จาก line_webhook และ publish ไปยัง line_auto_response, message_received_trigger, line_change_richmenu และ tracking_log (runtime profile main)

จุดเชื่อมต่อกับ Service อื่น

  • ต้นทางของงานline-management-webhook-go ซึ่งเป็น endpoint ที่รับ webhook จาก LINE
  • ฐานข้อมูลline_oa (channel secret, access token และ message_handling_config), line_user (find-or-create พร้อมข้อมูลกิจกรรมล่าสุด) รวมถึง friend_track_event และ friend_track_campaign
  • Redis — key กลุ่ม LINE_OA: สำหรับ cache token, webhook_config:<webhookId> และ mbox_inbox:<inboxId>
  • LINE APIGET /v2/bot/profile/{userId} และ OAuth endpoint สำหรับออกและตรวจสอบ channel access token
  • ปลายทางที่ถูกกระตุ้นต่อ — งาน auto response, งาน AI message trigger, งานจัดการ rich menu, งานบันทึก tracking log และงาน friend track