Μια custom εφαρμογή σπάνια λειτουργεί μόνη της. Συνδέεται με ERP, πληρωμές, μεταφορικές, email providers, CRM και υπηρεσίες τεχνητής νοημοσύνης. Όταν ένα εξωτερικό API καθυστερεί, η αφελής αντίδραση είναι να περιμένουμε περισσότερο ή να επαναλαμβάνουμε την κλήση. Έτσι όμως μια τοπική βλάβη μπορεί να εξαπλωθεί σε ολόκληρο το σύστημα.
Το circuit breaker είναι pattern ανθεκτικότητας που σταματά προσωρινά τις κλήσεις προς dependency που αποτυγχάνει συστηματικά. Αντί κάθε request χρήστη να περιμένει μέχρι timeout, η εφαρμογή αποτυγχάνει γρήγορα, χρησιμοποιεί ασφαλές fallback όπου υπάρχει και δίνει στην εξωτερική υπηρεσία χρόνο να ανακάμψει.
01Γιατί τα retries δεν αρκούν
Ένα retry είναι χρήσιμο για παροδικό πρόβλημα: μια στιγμιαία διακοπή δικτύου ή ένα προσωρινό 503. Αν όμως η υπηρεσία είναι εκτός λειτουργίας για λεπτά, κάθε νέο request ξεκινά τον ίδιο κύκλο αποτυχημένων προσπαθειών.
Τα retries αυξάνουν την κίνηση ακριβώς όταν ο provider δυσκολεύεται. Παράλληλα κρατούν threads, connections και μνήμη στην εφαρμογή. Η Microsoft περιγράφει το Circuit Breaker pattern ως τρόπο να αποτρέπονται συνεχείς κλήσεις προς dependency που πιθανότατα θα αποτύχει και να περιορίζονται cascading failures.
Retry και circuit breaker έχουν διαφορετικό ρόλο. Το retry δίνει λίγες ευκαιρίες σε transient fault. Ο breaker σταματά νέες προσπάθειες όταν το πρόβλημα φαίνεται επίμονο.
02Οι τρεις καταστάσεις
Closed
Η λειτουργία είναι φυσιολογική και οι κλήσεις περνούν. Ο breaker καταγράφει πρόσφατες αποτυχίες, timeouts και επιτυχίες. Μεμονωμένο λάθος δεν πρέπει να ανοίγει το circuit, αλλά ένα threshold μέσα σε συγκεκριμένο χρονικό παράθυρο μπορεί να το ενεργοποιήσει.
Open
Οι κλήσεις απορρίπτονται αμέσως χωρίς να φτάνουν στον provider. Η εφαρμογή επιστρέφει ελεγχόμενο σφάλμα, cached αποτέλεσμα ή τοποθετεί εργασία σε queue, ανάλογα με τη λειτουργία. Ένα χρονικό διάστημα επιτρέπει στην εξωτερική υπηρεσία να ανακάμψει.
Half-open
Μετά το διάστημα αναμονής, περνά περιορισμένος αριθμός δοκιμαστικών αιτημάτων. Αν επιτύχουν, το circuit κλείνει. Αν αποτύχουν, ανοίγει ξανά. Αυτό αποτρέπει το ξαφνικό κύμα κίνησης προς μια υπηρεσία που μόλις άρχισε να επανέρχεται.
03Timeouts πριν από όλα
Circuit breaker χωρίς σωστό timeout αντιδρά αργά. Αν κάθε κλήση περιμένει 60 δευτερόλεπτα, πολλά requests θα έχουν ήδη δεσμεύσει πόρους πριν φανεί η αποτυχία.
Το timeout πρέπει να βασίζεται στη φυσιολογική latency της συγκεκριμένης λειτουργίας και στο συνολικό χρονικό budget του user request. Connection timeout και response timeout είναι διαφορετικά. Ένα checkout δεν μπορεί να ξοδέψει όλο το budget περιμένοντας ένα δευτερεύον recommendation API.
04Ποια σφάλματα μετρούν
Δεν πρέπει κάθε αποτυχία να ανοίγει το circuit. Ένα 400 λόγω λανθασμένου payload είναι bug ή validation error και πιθανότατα θα αποτύχει ξανά. Ένα 401 μπορεί να σημαίνει ληγμένο credential και απαιτεί alert, όχι επαναλήψεις. Τα 429 και 503 μπορεί να είναι προσωρινά και να συνοδεύονται από Retry-After.
Η πολιτική ταξινομεί errors σε transient, permanent και throttling. Τα timeouts μπορεί να έχουν διαφορετικό βάρος από ένα άμεσο 500. Η μέτρηση καλό είναι να χρησιμοποιεί ποσοστό αποτυχίας και ελάχιστο όγκο, ώστε δύο αποτυχίες σε δύο κλήσεις χαμηλής κίνησης να μην έχουν την ίδια ερμηνεία με εκατοντάδες requests.
05Ένας breaker ανά πραγματικό dependency
Αν όλες οι εξωτερικές υπηρεσίες μοιράζονται έναν breaker, η βλάβη της μεταφορικής μπορεί να σταματήσει και το email. Ακόμη και στον ίδιο provider, διαφορετικά endpoints μπορεί να έχουν διαφορετική συμπεριφορά.
Ο breaker ορίζεται σε επίπεδο πόρου και λειτουργίας που μοιράζεται κοινό failure mode. Σε multi-tenant εφαρμογή ίσως χρειάζεται διάκριση ανά credential ή account, επειδή το rate limit ενός πελάτη δεν πρέπει να επηρεάζει όλους τους άλλους.
06Fallback με ειλικρινή συμπεριφορά
Το fallback εξαρτάται από το νόημα της λειτουργίας:
- cached τιμή για κατάλογο που ανέχεται μικρή καθυστέρηση,
- queue για συγχρονισμό ERP που μπορεί να ολοκληρωθεί αργότερα,
- προσωρινή απόκρυψη recommendations,
- read-only λειτουργία όταν αποτυγχάνει write dependency,
- σαφές μήνυμα στον χρήστη όταν δεν υπάρχει ασφαλής εναλλακτική.
Δεν χρησιμοποιούμε ψεύτικη επιτυχία. Αν η πληρωμή δεν επιβεβαιώθηκε, η εφαρμογή δεν πρέπει να δείξει ολοκληρωμένη παραγγελία. Αν το αίτημα μπει σε queue, ο χρήστης ενημερώνεται ότι εκκρεμεί.
07Idempotency για ασφαλή επανάληψη
Ένα timeout δεν αποδεικνύει ότι η εξωτερική ενέργεια δεν εκτελέστηκε. Ο provider μπορεί να χρέωσε την κάρτα αλλά η απάντηση να χάθηκε. Όταν το circuit κλείσει, η τυφλή επανάληψη μπορεί να διπλασιάσει την πράξη.
Οι write λειτουργίες χρειάζονται idempotency key, σταθερό business identifier ή διαδικασία reconciliation. Το queue διατηρεί attempt history και δεν δημιουργεί νέο command κάθε φορά που ένας worker ξαναδοκιμάζει.
08Distributed εφαρμογές και κοινή κατάσταση
Με πολλά instances, ένας τοπικός breaker σε κάθε process βλέπει μόνο μέρος της κίνησης. Αυτό μπορεί να είναι αποδεκτό, αλλά σημαίνει ότι αρκετά instances θα δοκιμάσουν ανεξάρτητα το προβληματικό dependency.
Η κοινή κατάσταση σε Redis ή service mesh δίνει ενιαία εικόνα, αλλά προσθέτει dependency και πολυπλοκότητα. Η απόφαση εξαρτάται από τον όγκο, το blast radius και το αν τα instances μοιράζονται το ίδιο quota. Ακόμη και με τοπικούς breakers, χρησιμοποιούμε jitter ώστε τα half-open probes να μη συμβούν ταυτόχρονα.
09Observability και χειροκίνητος έλεγχος
Κάθε αλλαγή state πρέπει να παράγει metric και structured event. Παρακολουθούμε:
- success, error και timeout rate,
- latency του dependency,
- state και διάρκεια open circuit,
- απορριφθείσες κλήσεις,
- half-open probes,
- queued εργασίες και ηλικία τους,
- επιτυχία fallback,
- retries ανά operation.
Ένα admin εργαλείο μπορεί να επιτρέπει force-open για προγραμματισμένη διακοπή ή ελεγχόμενο reset. Η χειροκίνητη ενέργεια καταγράφεται και δεν αντικαθιστά την αυτόματη ανάκαμψη.
10Δοκιμές που αξίζουν
Δεν αρκεί ένα unit test της state machine. Σε staging προσομοιώνουμε slow responses, connection resets, 429, 503, μερική αποτυχία και ανάκαμψη. Ελέγχουμε ότι το user-facing endpoint παραμένει γρήγορο όταν το dependency κρέμεται και ότι το half-open δεν πλημμυρίζει την υπηρεσία.
Δοκιμάζουμε επίσης το fallback: οι queued εργασίες εκτελούνται μία φορά, τα cached δεδομένα έχουν εμφανή ηλικία όπου χρειάζεται και τα alerts δεν δημιουργούν θόρυβο σε κάθε μεμονωμένο error.
11Πώς το υλοποιεί η Ai Foundry
12Checklist
Ο circuit breaker δεν κάνει ένα εξωτερικό API πιο αξιόπιστο. Κάνει τη δική σας εφαρμογή λιγότερο εξαρτημένη από τον τρόπο με τον οποίο εκείνο αποτυγχάνει.
13Πηγές
Θέλετε κάτι αντίστοιχο για τη δική σας επιχείρηση;
Ξεκινήστε το έργο σας →
Γράφτηκε από την ομάδα της Ai Foundry (aifoundry.gr), εταιρείας ανάπτυξης λογισμικού και εφαρμογών τεχνητής νοημοσύνης στην Ελλάδα.