57 lines
3.3 KiB
Markdown
57 lines
3.3 KiB
Markdown
# Spec: Perbaiki Delay Attachment 162s→<20s (GMW AI Analysis)
|
||||
|
|
|
|||
|
|
Tanggal: 2026-08-24 · Repo `~/GMW` · Service discord-gateway
|
|||
|
|
|
|||
|
|
## Evidence (audit produksi)
|
|||
|
|
|
|||
|
|
Klaster pesan attachment delay ~330–400 detik. Trace pesan `1541417073245290638` (.gif):
|
|||
|
|
19:01:08 dibuat → 19:01:09 batch incomplete → fan-out individual → **guard upload-pending
|
|||
|
|
mengembalikan `results:[]`** → diperalakukan sukses (`complete ... (undefined)`) → row
|
|||
|
|
tertahan `ai_status='processing'` **tanpa penanggung jawab** → 19:06:12 cleanup mengembalikan
|
|||
|
|
ke `pending` (tepat 300s) → baru dianalisis. Plus vision gagal 3× utk GIF besar
|
|||
|
|
("Stream ended before producing a non-ping SSE event") → degradasi teks.
|
|||
|
|
|
|||
|
|
## Root causes
|
|||
|
|
|
|||
|
|
- **A (fatal)**: `individualFallbackProcessor.processIndividualFallback` memperlakukan
|
|||
|
|
`ok:true + results:[]` sebagai sukses. Race-guard upload di `ai-analysis-worker.processIndividual`
|
|||
|
|
sengaja balik `results:[]` (desain lama) → pesan yatim `processing` sampai cleanup 300s.
|
|||
|
|
- **B**: `llmVision` hanya mencoba `stream:true`; kegagalan SSE truncation pada gambar besar
|
|||
|
|
= 3 retry sia-sia (semua jalur sama) → bukti media hilang.
|
|||
|
|
- **C**: safety-net cleanup 300s terlalu lambat sbg satu-satunya pemulih `processing`.
|
|||
|
|
|
|||
|
|
## Fix
|
|||
|
|
|
|||
|
|
1. **F1 — sinyal eksplisit upload-pending**: `IndividualOkResponse` + field opsional
|
|||
|
|
`uploadPending?: boolean`. Worker set `uploadPending:true` saat race guard kena.
|
|||
|
|
2. **F2 — processor menangani 3 kondisi** via helper murni baru
|
|||
|
|
`classifyIndividualWorkerResult(result): "success" | "upload_pending" | "incomplete" | "error"`
|
|||
|
|
(modul baru `fallbackResultClassifier.ts`, zero-dep agar mudah dites):
|
|||
|
|
- `upload_pending` → tulis ulang row ke `pending` (pola sama dgn revert apiFailed di
|
|||
|
|
batchProcessor) + broadcast + **re-schedule analisis percakapan segera**
|
|||
|
|
(dynamic import batchScheduler, pola anti-siklus yg sudah ada) → retry dalam ~250ms
|
|||
|
|
begitu upload beres. Bukan error, tidak naikkan CB counter.
|
|||
|
|
- `incomplete` (flags analysis_incomplete) → perilaku lama (exhausted path).
|
|||
|
|
- `error` / `results kosong tanpa penjelasan` → throw transien (retry oleh recovery),
|
|||
|
|
BUKAN sukses palsu. Log "(undefined)" hilang.
|
|||
|
|
3. **F3 — vision non-stream fallback**: di `llmVision`, jika error match
|
|||
|
|
`/Stream ended before producing a non-ping SSE|stream ended/i` → coba SEKALI lagi dengan
|
|||
|
|
`stream:false` (router agregasi penuh; timeout tetap 60s). Konversi hard-fail jadi sukses.
|
|||
|
|
4. **F4 — turunkan safety net**: default `revertStuckProcessingMessages` 300000 → 120000 ms.
|
|||
|
|
|
|||
|
|
## File disentuh
|
|||
|
|
|
|||
|
|
- `src/modules/ai-moderation/fallbackResultClassifier.ts` (BARU, pure)
|
|||
|
|
- `src/modules/ai-moderation/ai-analysis-worker.ts` (tipe + set flag uploadPending)
|
|||
|
|
- `src/modules/ai-moderation/individualFallbackProcessor.ts` (konsumsi classifier + reschedule)
|
|||
|
|
- `src/modules/ai-moderation/llmClient.ts` (fallback non-stream di llmVision)
|
|||
|
|
- `src/modules/message-capture/messagesCleanup.ts` (default 120s)
|
|||
|
|
|
|||
|
|
## Verifikasi
|
|||
|
|
|
|||
|
|
- Test baru `tests/fallbackResultClassifier.test.ts` (4 klasifikasi + edge kosong).
|
|||
|
|
- Gate: tsc --noEmit, biome error-level, vitest run semua hijau.
|
|||
|
|
- Deploy GHA sukses; pasca-deploy: pesan attachment baru p50 < 20s
|
|||
|
|
(`SELECT percentile_cont(0.5) ... WHERE metadata attachments>0 AND created_at > deploy`),
|
|||
|
|
tidak ada lagi "complete ... (undefined)".
|