Fallbacks¶
Introduction¶
When your downstream microservices fall apart, retries are exhausted, or circuit breakers open, you need a solid plan B to cover this failure for upstream microservices. Otherwise, the entire request chain would fail in a cascading fashion all the way up.
This plan B is typically called a fallback, and it comes in different forms depending on the context and functionality required.
Use Cases¶
- Show a default or cached value if the downstream dependency is not responding (e.g., show a placeholder instead of the user's actual avatar)
- Log and silence the exception (e.g., if the message broker is not responding and you can afford to miss the message)
- Use functional redundancy in case of failure (e.g., request currency rates from another provider if the primary one is down)
Usage¶
import asyncio
from typing import Any
from hyx.fallback import fallback
from hyx.fallback.typing import ResultT
def get_default_user_avatar(result: ResultT, *args: Any, **kwargs: Any) -> Any:
"""
If `get_user_avatar()` fails, this function will return a default placeholder
"""
...
@fallback(get_default_user_avatar, on=ConnectionError)
async def get_user_avatar(user_id: str) -> bytes:
"""
Get user avatar from the object storage
"""
# ...
return b""
asyncio.run(get_user_avatar(user_id="1234"))
hyx.fallback.fallback(handler, *, name=None, on=Provides a fallback on exceptions and/or specific result of the original function
Parameters
- handler (Callable) - The fallback handler
- on (None | Exception | tuple[Exception, ...]) - Fall back on the give exception(s)
- if_ (None | Callable) - Fall back if the given predicate function returns True on the original function result
- name (None | str) - A component name or ID (will be passed to listeners and mention in metrics)
- listeners (None | Sequence[TimeoutListener]) - List of listeners of this concreate component state