Memecahkan sinkronisasi cache dan worker queue di SvelteKit Edge

Ketika API SvelteKit dijalankan di lingkungan edge, permintaan biasanya menjangkau cache lokal atau Redis untuk menghindari latency dan beban berlebih ke data source primer. Namun, saat ada job yang diproses lewat worker queue, cache bisa menjadi stale atau job yang sama dijalankan berganda. Artikel ini langsung menjawab cara menyinkronkan cache dengan worker queue: kita membagi alur menjadi edge handler yang baca cache, push job ke queue, lalu worker menyelesaikan job dengan strategi invalidasi dan penguncian sederhana. Pendekatan ini menjaga konsistensi sementara tetap menjaga respons cepat.

Arsitektur sinkronisasi cache dan worker queue

Arsitektur praktis mencakup tiga komponen:

  • Edge API SvelteKit (misal di Vercel atau Cloudflare) bertugas merespons request, membaca cache, dan mengirim job.
  • Redis atau cache lokal menjadi lapisan cepat untuk data yang sering dibaca; juga menyimpan status job dan lock sederhana.
  • Worker queue (bisa berupa worker Cloudflare, Deno, atau proses Node terpisah) mengeksekusi tugas background dan memperbarui cache saat selesai.

Alur konkret: request masuk ke SvelteKit, memeriksa cache, jika data tidak tersedia (miss) maka job dikirim ke queue dan client mendapat respon sementara (misal 202). Worker mengambil job, menulis ke data utama, dan invalidasi cache agar edge API bisa refresh data berikutnya.

Flow request-to-worker dengan cache check

Contoh endpoint SvelteKit POST /api/process:

export async function post({ request, env }) {
  const payload = await request.json();
  const cacheKey = `document:${payload.id}`;
  const cached = await env.REDIS.get(cacheKey);

  if (cached) {
    return new Response(cached, { status: 200 });
  }

  const jobId = `job:${payload.id}`;
  const lock = await env.REDIS.set(jobId, 'locked', { nx: true, ex: 60 });
  if (!lock) {
    return new Response('Job sedang diproses', { status: 202 });
  }

  await env.WORKER_QUEUE.add('process', payload);
  return new Response('Dalam antrean', { status: 202 });
}

Penting: lock sederhana (SETNX + TTL) mencegah duplikasi job. Jika lock gagal, kita bisa mengembalikan 202 dengan pesan bahwa job sudah dijalankan. Cache hit langsung mengembalikan data, sehingga respons edge tetap cepat.

Worker queue, pembaruan data, dan invalidasi cache

Worker yang mengambil job harus memastikan urutan operasi berikut:

  1. Ambil job dari queue (misal Redis Stream, BullMQ, atau platform edge worker queue).
  2. Eksekusi update ke sumber data utama (misal database SQL, API internal).
  3. Update cache lokal/Redis dengan data terbaru.
  4. Hapus lock dan catat status job (set status=done) agar edge API tahu job selesai.

Contoh pseudo worker:

const job = await queue.getNext();
const result = await updateDatabase(job.payload);
await redis.set(`document:${job.payload.id}`, JSON.stringify(result), { ex: 300 });
await redis.del(`job:${job.payload.id}`);
await redis.set(`job:${job.payload.id}:status`, 'done', { ex: 60 });
queue.ack(job.id);

Repositori cache bisa diatur dengan TTL agar tidak selamanya stale. Worker yang sukses harus memastikan invalidasi atau refresh cache, bukan menunggu edge API menghapusnya. Ini mencegah cache yang usang saat job sudah selesai.

Strategi penguncian dan penanganan kesalahan

Penguncian sederhana (SETNX + TTL) menghindari job ganda. Namun, perlu juga menangani situasi seperti worker crash:

  • Simpan status job dengan TTL; setelah habis, edge API bisa mencoba mengirim ulang job.
  • Gunakan pola lease renewal jika job prosesnya panjang: worker memperbarui TTL lock secara periodik.
  • Monitoring lock yang lama (misal lewat grafana alert) membantu mendeteksi deadlock.

Jangan lupa membersihkan lock dan status bahkan saat worker gagal: gunakan try/finally atau mekanisme dead-letter queue.

Cache invalidation setelah job selesai

Ketika worker sudah menyelesaikan job, edge API harus melihat status terbaru saat request berikutnya. Strategi yang bisa dipakai:

  • Cache aside: Edge API baca cache; jika tidak ada, job dikirim. Worker menyimpan hasil lalu cache tersedia untuk permintaan berikutnya.
  • Event-driven invalidation: Worker mengirim event (misal via Redis Pub/Sub) agar edge API atau CDN menghapus cache terkait.
  • Versioned keys: Sertakan versi atau timestamp di key cache sehingga edge API bisa memeriksa apakah cache terkini.

Ingat: cache harus memiliki TTL agar stale data tidak bertahan bila worker gagal menulis ulang.

Observability dan monitoring

Langkah operational yang penting:

  • Latency tracing: instrumentasi request edge API hingga worker selesai (OpenTelemetry/Datadog) untuk tahu apakah jeda karena queue atau cache miss.
  • Status queue: Pantau panjang queue dan umur job tertua; jika terus meningkat, mungkin worker tidak cukup atau deadlock muncul.
  • Cache hit/miss ratio: Catat berapa banyak request memicu job. Rasio rendah artinya cache efektif, sebaliknya bisa jadi cache tidak diinvalidate dengan benar.
  • Lock age metrics: Alert jika lock tertentu bertahan > TTL. Itu bisa menandakan worker crash atau retry loop.

Debugging tip: saat job tidak pernah selesai, cek log worker untuk error update database, lalu periksa apakah lock dibersihkan. Pastikan worker overflow tidak membuat job terjebak; mekanisme dead-letter queue membantu memisahkan job bermasalah.

Kesimpulan

Sinkronisasi cache dan worker queue di SvelteKit edge membutuhkan aliran yang jelas: edge API cek cache dan kunci job sebelum push ke queue, worker menyelesaikan pekerjaan dan invalidasi cache, serta observability yang memantau latency, lock, dan status queue. Dengan pola ini, API edge tetap responsif tanpa kehilangan konsistensi data.