Mengenal Dapr, runtime sidecar yang menstandarkan building blocks microservices: state store, pub/sub, service invocation, bindings, dan secrets — bahasa agnostik, resiliency deklaratif, portabel antar cloud, dan bagaimana ia melengkapi service mesh di tokokita

Sepanjang series ini kita menulis banyak hal yang sama berulang-ulang: retry, timeout, circuit breaker di tiap service (episode 11), pub/sub Kafka di tiap producer/consumer (episode 12), state store Redis di tiap service yang butuh cache/sesion (episode 6, 15). Pertanyaan yang wajar muncul: apakah ada runtime yang menstandarkan semua ini, sehingga kita tidak menulis boilerplate yang sama tujuh kali?
Menjawab pertanyaan itu, episode ini memperkenalkan Dapr (Distributed Application Runtime) — runtime open-source yang menjadi salah satu fondasi microservices paling populer di 2026. Bukan framework yang mengikat bahasa, bukan pengganti service mesh, melainkan selubung building blocks yang bisa dikonsumsi service mana pun lewat HTTP/gRPC lokal.
Dapr berjalan sebagai sidecar (container pendamping di tiap pod/process) dan mengekspos API HTTP/gRPC di localhost:3500. Aplikasi tinggal memanggil endpoint lokal — Dapr yang berkomunikasi dengan infrastruktur nyata (Redis, Kafka, dll).
service-a ── localhost:3500 ──➤ dapr sidecar ──➤ Redis / Kafka / service-b
(bahasa apa pun: TS, Go, Python, Java)Building blocks inti Dapr:
| Building Block | Menggantikan | Dipakai tokokita untuk |
|---|---|---|
| Service Invocation | HTTP client antar service + retry | checkout memanggil product reserve |
| State Store | Simpan state dengan concurrency | cart & session (Redis) |
| Pub/Sub | Producer/consumer Kafka manual | order → payment → notif |
| Bindings | Integrasi ke sistem eksternal | kirim email (SMTP binding) |
| Secrets | Akses secret tiap language | JWT secret, DB URL |
Instalasi Dapr: local development dapr init -slim (tanpa Redis/Kafka bawaan); di K8s dapr init -k (chart ke cluster).
dapr init -slim # runtime lokal
dapr --versionState store memindahkan bagaimana menulis state dari kode ke konfigurasi — ganti backend Redis ke CosmosDB/AWS DynamoDB tanpa ubah kode:
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: statestore
spec:
type: state.redis
version: v1
metadata:
- name: redisHost
value: redis:6379import { DaprClient } from '@dapr/dapr'
const client = new DaprClient()
export async function saveCart(cartKey: string, items: unknown) {
await client.state.save('statestore', [{ key: cartKey, value: items }])
}
export async function loadCart<T>(cartKey: string): Promise<T | null> {
return client.state.get<T>('statestore', cartKey)
}Manfaatnya: concurrency & TTL jadi bawaan (etag untuk optimistic lock, TTL policy), bukan logika yang kita tulis manual di episode 6.
Kirim & terima event tanpa produce/consume boilerplate Kafka:
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: pubsub
spec:
type: pubsub.kafka
version: v1
metadata:
- name: brokers
value: kafka:9092
- name: consumerGroup
value: notification-serviceawait client.pubsub.publish('pubsub', 'order-events', {
id: randomUUID(),
type: 'order.confirmed',
timestamp: new Date().toISOString(),
data: { orderId, userId, total },
})Penting: Dapr menjamin at-least-once dan deduplication by message id bawaan (idempotent delivery). Prinsip consumer idempoten (episode 12) tetap kita jaga di aplikasi — Dapr menghilangkan boilerplate, bukan kewajiban dedup.
Ini nilai tersembunyi Dapr: resiliency policy deklaratif menggantikan circuit breaker yang kita tulis di episode 11:
apiVersion: dapr.io/v1alpha1
kind: Resiliency
metadata:
name: resiliency
spec:
policies:
timeouts:
default: 2s
retries:
default:
policy: fixed
duration: 200ms
maxRetries: 3
circuitBreakers:
default:
maxRequests: 1
timeout: 5s
targets:
apps:
product-service:
timeout: default
retry: default
circuitBreaker: defaultmTLS antar sidecar Dapr (koneksi sidecar-sidecar terenkripsi) + observability (tracing/metrik diekspos oleh sidecar) datang tanpa menulis kode di service — persis janji yang dulu dipegang service mesh, tapi pada tingkat runtime aplikasi.
Empat alasan yang membuatnya laris:
:3500; tim Go, TS, dan Python memakai runtime yang sama dan pola yang sama.| Aspek | Manual SDK | Dapr | Service mesh |
|---|---|---|---|
| Lokasi | Dalam aplikasi | Sidecar runtime | Sidecar proxy (wire) |
| Cakupan | Tiap service beda-beda | Building blocks seragam | mTLS/retry/traffic-level |
| Bahasa | Per SDK | One API (HTTP/gRPC) | Bahasa-agnostic |
| Mengubah kode? | Ya (tiap service) | Sedikit (SDK tipis) | Tidak |
| Konsistensi | Tergantung disiplin | Standar | Standar |
Kesimpulannya: Dapr dan service mesh adalah komplementer. Mesh menangani jalur data & policy wire-level (episode 18); Dapr menangani bangunan aplikasi (state, pub/sub, invocations). Tim besar sering memakai keduanya. Untuk tokokita, Dapr bisa menggantikan boilerplate resiliensi manual (episode 11) tanpa perlu mesh.
Note
Dapr bukan anti-pola di seri ini — ia adalah evolusi natural. Cara berpikir yang kita bangun (outbox, idempotency, dedup, saga) tetap wajib; yang berubah adalah tempat boilerplate-nya: dari kode ke runtime. Jika kalian tertarik, episode 27 menyertakan eksperimen mengganti pub/sub manual dengan Dapr workflow.
Episode 25 memperkenalkan Dapr:
localhost:3500.Di episode 26 selanjutnya, kita melangkah ke tren terakhir modern: platform engineering & AIOps — Internal Developer Platform dan golden path, Backstage sebagai service catalog, deteksi anomali dan analisis log berbasis LLM, self-healing dengan auto-rollback, serta feature flags untuk gradual rollout. Sampai jumpa di episode 26!