Menjalankan evaluasi dokumen teknis berskala besar—seperti verifikasi paper arsitektur komputer atau parsing spesifikasi perangkat keras—menggunakan LLM berhadapan langsung dengan dua limitasi utama: latensi inferensi tinggi (30–120 detik per dokumen) dan biaya token API yang mahal. Kegagalan worker di tengah proses sering memicu eksekusi ulang, melipatgandakan biaya token tanpa hasil nyata.
Untuk mengatasi masalah ini, sistem pemrosesan batch membutuhkan kombinasi mekanisme distributed job leasing dan prompt caching. Pendekatan ini memastikan hanya satu worker yang memproses dokumen pada satu waktu, progres terlindungi dari crash mendadak, serta komputasi redundan dicegah sepenuhnya.
Arsitektur Antrean: Redis Streams vs PostgreSQL Advisory Locks
Dua pendekatan umum untuk mengatur antrean evaluasi batch adalah Redis Streams dan PostgreSQL.
- Redis Streams: Pilihan tepat untuk throughput tinggi (ribuan evaluasi per menit) dengan consumer groups bawaan. State tersimpan in-memory, sehingga membutuhkan persistensi AOF/RDB untuk menghindari data hilang.
- PostgreSQL Advisory Locks: Pilihan ideal jika metadata paper, riwayat evaluasi, dan status pekerjaan sudah berada di PostgreSQL. Menghindari dependensi infrastruktur tambahan dengan memanfaatkan transaction-level atau session-level locks.
Implementasi PostgreSQL menggunakan query FOR UPDATE SKIP LOCKED memberikan mekanisme antrean aman tanpa race condition antar-worker:
-- Mengambil batch evaluasi yang belum diproses tanpa memblokir worker lain
BEGIN;
SELECT id, document_url, prompt_hash
FROM paper_evaluation_jobs
WHERE status = 'pending'
OR (status = 'processing' AND lease_expires_at < NOW())
ORDER BY priority DESC, created_at ASC
LIMIT 1
FOR UPDATE SKIP LOCKED;
UPDATE paper_evaluation_jobs
SET status = 'processing',
worker_id = 'worker-node-04',
lease_expires_at = NOW() + INTERVAL '2 minutes'
WHERE id = :selected_job_id;
COMMIT;Pola Distributed Job Leasing: Penanganan Timeout dan Crash
Inference dokumen panjang rentan terhadap false timeout jika menggunakan static visibility timeout. Apabila timeout diatur 60 detik tetapi LLM membutuhkan 75 detik, antrean akan menganggap worker mati dan melepas job ke worker lain, memicu eksekusi ganda.
Solusinya adalah heartbeat leasing (lease renewal). Worker memegang kunci dengan TTL pendek (misal 30 detik) dan memperpanjang masa aktif kunci secara berkala melalui background thread selama inferensi berlangsung.
import asyncio
import redis.asyncio as redis
async def renew_lease(redis_client: redis.Redis, job_id: str, token: str, interval: int = 15):
"""Perpanjang lease secara periodik selama LLM masih memproses."""
lua_extend_script = """
if redis.call('get', KEYS[1]) == ARGV[1] then
return redis.call('pexpire', KEYS[1], ARGV[2])
else
return 0
end
"""
while True:
await asyncio.sleep(interval)
extended = await redis_client.eval(
lua_extend_script, 1, f"lease:job:{job_id}", token, 30000
)
if not extended:
# Lease telah dicuri atau worker terisolasi dari network
raise RuntimeError(f"Lost lease for job {job_id}. Aborting.")
async def process_llm_eval(redis_client: redis.Redis, job_id: str, token: str, doc_payload: dict):
renew_task = asyncio.create_task(renew_lease(redis_client, job_id, token))
try:
# Panggilan API LLM evaluasi paper kompleks (bisa memakan waktu 30-90 detik)
result = await call_llm_api(doc_payload)
return result
finally:
renew_task.cancel()
try:
await renew_task
except asyncio.CancelledError:
passJika worker mati mendadak (OS kill, OOM, hardware failure), perpanjangan lease berhenti. Kunci kedaluwarsa otomatis dalam 30 detik, memungkinkan worker lain melanjutkan evaluasi tanpa intervensi manual.
Deduplikasi Prompt dan Mitigasi Thundering Herd
Pada pipeline batch, beberapa dokumen identik atau revisi berulang sering di-submit bersamaan. Mengirim prompt mentah ke LLM berulang kali merupakan pemborosan biaya.
1. Hash-Keyed Cache
Hitung SHA-256 dari representasi kanonikal payload: teks dokumen ternormalisasi, schema output, model target, dan system prompt. Gunakan hash ini sebagai kunci cache penyimpanan hasil evaluasi:
cache_key = "llm_eval:" + sha256(f"{model}:{system_prompt}:{normalized_doc_text}".encode()).hexdigest()2. Singleflight / Mutex Locking
Ketika seratus worker memproses paper arsitektur komputer yang sama dan cache masih kosong, seluruh worker berisiko menembak API LLM secara bersamaan (thundering herd). Terapkan acquisition lock pada cache_key sebelum memanggil LLM.
Hanya satu worker yang diizinkan memanggil LLM; worker lain menunggu rilis lock dan langsung membaca output dari cache setelah komputasi selesai.
Komparasi Pola Penyelesaian Masalah
| Tantangan | Pola Tradisional | Distributed Leasing + Cache |
|---|---|---|
| Latensi Eksekusi Panjang | Timeout statis (sering memicu timeout prematur) | Heartbeat leasing dinamis via TTL renewal |
| Worker Crash | Job stuck selamanya atau langsung di-retry | Failover otomatis saat TTL expired tanpa redudansi aktif |
| Duplikasi Payload | Setiap batch job memanggil provider LLM | SHA-256 canonical cache + singleflight lock |
| Biaya Kegagalan | Bayar token berulang per retry | Token dihitung sekali, hasil di-cache secara permanen |
Checklist Produksi
- Idempotensi Penyimpanan: Pastikan hasil evaluasi disimpan dengan upsert berbasis
job_idatauprompt_hashagar aman jika terjadi retry di batas lease. - Graceful Shutdown: Tangkap sinyal
SIGTERMpada worker container untuk melepaskan lease Redis/advisory lock secara proaktif sebelum proses dihentikan. - Batas Retry Terukur: Sertakan counter percobaan (misal maksimal 3 kali). Jika job gagal karena crash berulang, pindahkan ke Dead Letter Queue (DLQ) untuk audit manual.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!