Skip to content

Fallbacks

Introduction

When your downstream microservices fall apart, retries exceed or breakers fire on, you need to have a solid plan B that will cover this failure up for the upstream microservices. Otherwise, the whole request chain would fail in a cascading fashion all the way up.

This plan B is normally called a fallback, and it comes in different forms depending on the context and functionality to fill.

Use Cases

  • Show a default or cached value if the downstream dependency is not responding (e.g. show a placeholder instead of the actual user's avatar)
  • Log and silence the exception (e.g. if the message broker is not responding, and you can miss the message)
  • Use some functional redundancy in a 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=, if_=None, listeners=None, event_manager=None)

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