Menjalankan asynchronous task berdurasi panjang seperti pipeline training AI, video encoding, atau batch processing pada Spot Instance (misalnya GKE Spot Nodes atau AWS Spot Instances) memangkas biaya infrastruktur hingga 60–80%. Konsekuensinya, infrastruktur dapat mencabut node kapan saja melalui pod eviction dengan toleransi waktu sempit (umumnya 25–30 detik antara SIGTERM dan SIGKILL).
Jika kontrak API dan arsitektur worker tidak dirancang toleran terhadap interupsi, beban kerja asinkronus akan mengalami mutasi data ganda, task berstatus menggantung (hanging state), atau kegagalan total yang memboroskan komputasi. Artikel ini menyajikan spesifikasi teknis kontrak API berbasis idempotency token dan mekanisme checkpointing untuk menjamin eksekusi task dapat dilanjutkan (resume) tanpa duplikasi.
Tiga Pitfall Integrasi Saat Eviction (SIGTERM)
Ketika Kubernetes memulai penggusuran pod (eviction), kubelet mengirimkan sinyal SIGTERM ke proses kontainer sebelum terminationGracePeriodSeconds berakhir. Tanpa penanganan deterministik pada boundary API dan worker, tiga kegagalan sistem berikut pasti terjadi:
- Mutasi Ganda (Double Mutation): Worker baru mengambil task yang diasumsikan gagal, lalu memproses ulang step yang sebenarnya telah menghasilkan mutasi eksternal (seperti pemanggilan API pihak ketiga atau pemotongan saldo).
- Hanging State: Database mencatat status task tetap
IN_PROGRESSsecara permanen karena worker mati mendadak sebelum sempat memperbarui state ke storage pusat. - Ambiguous Timeout: Klien atau orchestrator mendeteksi koneksi putus atau timeout HTTP tanpa mengetahui apakah batch step terakhir berhasil dikomit atau gugur di tengah jalan.
Pola Kontrak API 202 Accepted & Lifecycle Polling
Operasi asinkronus yang memakan waktu lebih dari 1 detik wajib mengembalikan status code 202 Accepted. Klien tidak menunggu hasil akhir, melainkan menerima resource locator untuk pemantauan.
POST /v1/ai/batch-inference HTTP/1.1
Host: api.internal.domain
Content-Type: application/json
Idempotency-Key: idemp_req_98a7cf810b
{
"model_id": "llm-embed-v2",
"dataset_uri": "s3://bucket/dataset-01.jsonl",
"callback_url": "https://client.internal.domain/webhooks/task-finish"
}Respons server wajib menyertakan ID tugas, status awal, dan header Location untuk polling:
HTTP/1.1 202 Accepted
Content-Type: application/json
Location: /v1/ai/batch-inference/task_01HY74M3K
{
"task_id": "task_01HY74M3K",
"status": "QUEUED",
"created_at": "2025-05-10T10:00:00Z",
"checkpoint": {
"current_step": 0,
"continuation_token": null
}
}Checkpointing Contract & Token Idempotensi Bertahap
Untuk workload berukuran besar, unit eksekusi harus dibagi menjadi partisi diskrit (chunks/batches). Setiap partisi memiliki step idempotency key yang dihitung secara deterministik: hash(task_id + step_index).
Ketika pod mengalami eviction di tengah proses, worker wajib menyimpan snapshot kemajuan terakhir (checkpoint). Respons polling status mengekspos properti ini agar proses pemulihan dapat memverifikasi batas komputasi yang valid.
Skema Kontrak Polling & State Handshake
GET /v1/ai/batch-inference/task_01HY74M3K HTTP/1.1
Host: api.internal.domainHTTP/1.1 200 OK
Content-Type: application/json
{
"task_id": "task_01HY74M3K",
"status": "SUSPENDED",
"total_steps": 100,
"completed_steps": 42,
"checkpoint": {
"last_committed_step": 42,
"continuation_token": "chk_step42_sha256_9f8e7d6c",
"last_heartbeat": "2025-05-10T10:04:15Z"
},
"error": null
}Nilai enum status yang valid dalam kontrak:
QUEUED: Task menunggu antrean worker.PROCESSING: Worker aktif mengeksekusi batch.SUSPENDED: Pod mati akibat SIGTERM; state aman disimpan pada checkpoint terakhir.COMPLETED: Seluruh step selesai diproses.FAILED: Terjadi eror unrecoverable/fatal.
Implementasi Worker: Signal Handling & State Sync
Worker bertugas mencegat sinyal OS, menghentikan iterasi batch baru, menulis checkpoint terakhir ke database persisten, lalu melepaskan lease lock sebelum kontainer dimatikan paksa.
Berikut implementasi minimal signal handling pada worker berbasis Python:
import signal
import sys
import time
import hashlib
class GracefulTaskWorker:
def __init__(self, task_id: str, db_client):
self.task_id = task_id
self.db = db_client
self.eviction_signaled = False
# Daftarkan penanganan sinyal SIGTERM
signal.signal(signal.SIGTERM, self._handle_sigterm)
signal.signal(signal.SIGINT, self._handle_sigterm)
def _handle_sigterm(self, signum, frame):
# Beri flag untuk stop iterasi berikutnya, maksimalkan sisa waktu grace period
self.eviction_signaled = True
def _generate_step_token(self, step_idx: int) -> str:
raw = f"{self.task_id}:{step_idx}"
return "chk_" + hashlib.sha256(raw.encode()).hexdigest()[:16]
def run(self, total_steps: int):
checkpoint = self.db.get_checkpoint(self.task_id)
start_step = checkpoint.get("last_committed_step", 0) + 1
for step in range(start_step, total_steps + 1):
if self.eviction_signaled:
# Pod terkena eviction; simpan status SUSPENDED dan flush state
self.db.update_state(
task_id=self.task_id,
status="SUSPENDED",
last_step=step - 1,
token=self._generate_step_token(step - 1)
)
sys.exit(0)
step_token = self._generate_step_token(step)
# Eksekusi unit atomik pekerjaan dengan idempotency key step
self.process_step(step, step_token)
# Update checkpoint
self.db.update_checkpoint(self.task_id, step, step_token)
self.db.update_state(self.task_id, status="COMPLETED", last_step=total_steps, token=None)
def process_step(self, step: int, token: str):
# ponytail: implementasi eksekusi actual via downstream API/storage
pass
Catatan Konfigurasi Kubernetes: Pastikan
terminationGracePeriodSecondspada spesifikasi Deployment/StatefulSet diatur lebih besar dari latensi maksimum pemrosesan satu batch step (misalnya:60s), agar handler memiliki cukup waktu untuk menyelesaikan checkpoint ke database.
Checklist Verifikasi Pemulihan Task
Gunakan kriteria berikut dalam automated test (chaos/e2e) untuk menjamin pemulihan task tanpa efek samping:
- Uji Interupsi Terkendali: Kirim
kubectl delete pod <pod-name> --now=falsesaat task berada pada progress 50%. Verifikasi status berubah keSUSPENDED, bukanFAILED. - Validasi Batas Token: Jalankan kembali worker baru dengan task yang sama. Worker harus memulai eksekusi tepat pada
last_committed_step + 1. - Idempotensi Mutasi Hilir: Pastikan pemanggilan ulang (replay) step yang telah memiliki token di log audit eksternal mengembalikan hasil tersimpan (cached result) tanpa mengeksekusi mutasi sekunder.
- Pembersihan Lock Orphan: Bila worker mati sebelum sempat menangani
SIGTERM(misal skenario Host Kernel Panic /SIGKILLinstan), pastikan sistem memiliki mekanisme heartbeat TTL otomatis untuk merebut (reclaim) task yang menggantung.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!