Circuit breaker pattern
Radim Štěpaník
https://app.sli.do/event/heoixjpa/live/questions
slido.com:
👀 CTO
👷 Teamleader
👩💻 JS developer
🎤 Moderátor
🎸 Kytarista
👨👧 Rodič
(snad lepší než kytarista)
🎧 Listen on spotify
🐦 Follow me on twitter
kinapets
QCAST
⚡️Jistič
Kdy nad tím přemýšlet
- distribuované prostředí
- fail fast
- fault tolerance
Chyby jsou všude
- síťové chyby
- výpadky služeb
- výpadky v datacentru
- chyby v kódu
Typický scénář
Něco nám začíná hořet
Retry
- Volání opakuj v jakémkoliv případě
- Možné vylepšení rozprostřít volání v čase
- Dobré dokud všechno funguje
💥
👉
Jak to asi dopadne?
Kompletní pád
Co dělá CB?
Rozpojeno
Čekáme na zotavení
Jistič se automaticky sepne
Circuit breaker
- Stav jističe
- chyby, timeouty
- Samotná operace
- Fallback
- Nastavení
- práh erroru
- timeout
- .... ochranné pásmo - čas,
množství, etc.
Podpora
- vlastní implementace
-
knihovny
- nodejs - https://www.npmjs.com/package/opossum
- resilience4j - https://github.com/resilience4j/resilience4j
- php - https://github.com/upwork/phystrix
- ....
Code example
- Stav jističe
- chyby, timeouty
- Samotná operace
- Fallback
- Nastavení
- práh erroru
- timeout
- .... ochranné pásmo - čas,
množství, etc.
import CircuitBreaker from 'opossum';
function asyncFunctionThatCouldFail(x, y) {
return new Promise((resolve, reject) => {
// Do something, maybe on the network or a disk
});
}
const options = {
timeout: 3000, // If our function takes longer than 3 seconds, trigger a failure
errorThresholdPercentage: 50, // When 50% of requests fail, trip the circuit
resetTimeout: 30000, // After 30 seconds, try again.
};
const breaker = new CircuitBreaker(asyncFunctionThatCouldFail, options);
breaker.fire(x, y).then(console.log).catch(console.error);
Code example
- Stav jističe
- chyby, timeouty
- Samotná operace
- Fallback
- Nastavení
- práh erroru
- timeout
- .... ochranné pásmo - čas,
množství, etc.
import CircuitBreaker from 'opossum';
function asyncFunctionThatCouldFail(x, y) {
return new Promise((resolve, reject) => {
// Do something, maybe on the network or a disk
});
}
const options = {
timeout: 3000, // If our function takes longer than 3 seconds, trigger a failure
errorThresholdPercentage: 50, // When 50% of requests fail, trip the circuit
resetTimeout: 30000, // After 30 seconds, try again.
};
const breaker = new CircuitBreaker(asyncFunctionThatCouldFail, options)
.fallback(() => 'do something else');
breaker.fire(x, y).then(console.log).catch(console.error);
Use cases
- IO operace
- http klienti
- databazove operace - např. redis
- čtení ze sdíleného souboru
- High level logic
- nastavení fallbacks
-
💡Co takhle použití s graphql?
Věci na které nelze spoléhat
Use case
Products
Categories
Banners
GQL GW
50+ service
search
customer
cart
bestsellers
banners
menu
category
products
filters
content
# Calls category
getCategory(categoryUrl: $categoryUrl) {
id
howto
# Calls content service
... on ContentCategory {
content {
id
title
body
}
}
# Calls product service
... on ProductCategory {
productCollection {
items {
... on Product {
...productForList
}
# Calls estimated delivery service
... on BonusSet {
estimatedDeliveries {
...productEstimatedDeliveryFragment
}
}
# Calls banners service
... on SectionBannerSlideImage {
...sectionBannerSlide
}
}
}
}
}
// 👉 every resolver has unique name - Query:category, Category:productCollection
const resolvers = {
Query: {
category: resolveCategory,
},
Category: {
productCollection: resolveProductCollection,
},
};
// 🌍 global configuration of specific resolvers
export const resolverConfig: Map<string, ResolverConfig> = new Map<string, ResolverConfig>()
.set('Query:category', { timeout: 3000 })
.set('Category:productCollection', { timeout: 3000, fallback: () => [] });
// 👷 Usage of high order function. Resolver is wrapped by circuit breaker
const resolversWithCircuitBreakers = mapResolvers(
resolvers,
//
({ resolver, name }: CreateResolverInput): IFieldResolver<unknown, unknown, unknown> => {
const { ...breakerDefaultConfig } = resolverConfig.get(name) ?? {};
const config = { name, ...breakerDefaultConfig };
const breaker = createCircuitBreaker(config, resolver);
return async (...params: ResolverParams): Promise<unknown> => breaker.fire(...params);
},
);
Nedokážeme to vyřešit obecně❓
Monitoring hystrix
Monitoring prometheus/grafana
- sms notification
- teams notification
Je odpovědí na všechno?
- zvyšuje komplexitu aplikace
- nutné správné nastavení timeoutů
- nutné rozlišovat
- při použití přímo v kódu
- zvyšuje nároky na zpracování
👋 Díky za pozornost
Dotazy?
slido.com
Qeetup Circuit breaker
By Radim Štěpaník
Qeetup Circuit breaker
- 290