Worker queue cache TTS adalah tantangan utama saat menjalankan Kokoro TTS lokal yang harus bersaing dengan batasan CPU. Artikel ini langsung membahas solusi teknis: bagaimana dispatcher, worker, dan cache terkoordinasi untuk mencegah duplikasi, menjaga latency, dan menangani lonjakan beban tanpa bergantung pada GPU.

1. Arsitektur Kokoro TTS untuk CPU-Friendly Queue

Desain Kokoro TTS harus membagi tugas antara dispatcher yang menerima permintaan, queue terkelola, dan worker yang mengkonsumsi job dengan kontrol TTL cache. Dispatcher mencatat metadata job (teks, model, opsi) lalu menulis ke queue Redis/priority queue lokal, dilengkapi metadata dedupe seperti fingerprint hash.

Worker menarik job satu per satu, memeriksa cache hasil percakapan, dan mengeksekusi pipeline audio. Penggunaan CPU-intensive dilakukan secara batch kecil agar tidak menyumbat scheduler sistem. Pastikan worker berjalan dengan cgroup atau nice adjustment agar tidak mengganggu proses sistem lain.

2. Dispatcher, Queue, dan Locking/Dedupe

Dispatcher harus mengunci job sejenak untuk menghindari enqueuing ganda, misalnya dengan Redis SETNX:

if redis.setnx("tts:lock:" + fingerprint, job_id):
    redis.expire("tts:lock:" + fingerprint, 60)
    enqueue(job)
else:
    log("Job duplikat, menggunakan cache atau menunggu")

Fingerprint adalah hash dari teks dan parameter model; ini memudahkan dedupe sebelum masuk worker. Job dengan fingerprint yang sama hanya diproses ulang jika hasil cache sudah kedaluwarsa. Kunci lock ditempatkan dengan TTL untuk menghindari deadlock jika dispatcher crash.

Queue bisa berupa sorted set yang menyisipkan timestamp target dan prioritas. Worker mem-poll queue sesuai head dan menangani backpressure dengan menolak job baru saat antrean terlalu panjang, misalnya dengan tingkatkan delay atau memberi respons 429 ke pemanggil.

3. TTL Cache, Konsistensi, dan Cache-First Flow

Cache menyimpan output audio (atau metadata pointer ke file audio) dan TTL pendek, misalnya 5-10 menit, disesuaikan dengan frekuensi reuse. Sebelum job diproses, worker memeriksa cache untuk fingerprint. Bila tersedia dan metadata sinkron, worker langsung mengembalikan URI audio tanpa menghitung ulang.

Untuk menjaga konsistensi, cache hanya dikosongkan oleh worker saat job selesai sukses. Jika worker crash, TTL kunci akan kedaluwarsa, tapi hasil partial tidak dikomit ke cache. Gunakan pola last-write-wins: worker menulis hasil ke cache hanya setelah proses audio selesai.

4. Retry, Backpressure, dan Job Stuck Detection

Worker harus mengimplementasikan retry terbatas (misalnya 3 kali) dengan exponential backoff agar node tetap responsif. Job stuck dapat terdeteksi dengan memonitor durasi pemrosesan: jika job berjalan lebih lama dari ambang (misal 60 detik), worker menandai sebagai stuck agar dispatcher bisa memperbarui status dan melakukan fallback. Fallback bisa berupa pengembalian pesan error atau delegasi ke worker cadangan.

Backpressure pada dispatcher dilakukan dengan memantau panjang queue atau latensi respon. Saat queue mendekati limit, dispatcher bisa menolak request baru sementara worker menyelesaikan backlog, atau menambahkan delay respons terhadap client long polling.

5. Cache Eviction dan Handling Load Tinggi

Cache dengan TTL pendek harus dikombinasikan LRU/size limit agar tidak menghabiskan memori. Saat load tinggi, worker dapat mengaktifkan mode cache-only untuk memeriksa kembali fingerprint lebih sering daripada memproses ulang audio. Ini mengurangi beban CPU karena banyak job direply dari cache.

Selain itu, ada strategi batch dedupe: worker menggabungkan job yang masuk dalam jendela waktu singkat dengan fingerprint yang sama menjadi satu eksekusi. Dispatcher dapat menunggu coalescing window sebelum menambahkan job ke queue untuk mengurangi duplikasi pemrosesan.

6. Observabilitas dan Monitoring Latency

Observabilitas meliputi metrik queue depth, latency dari enqueue ke hasil, time-to-lock, dan cache hit ratio. Gunakan histogram (misal Prometheus) untuk memantau distribusi latency. Alur yang ideal: dispatcher mendorong job ke queue, worker mengambil, cache hit, langsung respons. Perbedaan nyata antara latency cache hit dan compute hit harus menjadi alert threshold.

Logging harus mencatat fingerprint, job_id, duration, cache status, serta alasan retry. Dengan tracing distributed, Anda dapat melihat apakah latency tinggi disebabkan oleh queue backlog, proses TTS atau penulisan cache.

7. Strategi Operasional dan Observabilitas

  • Deteksi Job Stuck: Worker menulis heartbeat periodik saat memproses. Jika heartbeat tidak diperbarui, job dianggap stuck dan di-requeue setelah cleanup kunci.
  • Fallback: Ketika worker gagal setelah retry, dispatcher mengembalikan error terperinci dan mengaktifkan mode graceful degradation seperti menurunkan sample rate agar CPU turun.
  • Monitoring: Dashboard harus menampilkan cache hit ratio, retry count, job stuck rate, dan latency downstream. Tambahkan alert ketika queue depth melebihi threshold atau cache hit turun drastis.
  • Alert TTS: Gunakan synthetic check untuk memvalidasi pipeline: kirim teks dummy, pastikan audio di-cache dalam batas waktu tertentu.

Penutup

Optimasi worker queue dan cache Kokoro TTS lokal menuntut pendekatan terintegrasi—lock/dedupe untuk mencegah duplikasi, cache TTL untuk mengurangi CPU, retry/backpressure untuk kestabilan, serta monitoring latency untuk response cepat. Dengan arsitektur pipeline terstruktur, implementasi kode berhati-hati, dan operasi terpantau, TTS lokal tetap responsif meskipun sumber daya terbatas.