argabayu— Backend & Systems Engineer

queued

Pustaka antrean kerja persistensial untuk Go, tanpa broker eksternal.
Bintang
310
Dependensi
1
Ukuran
2.1k LOC

Antrean kerja yang disimpan di SQLite. Untuk tim yang butuh antrean andal tapi tidak ingin merawat broker terpisah.

Mengapa SQLite

Kebanyakan proyek tidak butuh Kafka. Mereka butuh “jalankan ini nanti, dan jangan hilang kalau proses mati”. SQLite sudah menyelesaikan bagian persistensi dan konkurensi dengan baik, dan satu berkas jauh lebih mudah dicadangkan.

go
q, err := queued.Open("jobs.db")
if err != nil {
	log.Fatal(err)
}

// Enqueue di dalam transaksi yang sama dengan pekerjaan utama,
// sehingga keduanya komit atau gagal bersamaan.
err = q.Enqueue(ctx, tx, "resize", ResizePayload{ID: 42, Width: 800})

Bagian yang menarik adalah Enqueue menerima transaksi. Pekerjaan dan penjadwalannya komit bersamaan — tidak ada keadaan di mana data ada tapi pekerjaannya tidak tercatat.

Konkurensi

Klaim pekerjaan memakai UPDATE ... RETURNING dalam transaksi BEGIN IMMEDIATE, sehingga dua worker tidak pernah mengambil pekerjaan yang sama:

sql
UPDATE jobs
SET state = 'running', claimed_at = ?
WHERE id = (
  SELECT id FROM jobs
  WHERE state = 'pending' AND run_at <= ?
  ORDER BY run_at
  LIMIT 1
)
RETURNING id, kind, payload;

Yang saya pelajari

Menulis ulang ini tiga kali. Versi pertama memakai tabel terpisah per status, versi kedua memakai polling tanpa indeks. Keduanya gagal pada beban uji yang sama: banyak worker, sedikit pekerjaan.