Durable execution menjamin bahwa eksekusi kode berjalan hingga selesai (run-to-completion) meskipun terjadi kegagalan proses, restart container, atau partisi jaringan. Alih-alih mengelola state machine kompleks secara manual di atas database relasional atau message broker, runtime durable execution memetakan status thread kode langsung ke storage persisten.

Terdapat tiga paradigma utama dalam implementasi durable execution: event-sourcing replay (Temporal), durable RPC suspension (Restate), dan deterministic memory snapshotting (WASM via Obelisk). Masing-masing arsitektur membawa kompromi mendasar pada overhead storage, batasan penulisan kode aplikasi, serta kompleksitas operasional infrastruktur.

1. Tiga Paradigma Durable Execution

Event-Sourcing Replay (Temporal)

Temporal memisahkan cluster server dan aplikasi worker. Worker mengeksekusi kode workflow dan mengirimkan perintah (commands) ke server. Server mencatat perintah tersebut sebagai event stream ke database (PostgreSQL, Cassandra, dsb.).

Ketika worker mengalami crash atau workflow dibangunkan dari sleep, worker tidak memuat memori sebelumnya. Worker mengeksekusi ulang kode dari awal (replay). Interaksi I/O (Activity) tidak dieksekusi ulang; sistem mencegat panggilan tersebut dan mengembalikan nilai dari riwayat event (history log).

Durable RPC & Suspension (Restate)

Restate beroperasi sebagai reverse-proxy berbasis event log terdistribusi. Worker aplikasi berupa server HTTP biasa. Ketika workflow melakukan panggilan eksternal melalui SDK Restate (seperti ctx.run() atau ctx.call()), Restate mencatat hasil pemanggilan ke journal.

Jika eksekusi menunggu I/O atau timer, koneksi HTTP ditutup dan eksekusi disuspensi (suspended). Saat hasil tersedia atau server hidup kembali setelah crash, Restate mengirimkan HTTP request baru yang menyertakan riwayat journal, melanjutkan thread dari titik suspensi tanpa menjalankan ulang kode di luar checkpoint.

Deterministic WASM Memory Snapshotting (Obelisk)

WASM sandbox menyediakan memori linier yang terisolasi sepenuhnya dari sistem operasi host. Obelisk dan runtime WASM serupa mengeksekusi alur kerja di dalam engine Wasmtime.

Ketika terjadi operasi blocking (seperti sleep atau pemanggilan fungsi RPC), host engine membuat snapshot status memori linier WASM menggunakan mekanisme Copy-On-Write (COW) atau dirty page tracking, lalu menyimpannya ke disk. Saat bangun, engine memetakan kembali halaman memori tersebut ke RAM. Eksekusi berlanjut langsung dari instruksi CPU terakhir tanpa replay kode dan tanpa replay journal.

2. Trade-off Arsitektur dan Karakteristik Teknis

Persyaratan Determinisme Kode

Tingkat isolasi runtime menentukan batasan kebebasan developer dalam menulis kode:

  • Temporal: Memerlukan determinisme absolut pada fungsi workflow. Developer dilarang membaca jam sistem (Date.now()), menggunakan generator angka acak bawaan bahasa, menjalankan thread/goroutine non-deterministik, atau membaca global variable yang dapat bermutasi. Perubahan logika pada alur kerja yang sedang berjalan memerlukan API versioning eksplisit (workflow.getVersion()) untuk menghindari error non-deterministic history mismatch.
  • Restate: Isolasi determinisme lebih longgar. Bagian non-deterministik cukup dibungkus di dalam blok ctx.run(). Kode di luar blok tersebut bebas memanggil library eksternal standar karena Restate hanya menjamin determinisme pada level journal transition boundary.
  • WASM (Obelisk): Determinisme dipaksakan pada level instruksi mesin virtual. Interaksi I/O dan sistem dialihkan melalui WASI interface yang sepenuhnya deterministik. Developer tidak dapat membocorkan state non-deterministik dari host OS secara tidak sengaja.
// Contoh Temporal: Memerlukan API versioning ketat saat refactoring
import { proxyActivities, getVersion } from '@temporalio/workflow';

const { chargeCreditCard, chargeViaNewGateway } = proxyActivities({
  startToCloseTimeout: '1 minute',
});

export async function paymentWorkflow(userId: string, amount: number) {
  // Versioning wajib jika ada workflow in-flight
  const version = getVersion('payment-gateway-v2', 1, 2);

  if (version === 1) {
    await chargeCreditCard(userId, amount);
  } else {
    await chargeViaNewGateway(userId, amount);
  }
}
// Contoh Restate: Determinisme dibatasi pada context boundaries
import * as restate from '@restatedev/restate-sdk';

const paymentService = restate.service({
  name: 'payment',
  handlers: {
    process: async (ctx: restate.Context, req: { amount: number }) => {
      // Side-effect non-deterministik diisolasi di ctx.run
      const authCode = await ctx.run('gen-auth', () => {
        return crypto.randomUUID(); // Valid di dalam ctx.run
      });

      // Durable RPC invocation
      await ctx.serviceClient(ThirdPartyService).charge({ authCode, amount: req.amount });
    },
  },
});

Overhead Penyimpanan dan Ukuran History

Perbedaan metode persistensi berdampak langsung pada skala database:

  • Temporal: History log bertambah secara linear $O(N)$ terhadap jumlah activity dan timer. Workflow jangka panjang (seperti subscription atau IoT listener) akan mengalami memory bloat saat replay jika tidak menerapkan pola continueAsNew untuk memangkas ukuran riwayat event.
  • Restate: Menggunakan model append-only log yang dapat dipangkas (compacted) setelah checkpoint berhasil di-commit. Payload ditransmisikan via HTTP stream, meminimalkan metadata historis yang tidak relevan.
  • WASM: Snapshot memori linier dapat berukuran puluhan megabyte per instans jika heap alur kerja besar. Meskipun COW mengurangi penyimpanan duplikat pada disk, footprint snapshotting memori jauh lebih besar per checkpoint dibanding sekadar event log JSON/Protobuf Temporal atau Restate.

Latensi Pemulihan Crash (Recovery Latency)

Waktu yang dibutuhkan sistem untuk melanjutkan eksekusi setelah worker crash:

  • Temporal: Latensi pemulihan tinggi pada workflow dengan history panjang. Worker harus mengambil seluruh riwayat event dari database cluster, mem-parsing event stream, dan mengeksekusi ulang kode dari baris pertama hingga mencapai step terakhir.
  • Restate: Latensi pemulihan sedang. Worker menerima payload state terbaru dari Restate journal dan mengeksekusi handler langsung dari suspension point aktif tanpa iterasi event dari nol.
  • WASM: Latensi pemulihan mendekati nol (sub-millisecond). Engine hanya perlu memetakan dirty pages dari persistent store ke memori virtual, mengembalikan nilai register, dan melanjutkan eksekusi instruksi WebAssembly berikutnya.

3. Perbandingan Biaya Operasional dan Kompleksitas Infrastruktur

Metrik ArsitekturTemporalRestateWASM (Obelisk)
Topologi ClusterKompleks (Frontend, History, Matching, DB, Elasticsearch)Sederhana (Single-binary Restate server / distributed Raft)Minimal (Single binary runner / stateless container)
Model WorkerLong-running polling worker (gRPC long-poll)Standard HTTP/2 server / FaaS endpointsIn-process WASM guest runtime
Footprint ResourceTinggi (Kebutuhan RAM DB & worker pool terdedikasi)Rendah ke Sedang (Efisien dalam multiplexing stream)Sangat Rendah (CPU idle zero, disk I/O terikat snapshot)
Maturitas EkosistemSangat Matang (Go, Java, TS, Python, .NET)Berkembang (TS, Java, Kotlin, Rust, Go)Eksperimental / Awal (Rust, C/C++, Go via TinyGo)

Beban Maintainability SDK

Pada Temporal, SDK mengintegrasikan engine deterministik in-memory. Jika terdapat bug internal pada implementasi concurrency runtime bawaan SDK (misalnya thread scheduling di Go atau async resolution di Node.js), tim menghadapi insiden nondeterminism error yang sulit di-debug.

Pada Restate, SDK jauh lebih tipis (thin-client) karena hanya bertindak sebagai interceptor HTTP request dan wrapper serialisasi payload JSON/Protobuf. Kompleksitas durable log ditangani sepenuhnya oleh Restate server binary.

Pada WASM, SDK bergantung pada kesiapan compiler target bahasa ke WebAssembly Component Model (WASI 0.2). Developer dibatasi oleh ekosistem library yang kompatibel dengan kompilasi WASM tanpa dependensi native OS bindings (seperti socket C mentah atau threaded runtime tertentu).

4. Panduan Pemilihan Arsitektur

  1. Pilih Temporal jika: Sistem menangani orchestrasi proses bisnis skala enterprise berskala tinggi, memiliki alur kerja yang melibatkan integrasi puluhan microservices heterogen, dan tim memiliki kapasitas DevOps untuk mengelola cluster Stateful (Cassandra/Postgres + Temporal Server).
  2. Pilih Restate jika: Tim membangun arsitektur berbasis RPC/HTTP biasa, ingin mengadopsi FaaS (AWS Lambda) atau container stateless (Knative, ECS) tanpa worker polling terus-menerus, dan membutuhkan footprint infrastruktur yang ringkas (single-binary ops).
  3. Pilih WASM (Obelisk) jika: Prioritas utama adalah resource efficiency ekstrem, cold-start mendekati instan, isolasi determinisme matematis pada level multi-tenant compute, dan codebase dapat ditulis dalam bahasa dengan dukungan WASM kelas satu seperti Rust.