Microservices architecture menawarkan fleksibilitas tinggi, tetapi juga memperkenalkan kompleksitas baru. Ketika satu service gagal, kegagalan tersebut bisa menyebar seperti efek domino ke service lain yang bergantung padanya. Circuit breaker pattern hadir sebagai solusi untuk mencegah cascading failure dengan mendeteksi kegagalan dan menghentikan request ke service yang bermasalah sementara waktu.
Dalam artikel ini, kita akan membangun implementasi circuit breaker di Python menggunakan library pybreaker. Pola ini sangat relevan untuk developer yang membangun sistem terdistribusi dan ingin meningkatkan resiliensi aplikasi mereka.
Circuit breaker adalah pola desain yang pertama kali dipopulerkan oleh Martin Fowler untuk menangani kegagalan di sistem terdistribusi. Konsepnya mirip dengan circuit breaker di listrik: ketika terjadi masalah, sirkuit akan "putus" untuk mencegah kerusakan lebih lanjut.
Ada tiga state utama dalam circuit breaker:
Closed: Semua request berjalan normal. Circuit breaker memonitor kegagalan di background.
Open: Ketika kegagalan melebihi threshold, circuit breaker membuka dan menolak semua request secara langsung.
Half-Open: Setelah timeout, circuit breaker mengizinkan beberapa request uji coba untuk mengecek apakah service sudah pulih.
Sebelum memulai, pastikan Python 3.9 atau lebih baru sudah terinstal di sistem Anda. Buat virtual environment baru dan install dependency yang diperlukan:
python3 -m venv venv
source venv/bin/activate
pip install pybreaker requests flask
Library pybreaker adalah implementasi circuit breaker yang mature dan mudah digunakan di Python. Anda dapat mengeksplorasi repository resminya di GitHub pybreaker.
Pertama, kita perlu membuat service eksternal yang akan kita panggil. Buat file external_service.py dengan kode Flask berikut:
from flask import Flask, jsonify
import random
app = Flask(__name__)
@app.route('/api/data')
def get_data():
if random.random() < 0.7:
return jsonify({"error": "Service unavailable"}), 503
return jsonify({"data": "success", "items": [1, 2, 3]})
if __name__ == '__main__':
app.run(port=5001)
Service ini secara acak mengembalikan error 503 dengan probabilitas 70 persen, yang akan kita gunakan untuk mensimulasikan service yang tidak stabil.
Buat file circuit_client.py dan implementasikan circuit breaker dengan pybreaker:
import requests
from pybreaker import CircuitBreaker
from pybreaker import CircuitBreakerListener
class LogListener(CircuitBreakerListener):
def state_change(self, cb, old_state, new_state):
print(f"Circuit breaker state: {old_state} -> {new_state}")
breaker = CircuitBreaker(
fail_max=3,
reset_timeout=10,
listeners=[LogListener()]
)
@breaker
def call_external_service():
response = requests.get('http://localhost:5001/api/data', timeout=2)
response.raise_for_status()
return response.json()
if __name__ == '__main__':
for i in range(20):
try:
result = call_external_service()
print(f"Request {i+1}: Success - {result}")
except Exception as e:
print(f"Request {i+1}: Failed - {type(e).__name__}")
Konfigurasi di atas menetapkan threshold kegagalan maksimal 3 kali sebelum circuit breaker membuka. Setelah 10 detik, circuit breaker akan mencoba state half-open untuk mengecek ketersediaan service.
Circuit breaker yang baik harus disertai dengan fallback mechanism. Modifikasi file circuit_client.py untuk menangani request saat circuit breaker dalam state open:
def get_data_with_fallback():
try:
return call_external_service()
except Exception:
return {
"data": "fallback",
"message": "Service sedang tidak tersedia, menggunakan data cache",
"items": []
}
if __name__ == '__main__':
for i in range(20):
result = get_data_with_fallback()
print(f"Request {i+1}: {result}")
Fallback mechanism memastikan aplikasi tetap responsif meskipun service eksternal mengalami gangguan. Anda dapat mengganti data fallback dengan cache dari Redis atau database lokal.
Untuk production, Anda perlu memonitor state circuit breaker secara real-time. Pybreaker menyediakan property untuk mengakses informasi internal:
print(f"Current state: {breaker.current_state}")
print(f"Failure count: {breaker.fail_counter}")
print(f"Success count: {breaker.success_counter}")
Integrasikan metrik ini dengan Prometheus atau Datadog untuk alerting. Ketika circuit breaker sering berada dalam state open, itu adalah sinyal bahwa service target perlu diperbaiki.
Terakhir, mari integrasikan circuit breaker ke aplikasi web menggunakan FastAPI:
from fastapi import FastAPI, HTTPException
from pybreaker import CircuitBreaker
import requests
app = FastAPI()
breaker = CircuitBreaker(fail_max=5, reset_timeout=30)
@breaker
def fetch_user_profile(user_id: str):
resp = requests.get(f"https://api.example.com/users/{user_id}")
resp.raise_for_status()
return resp.json()
@app.get("/users/{user_id}")
async def get_user(user_id: str):
try:
data = fetch_user_profile(user_id)
return {"status": "ok", "data": data}
except Exception:
raise HTTPException(
status_code=503,
detail="User service sedang tidak tersedia"
)
Pattern ini dapat diterapkan ke endpoint mana pun yang bergantung pada service eksternal. Pastikan untuk menyesuaikan nilai fail_max dan reset_timeout berdasarkan karakteristik service yang Anda konsumsi.
Circuit breaker pattern adalah komponen penting dalam arsitektur microservices yang resilient. Dengan library pybreaker, implementasi di Python menjadi sangat mudah tanpa perlu menulis logika state machine dari nol.
Beberapa poin kunci yang perlu diingat: selalu tambahkan fallback mechanism, monitor state circuit breaker di production, dan sesuaikan threshold berdasarkan pola traffic aplikasi Anda. Untuk referensi lebih lanjut, pelajari juga library Polly untuk .NET yang menawarkan fitur circuit breaker yang lebih lengkap.
Banyak developer yang baru mengenal circuit breaker melakukan kesalahan konfigurasi yang justru memperburuk masalah. Berikut adalah beberapa anti-pattern yang sering terjadi di production:
Threshold terlalu rendah: Menetapkan fail_max=1 pada service yang memang memiliki baseline error rate tinggi akan membuat circuit breaker selalu terbuka. Analisis dulu metrik error service target sebelum menentukan threshold.
Tanpa fallback: Circuit breaker yang hanya melempar exception tanpa fallback sama saja dengan membiarkan kegagalan menyebar. Selalu sediakan degraded response yang masih memberikan nilai kepada user.
Reset timeout terlalu cepat: Jika reset_timeout hanya 1 detik, service yang baru saja down akan langsung kembali dibebani request. Berikan waktu cukup untuk recovery, biasanya 10 sampai 60 detik tergantung service.
Selain itu, hindari menggabungkan terlalu banyak service dalam satu circuit breaker instance. Setiap service eksternal harus memiliki circuit breaker sendiri agar kegagalan satu service tidak mempengaruhi service lain.
Dapatkan feedback, users, dan eksposur dari komunitas kreator, developer, dan entrepreneur digital Indonesia.
Submit Produk → Pelajari Dulu