LOVEREC · INCIDENT SUMMARY · LRCC-2417 · Production Notification Bug
🇻🇳 Tiếng Việt
P0 · High Priority LRCC-2417 Production Reporter: hideyuki yamanaka (khách hàng) | Comtor (cầu nối VN-JP): nhan.ngo

Sự cố notification production
Diễn biến từ khiếu nại KH tới fix UAT

Báo cáo tổng hợp diễn biến sự cố từ khi khách hàng log ticket ngày 2026-05-12 đến hiện tại 2026-05-21. Bao gồm timeline điều tra, các hướng đi sai, root cause được xác định, fix đã apply trên UAT, và kế hoạch xử lý tận gốc.

9
Ngày từ khi log bug tới fix verified
2
Rounds investigation (1 fail, 1 success)
10k
Follower test thành công trên UAT
~10p
Thời gian gửi hết email cho 10k
01 / Bối cảnh

Khiếu nại của khách hàng

Khách hàng Yamanaka log ticket LRCC-2417 ngày 2026-05-12, gộp 2 issue notification phát hiện trên production.

Issue A End-user feedback

Notification "WAVE video update" lặp bất thường

End-user orthodox_paradox@icloud.com phản ánh: notification về creator "れちゃん" cập nhật WAVE video xuất hiện với số lần bất thường trong thanh thông báo LOVEREC. Khả năng bug, hoặc third-party thao tác xấu.

→ Yêu cầu: verify fact-finding sự thật, đếm số lần notification thực sự được gửi.

Issue B Khách hàng tự phát hiện

Email gửi nhưng in-app notification missing

Khách hàng Yamanaka tự kiểm tra account @pz9ve9Zyd6 và phát hiện: email notification đã được gửi, nhưng in-app notification không xuất hiện. Theo spec, 2 kênh này phải đi chung 1 trigger.

→ Yêu cầu: tìm root cause spec violation này.

📋 Tóm tắt yêu cầu khách hàng

Khách dùng từ "本番環境のクレーム" (complaint trên production environment) → SLA cao, ưu tiên xử lý nhanh. Yêu cầu cụ thể: fact-finding cho Issue A + xác định root cause Issue B, cả 2 cùng 1 ticket.

02 / Timeline điều tra

Diễn biến từng bước

Từ ngày khách hàng log bug tới khi fix được apply trên UAT.

2026-05-12 13:54 (UTC)
Khách hàng Yamanaka log ticket LRCC-2417 với priority HIGH
Ticket gộp Issue A (end-user complaint về notification lặp bất thường) và Issue B (email-arrives-but-in-app-missing self-discovery). Yêu cầu fact-finding + root cause analysis. Environment: 本番 (production).
2026-05-13 02:07
Comtor (nhan.ngo) phản hồi khách hàng — acknowledge ticket
Comtor là cầu nối giao tiếp giữa khách hàng Nhật và đội phát triển VN. Comtor reply trên ticket Backlog acknowledge đã nhận yêu cầu, đồng thời relay yêu cầu sang đội phát triển VN để bắt đầu investigation.
2026-05-13 11:28
Khách hàng Yamanaka follow up — nhấn mạnh tính khẩn cấp
Yamanaka nhắc lại: "本番環境のクレーム" — complaint trên production, yêu cầu ưu tiên xử lý nhanh.
2026-05-14 06:52
Investigation đi sai hướng — Round 1 kết luận sai
Đội phát triển VN báo cáo round 1 (qua comtor relay lên ticket): screenshot user phuong.nguyen+1userprd cho thấy notification setting = OFF → kết luận đây là nguyên nhân không nhận in-app notification.

⚠ Vấn đề: đội phát triển đang investigate sai user. Account này KHÔNG phải account mà khách hàng đang nói tới.
2026-05-14 06:56
Khách hàng Yamanaka push back — investigation phải restart
Khách hàng chỉ ra account đúng là @pz9ve9Zyd6 (Google login, plan 通常). Trên CMS thấy:
  • User đang follow creator (フォロー中)
  • Các notification khác vẫn về
  • Mismatch CHỈ xảy ra ở subset event này
→ Setting OFF KHÔNG phải nguyên nhân. Investigation phải restart từ đầu.
2026-05-14 → 2026-05-18
Team sửa code dựa trên hypothesis ban đầu — KHÔNG test scale lớn
Sau khi khách hàng push back, đội phát triển điều tra lại + áp dụng các fix dựa trên hypothesis ban đầu (xử lý notification path, dedup, retry logic, v.v.). Code được deploy UAT.

⚠ Sai lầm test strategy: team chỉ verify UAT chạy thành công với data nhỏ (vài chục → vài trăm follower) → kết luận fix OK → close investigation.

Vấn đề: data trên UAT thời điểm đó không có account nào với số lượng follower lớn như PRD. Bug thực sự (root cause tìm ra sau này) chỉ kích hoạt với scale ≥ 5,000 follower → test scale nhỏ KHÔNG reproduce được → bug vẫn nguyên trên PRD.
2026-05-19
KH claim lần nữa — bug manifest rõ trên PRD
Trên PRD, 1 creator publish video với 7,121 follower — workload thực tế vượt scale team từng test UAT. Bug kích hoạt nặng:
  • Creator nhận notification + email bị lặp nhiều lần (gap mỗi lần đúng 5 phút)
  • Toàn bộ 6,699 follower đáng lẽ nhận email — SendGrid Activity = 0
  • ~1,482 follower nhận in-app notification (sau khi tech lead clean DB)
KH claim lần nữa trên ticket. Symptom rõ hơn Issue A/B ban đầu — pattern bug có dấu hiệu rõ ràng liên quan đến scale (workload lớn). Team nhận ra fix tuần trước KHÔNG đủ — phải redo điều tra với scale test đúng cách.
2026-05-20 (hôm qua)
Team triển khai action điều tra trên UAT
Plan để replicate bug có control trên environment safe:
  1. Backup DB UAT, modify data để có account test với 10,000 follower
  2. Adjust hạ tầng UAT (ECS scaling policies, task sizing) giống PRD
  3. Publish video test → monitor logs + AWS CloudWatch metrics
  4. Xác định root cause
  5. Apply fix → retest 10k follower → verify hết bug
2026-05-20 (trong điều tra)
Root cause xác định
Code không xử lý đủ tốt để handle lượng email lớn → khi publish video với nhiều follower, service bị quá tải (RAM/CPU), không thể gửi đủ email.

Đồng thời điều tra cũng phát hiện thêm các vấn đề phụ:
  • Code dùng pattern fire-and-forget — function return trước khi email thực sự được enqueue
  • Tài liệu config auto-scale CPU/RAM threshold 70% quá nhạy với bursty workload
  • Một số dedup logic ở notification path bị disable
→ Tuy nhiên: chỉ cần xử lý 1 phần (root cause chính) cũng đáp ứng được.
2026-05-20 (cuối ngày)
Fix applied + retest UAT thành công
Apply fix code (commit LRC-14126):
  • Chunking DB query: tách query lớn IN([10k IDs]) thành nhiều chunk 500 IDs
  • Limit concurrency: chỉ 20 email enqueue song song mỗi đợt (thay vì 10k cùng lúc)
  • Chunked SQS message: notification SQS message chứa max 50 memberIds
Deploy UAT → publish video test 10k follower → toàn bộ member hợp lệ đã nhận email + notify sau ~10 phút. Bug được break.
2026-05-21 (hôm nay)
Đánh giá kết quả + plan xử lý tận gốc
Đánh giá tổng kết:
  • Auto-scale config hiện tại không hợp lý với bursty workload publish video
  • CPU/RAM allocated cho service xử lý publish video quá thấp để chịu tải peak
  • Có một số code path khác có nguy cơ bug tương tự (chưa phải critical)
→ Team lên plan chi tiết hôm nay để xử lý tận gốc: tune infra + đánh giá lại pattern code khác.
03 / Root cause

Nguyên nhân gốc

Phát hiện trong quá trình replicate trên UAT với 10k follower.

Nguyên nhân chính

Code xử lý gửi email cho follower khi publish video không được thiết kế để handle scale lớn. Khi số lượng follower cao (≥ 5,000):

Các vấn đề phụ phát hiện trong điều tra

Điều tra UAT đồng thời lộ ra nhiều vấn đề khác không trực tiếp gây bug observed, nhưng tiềm ẩn nguy cơ tương tự:

Vấn đềLoạiTác độngTrạng thái
Code fire-and-forget enqueue 10k email không await Code Email bị huỷ khi instance kill FIXED (LRC-14126)
Auto-scale CPU/RAM target 70% quá nhạy với bursty workload Infra Kill task ngay sau burst, mất Promise in-flight PENDING — plan hôm nay
CPU/RAM allocation cho video-service task quá thấp Infra Spike chạm threshold dễ hơn cần thiết PENDING — plan hôm nay
deleteMessageBatch dùng callback-style fire-forget Code SQS retry nếu instance kill trước khi delete confirmed CHƯA FIX — không kích hoạt sau fix #1
UPSERT logic cho PUBLIC_VIDEO_FOR_FOLLOWER bị comment out Code Amplify duplicate khi có retry CHƯA FIX — không kích hoạt sau fix #1
Backend outputObject.forEach(async) race condition Code (backend) Race condition tiềm ẩn, chưa thấy kích hoạt CHƯA FIX — preventive
💡 Quan sát quan trọng — chỉ cần xử lý 1 phần là đủ

Nhiều vấn đề phụ kể trên thực ra chỉ kích hoạt khi vấn đề chính (fire-and-forget + scale) xảy ra. Khi team fix vấn đề chính (chunking + concurrency limit), instance không còn bị kill mid-flight → các vấn đề phụ tự động không còn ảnh hưởng dù code path vẫn nguyên.

→ Team chọn fix targeted (chỉ 1 phần code) thay vì fix tất cả → vẫn đáp ứng được yêu cầu khách hàng (10k follower test pass), giảm risk regression khi deploy nhiều thay đổi cùng lúc.

04 / Fix đã apply

Sửa cái gì trên UAT?

Commit LRC-14126 trên branch UAT — chunking + bounded concurrency.

1️⃣

DB query chunking

Các query với IN([10k IDs]) được tách thành nhiều chunk 500 IDs.

Tránh max_allowed_packet limit, query plan của MySQL tối ưu hơn, latency mỗi query thấp hơn.

2️⃣

Email enqueue concurrency limit

Thay vì fire 10,000 Promise cùng lúc, chỉ 20 song song mỗi đợt, dùng await Promise.all cho từng batch.

Function đợi từng batch enqueue xong rồi mới sang batch tiếp. Không còn fire-and-forget. Smooth CPU load profile.

3️⃣

SQS notification message chunking

Mỗi SQS message chứa max 50 memberIds thay vì 1 message với 10k IDs.

Payload SQS nhỏ hơn nhiều lần, consumer dễ xử lý, ít risk message body limit.

⚙️ Quan trọng: KHÔNG cần auto-scale để hoạt động

Sau fix, test UAT publish video với 10k follower không cần auto-scale vẫn xử lý bình thường trong ~10 phút. CPU/RAM smooth, không spike đột ngột, không cần thêm task. Điều này confirm:

05 / Kết quả test UAT

10k follower test passed

10,000
Follower test trên UAT
100%
Email gửi tới member hợp lệ
~10p
Thời gian xử lý toàn bộ
✅ Kết quả verify
06 / Việc còn lại

Plan xử lý tận gốc

Hôm nay team lên detail plan cho 3 hạng mục.

P1 · Infra Auto-scale tuning

Đánh giá lại config auto-scale

3 scaling policy hiện tại (CPU 70%, RAM 70%, BacklogPerTask 100) quá nhạy với bursty workload. Cần tune:

  • Tăng scale-in cooldown (default 300s → 15-30 phút)
  • Tăng CPU/RAM target threshold (70% → 85%)
  • Review xem có cần SQS BacklogPerTask policy không (có thể duplicate với CPU policy)
P1 · Infra Task sizing

Tăng CPU/RAM allocation cho video-service task

Task hiện tại được cấp tài nguyên thấp. Bursty workload publish video cần more headroom để xử lý smooth. Khuyến nghị:

  • Đo baseline CPU/RAM utilization trong giờ peak vs idle
  • Tăng task definition CPU/Memory với buffer 2× peak observed
  • Test lại bằng load test (vd: publish 5 video với 10k follower liên tiếp)
P2 · Code Optimization

Xử lý CPU bottleneck còn lại — HTML template formatting

Sau fix, bottleneck CPU còn lại chủ yếu là format() HTML template (~50% CPU work khi gửi email burst). Options:

  • SendGrid Dynamic Template — offload template render sang SendGrid, save ~90% CPU. Migrate chỉ template high-volume (publicVideoForSubscribers)
  • HOẶC giữ template trong code + dùng worker_threads cho render
  • HOẶC pre-compile template once, reuse cho từng iteration
07 / Vấn đề khách hàng gốc chưa close

Issue A & B từ ticket gốc

Cần follow-up với khách hàng Yamanaka về 2 issue ban đầu.

Issue A

Notification lặp bất thường (end-user complaint)

Trong quá trình điều tra hôm qua, phát hiện vấn đề duplicate notification ở scale lớn → giải thích được hiện tượng "lặp bất thường" mà end-user phản ánh.

Action: comtor relay tới khách hàng:

  • Root cause đã xác định (scale-related)
  • Fix đã apply trên UAT, test 10k follower pass
  • Plan deploy PRD sau khi hoàn tất plan infra hôm nay
Issue B

Email arrives but in-app missing

Issue B (account @pz9ve9Zyd6) cùng nguyên nhân với bug scale chính: in-app notification path bị kill mid-flight do auto-scale, trong khi email path đôi khi vẫn sống sót (vì 1 Promise duy nhất nhanh hơn 10k Promise burst).

Action: comtor relay tới khách hàng:

  • Spec violation "email arrives but in-app missing" được giải thích bởi root cause này
  • Fix UAT cũng đồng thời resolve Issue B
  • Verify trên UAT bằng test 10k follower confirmed cả 2 kênh nhận đủ
📝 Đề xuất communication tới khách hàng (qua comtor)

Khi report lại cho khách hàng Yamanaka (qua comtor), focus 3 điểm:

  1. Acknowledge 2 sai lầm trong quá trình điều tra:
    • Round 1 (5/14): investigate sai account → khách hàng push back, đã reset
    • Round 2 (5/14-5/18): sửa code dựa hypothesis ban đầu nhưng chỉ test scale nhỏ trên UAT → fix không cover được scale lớn → KH claim lần nữa 5/19
  2. Root cause đã xác định chính xác lần này: bug scale-dependent, kích hoạt khi follower ≥ 5k. Không phải user setting hay third-party abuse.
  3. Fix verify với 10k follower trên UAT — strategy test scale lớn được áp dụng để tránh lặp lại sai lầm 5/14-5/18. Sẵn sàng deploy PRD sau khi hoàn tất plan infra hôm nay.
  4. Cam kết quality: review process cải thiện — mọi fix bug scale-related sau này sẽ bắt buộc test với data UAT ≥ scale PRD trước khi đóng ticket.

Có thể đính kèm timeline + result test UAT làm evidence.

08 / Lesson learned

Bài học rút ra

🔍

Verify đúng đối tượng investigate trước khi kết luận

Round 1 (5/14) đi sai hướng do investigate sai account → khách hàng push back → mất 5 ngày trước khi tìm đúng vấn đề. Lesson: comtor cần confirm rõ với khách hàng về thông tin user/account (forward đầy đủ context cho đội phát triển VN) trước khi deep dive technical.

📊

Test với scale gần production — bài học đắt nhất

Trong khoảng 5/14 — 5/18, team đã sửa code và verify UAT thành công nhưng chỉ test với data nhỏ (vài trăm follower). Bug thực sự chỉ kích hoạt khi scale ≥ 5k follower → fix không đủ → KH claim lần nữa ngày 5/19.

Hậu quả: mất thêm 1 tuần investigation, KH mất niềm tin, ticket bị reopened. UAT cần có data scale tương đương PRD (vd: account test với 10k+ follower bot accounts) để catch scale-dependent bug.

🎯

Fix targeted, không over-fix

Điều tra phát hiện 6+ vấn đề, nhưng chỉ cần fix 1 vấn đề chính là đáp ứng. Tránh deploy nhiều thay đổi cùng lúc → giảm risk regression.

⚙️

Code pattern + Infra config phải align với nhau

Code fire-and-forget + auto-scale aggressive = combo nguy hiểm. Bài học: review pattern code khi setup auto-scale, hoặc ngược lại.