Episode ini membuat service gRPC tahan banting: retry policy lewat service config, circuit breaker, strategi timeout dan failover, serta graceful shutdown, health checks, dan readiness probes untuk downtime yang nyaris nol.

Kegagalan adalah kepastian — server crash, jaringan putus, dependency lambat. Pertanyaannya bukan "apakah akan gagal", tapi "apakah sistem tetap melayani saat itu terjadi". Episode 15 membangun ketahanan gRPC: retry untuk transien, circuit breaker untuk kegagalan berulang, timeout dan failover untuk dependency yang lambat, dan graceful shutdown agar pergantian versi tidak memutus request yang sedang berjalan.
Prinsipnya: sistem yang resilien bukan yang tidak pernah gagal, tapi yang gagal dengan anggun dan pulih dengan cepat.
gRPC punya retry bawaan yang dikonfigurasi lewat service config JSON, bukan kode. Ingat konfigurasi di episode 7 — sekarang kita pakai penuh:
{
"methodConfig": [
{
"name": [{ "service": "catalog.v1.CatalogService" }],
"retryPolicy": {
"maxAttempts": 4,
"initialBackoff": "0.1s",
"maxBackoff": "2s",
"backoffMultiplier": 2.0,
"retryableStatusCodes": ["UNAVAILABLE", "RESOURCE_EXHAUSTED"]
}
}
]
}"retryableStatusCodes": ["UNAVAILABLE"] menentukan error mana yang aman di-retry. Jangan pernah memasukkan INVALID_ARGUMENT — retry request yang salah logika hanya membuang resource. Backoff berlipat (0.1s, 0.2s, 0.4s) memberi dependency waktu pulih.
conn, _ := grpc.NewClient("localhost:50051",
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithDefaultServiceConfig(retryConfig),
)grpc.WithDefaultServiceConfig(retryConfig) mengirim retry policy bersama channel. Retry transparan bagi kode aplikasi — gRPC yang menangani percobaannya.
Retry menambah beban saat service sedang sekarat — justru memperparah. Circuit breaker mencegah itu: tiga state — closed (normal), open (pemutusan), dan half-open (uji coba). Saat error rate melewati ambang, breaker open dan semua panggilan ditolak cepat dengan UNAVAILABLE tanpa menyentuh server; setelah jeda, half-open menguji satu panggilan sebelum menutup kembali.
if breaker.IsOpen() {
return nil, status.Error(codes.Unavailable, "circuit terbuka")
}
err := callBackend()
breaker.Record(err)breaker.Record(err) memperbarui statistik error. Implementasi siap pakai tersedia di library seperti sony/gobreaker atau hystrix-go, plus circuit breaker native di service mesh.
Jangan bergantung pada satu deadline. Terapkan timeout bertingkat — pendek untuk panggilan internal, lebih panjang untuk agregasi:
ctx, cancel := context.WithTimeout(ctx, 500*time.Millisecond)
defer cancel()
res, err := client.GetProduct(ctx, req)
if status.Code(err) == codes.DeadlineExceeded {
return nil, fallbackFromCache(ctx)
}context.WithTimeout(ctx, 500*time.Millisecond) memberi dependency paling lambat setengah detik. Pola fallback — misalnya ke cache — menjaga pengalaman user tetap baik saat sumber utama melambat.
Client bisa mencoba alamat cadangan saat target utama gagal. Resolver gRPC mendukung daftar alamat yang dipisahkan koma:
targets := "catalog-svc:50051,catalog-backup:50051"
conn, _ := grpc.NewClient(targets,
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithDefaultServiceConfig(`{"loadBalancingConfig":[{"pick_first":{}}]}`),
)Dengan pick_first, client memakai alamat pertama yang sehat dari daftar. Bila primary mati, connection berpindah ke backup — dasar dari high availability tanpa perantara.
Saat container di-stop, request yang sedang berjalan harus selesai dulu, bukan diputus paksa. Di Go, GracefulStop menangani ini:
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGTERM, syscall.SIGINT)
<-quit
s.GracefulStop()signal.Notify(quit, syscall.SIGTERM, syscall.SIGINT) menangkap sinyal penghentian dari Kubernetes. s.GracefulStop() berhenti menerima request baru tapi menuntaskan yang sedang berjalan — lalu bisa dipanggil s.Stop() sebagai pengaman waktu.
Kombinasikan dengan episode 9 agar orchestrator tahu kapan aman mengarahkan traffic:
readinessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:50051"]
initialDelaySeconds: 5
livenessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:50051"]
periodSeconds: 10Probe readinessProbe menahan traffic selama server masih melakukan persiapan; livenessProbe meminta restart saat server membeku. Selama shutdown anggun, readiness harus dinonaktifkan agar pod tidak menerima traffic baru.
Inti yang harus dibawa pulang:
UNAVAILABLE, jangan untuk INVALID_ARGUMENT.Di episode 16 selanjutnya kita membahas gRPC-Web, Envoy, dan gateway integrations — konsep gRPC-Web untuk interoperabilitas browser, integrasi dengan Envoy proxy dan API gateway, serta penggabungan gRPC dengan REST gateway untuk API hybrid. Service yang tangguh kini dibuka untuk konsumen di luar jaringan internal.