mode

AsyncIO Service-based programming.

class mode.BaseSignal(*, name: Optional[str] = None, owner: Optional[Type] = None, loop: Optional[AbstractEventLoop] = None, default_sender: Optional[Any] = None, receivers: Optional[MutableSet[Union[Callable[[], Union[Callable[[T, Any, BaseSignalT, Any], None], Callable[[T, Any, BaseSignalT, Any], Awaitable[None]]]], weakref[Union[Callable[[T, Any, mode.types.signals.BaseSignalT, Any], NoneType], Callable[[T, Any, mode.types.signals.BaseSignalT, Any], Awaitable[NoneType]]]]]]] = None, filter_receivers: Optional[MutableMapping[Any, MutableSet[Union[Callable[[], Union[Callable[[T, Any, BaseSignalT, Any], None], Callable[[T, Any, BaseSignalT, Any], Awaitable[None]]]], weakref[Union[Callable[[T, Any, mode.types.signals.BaseSignalT, Any], NoneType], Callable[[T, Any, mode.types.signals.BaseSignalT, Any], Awaitable[NoneType]]]]]]]] = None)

Base class for signal/observer pattern.

asdict() Mapping[str, Any]
clone(**kwargs: Any) BaseSignalT
connect(fun: Optional[Union[Callable[[T, Any, BaseSignalT, Any], None], Callable[[T, Any, BaseSignalT, Any], Awaitable[None]]]] = None, **kwargs: Any) Callable
disconnect(fun: Union[Callable[[T, Any, BaseSignalT, Any], None], Callable[[T, Any, BaseSignalT, Any], Awaitable[None]]], *, weak: bool = False, sender: Optional[Any] = None) None
property ident: str
iter_receivers(sender: T_contra) Iterable[Union[Callable[[T, Any, BaseSignalT, Any], None], Callable[[T, Any, BaseSignalT, Any], Awaitable[None]]]]
property label: str
unpack_sender_from_args(*args: Any) tuple[T, tuple[Any, ...]]
with_default_sender(sender: Optional[Any] = None) BaseSignalT
class mode.BaseSignalT(*, name: Optional[str] = None, owner: Optional[Type] = None, loop: Optional[AbstractEventLoop] = None, default_sender: Optional[Any] = None, receivers: Optional[MutableSet[Union[Callable[[], Union[Callable[[T, Any, BaseSignalT, Any], None], Callable[[T, Any, BaseSignalT, Any], Awaitable[None]]]], weakref[Union[Callable[[T, Any, mode.types.signals.BaseSignalT, Any], NoneType], Callable[[T, Any, mode.types.signals.BaseSignalT, Any], Awaitable[NoneType]]]]]]] = None, filter_receivers: Optional[MutableMapping[Any, MutableSet[Union[Callable[[], Union[Callable[[T, Any, BaseSignalT, Any], None], Callable[[T, Any, BaseSignalT, Any], Awaitable[None]]]], weakref[Union[Callable[[T, Any, mode.types.signals.BaseSignalT, Any], NoneType], Callable[[T, Any, mode.types.signals.BaseSignalT, Any], Awaitable[NoneType]]]]]]]] = None)

Base type for all signals.

abstract clone(**kwargs: Any) BaseSignalT
abstract connect(fun: Union[Callable[[T, Any, BaseSignalT, Any], None], Callable[[T, Any, BaseSignalT, Any], Awaitable[None]]], **kwargs: Any) Callable
abstract disconnect(fun: Union[Callable[[T, Any, BaseSignalT, Any], None], Callable[[T, Any, BaseSignalT, Any], Awaitable[None]]], *, sender: Optional[Any] = None, weak: bool = True) None
name: str
owner: Optional[Type]
abstract with_default_sender(sender: Optional[Any] = None) BaseSignalT
class mode.CrashingSupervisor(*services: ~mode.types.services.ServiceT, max_restarts: ~typing.Union[~datetime.timedelta, int, float, str] = 100.0, over: ~typing.Union[~datetime.timedelta, int, float, str] = 1.0, raises: ~typing.Type[BaseException] = <class 'mode.exceptions.MaxRestartsExceeded'>, replacement: ~typing.Optional[~typing.Callable[[~mode.types.services.ServiceT, int], ~typing.Awaitable[~mode.types.services.ServiceT]]] = None, **kwargs: ~typing.Any)

Supervisor that crashes the whole program.

logger: logging.Logger = <Logger mode.supervisors (WARNING)>
wakeup() None
class mode.ForfeitOneForAllSupervisor(*services: ~mode.types.services.ServiceT, max_restarts: ~typing.Union[~datetime.timedelta, int, float, str] = 100.0, over: ~typing.Union[~datetime.timedelta, int, float, str] = 1.0, raises: ~typing.Type[BaseException] = <class 'mode.exceptions.MaxRestartsExceeded'>, replacement: ~typing.Optional[~typing.Callable[[~mode.types.services.ServiceT, int], ~typing.Awaitable[~mode.types.services.ServiceT]]] = None, **kwargs: ~typing.Any)

If one service in the group crashes, we give up on all of them.

logger: logging.Logger = <Logger mode.supervisors (WARNING)>
async restart_services(services: list[mode.types.services.ServiceT]) None
class mode.ForfeitOneForOneSupervisor(*services: ~mode.types.services.ServiceT, max_restarts: ~typing.Union[~datetime.timedelta, int, float, str] = 100.0, over: ~typing.Union[~datetime.timedelta, int, float, str] = 1.0, raises: ~typing.Type[BaseException] = <class 'mode.exceptions.MaxRestartsExceeded'>, replacement: ~typing.Optional[~typing.Callable[[~mode.types.services.ServiceT, int], ~typing.Awaitable[~mode.types.services.ServiceT]]] = None, **kwargs: ~typing.Any)

Supervisor that if a service crashes, we do not restart it.

logger: logging.Logger = <Logger mode.supervisors (WARNING)>
async restart_services(services: list[mode.types.services.ServiceT]) None
class mode.OneForAllSupervisor(*services: ~mode.types.services.ServiceT, max_restarts: ~typing.Union[~datetime.timedelta, int, float, str] = 100.0, over: ~typing.Union[~datetime.timedelta, int, float, str] = 1.0, raises: ~typing.Type[BaseException] = <class 'mode.exceptions.MaxRestartsExceeded'>, replacement: ~typing.Optional[~typing.Callable[[~mode.types.services.ServiceT, int], ~typing.Awaitable[~mode.types.services.ServiceT]]] = None, **kwargs: ~typing.Any)

Supervisor that restarts all services when a service crashes.

logger: logging.Logger = <Logger mode.supervisors (WARNING)>
async restart_services(services: list[mode.types.services.ServiceT]) None
class mode.OneForOneSupervisor(*services: ~mode.types.services.ServiceT, max_restarts: ~typing.Union[~datetime.timedelta, int, float, str] = 100.0, over: ~typing.Union[~datetime.timedelta, int, float, str] = 1.0, raises: ~typing.Type[BaseException] = <class 'mode.exceptions.MaxRestartsExceeded'>, replacement: ~typing.Optional[~typing.Callable[[~mode.types.services.ServiceT, int], ~typing.Awaitable[~mode.types.services.ServiceT]]] = None, **kwargs: ~typing.Any)

Supervisor simply restarts any crashed service.

logger: logging.Logger = <Logger mode.supervisors (WARNING)>
class mode.Service(*, beacon: Optional[NodeT] = None, loop: Optional[AbstractEventLoop] = None)

An asyncio service that can be started/stopped/restarted.

Keyword Arguments:
  • beacon (NodeT) – Beacon used to track services in a graph.

  • loop (AbstractEventLoop) – Event loop object.

class Diag(service: ServiceT)

Service diagnostics.

This can be used to track what your service is doing. For example if your service is a Kafka consumer with a background thread that commits the offset every 30 seconds, you may want to see when this happens:

DIAG_COMMITTING = 'committing'

class Consumer(Service):

    @Service.task
    async def _background_commit(self) -> None:
        while not self.should_stop:
            await self.sleep(30.0)
            self.diag.set_flag(DIAG_COMITTING)
            try:
                await self._consumer.commit()
            finally:
                self.diag.unset_flag(DIAG_COMMITTING)

The above code is setting the flag manually, but you can also use a decorator to accomplish the same thing:

@Service.timer(30.0)
async def _background_commit(self) -> None:
    await self.commit()

@Service.transitions_with(DIAG_COMITTING)
async def commit(self) -> None:
    await self._consumer.commit()
set_flag(flag: str) None
unset_flag(flag: str) None
abstract: ClassVar[bool] = False

Set to True if this service class is abstract-only, meaning it will only be used as a base class.

async add_async_context(context: AsyncContextManager) Any
add_context(context: ContextManager) Any
add_dependency(service: ServiceT) ServiceT

Add dependency to other service.

The service will be started/stopped with this service.

add_future(coro: Awaitable) Future

Add relationship to asyncio.Future.

The future will be joined when this service is stopped.

async add_runtime_dependency(service: ServiceT) ServiceT
property beacon: NodeT

Beacon used to track services in a dependency graph.

async crash(reason: BaseException) None

Crash the service and all child services.

property crash_reason: Optional[BaseException]
property crashed: bool
classmethod crontab(cron_format: str, *, timezone: Optional[tzinfo] = None) Callable[[Callable], ServiceTask]

Background timer executing periodic task based on Crontab description.

Example

>>> class S(Service):
...
...     @Service.crontab(cron_format='30 18 * * *',
                         timezone=pytz.timezone('US/Pacific'))
...     async def every_6_30_pm_pacific(self):
...         print('IT IS 6:30pm')
...
...     @Service.crontab(cron_format='30 18 * * *')
...     async def every_6_30_pm(self):
...         print('6:30pm UTC')
classmethod from_awaitable(coro: Awaitable, *, name: Optional[str] = None, **kwargs: Any) ServiceT
human_tracebacks() str
async itertimer(interval: ~typing.Union[~datetime.timedelta, int, float, str], *, max_drift_correction: float = 0.1, sleep: ~typing.Optional[~typing.Callable[[...], ~typing.Awaitable]] = None, clock: ~typing.Callable[[], float] = <built-in function perf_counter>, name: str = '') AsyncIterator[float]

Sleep interval seconds for every iteration.

This is an async iterator that takes advantage of Timer() to monitor drift and timer oerlap.

Uses Service.sleep so exits fast when the service is stopped.

Note

Will sleep the full interval seconds before returning from first iteration.

Examples

>>> async for sleep_time in self.itertimer(1.0):
...   print('another second passed, just woke up...')
...   await perform_some_http_request()
async join_services(services: Sequence[ServiceT]) None
property label: str

Label used for graphs.

logger: logging.Logger = <Logger mode.services (WARNING)>
async maybe_start() bool

Start the service, if it has not already been started.

mundane_level = 'info'

The log level for mundane info such as starting, stopping, etc. Set this to "debug" for less information.

on_init_dependencies() Iterable[ServiceT]

Return list of service dependencies for this service.

async remove_dependency(service: ServiceT) ServiceT

Stop and remove dependency of this service.

async restart() None

Restart this service.

restart_count: int = 0

Current number of times this service instance has been restarted.

service_reset() None
set_shutdown() None

Set the shutdown signal.

Notes

If wait_for_shutdown is set, stopping the service will wait for this flag to be set.

property shortlabel: str

Label used for logging.

property should_stop: bool

Return True if the service must stop.

shutdown_timeout: float = 60.0

Time to wait for shutdown flag set before we give up.

async sleep(n: Union[timedelta, int, float, str]) None

Sleep for n seconds, or until service stopped.

async start() None
property started: bool

Return True if the service was started.

property state: str

Service state - as a human readable string.

async stop() None

Stop the service.

classmethod task(fun: Callable[[Any], Awaitable[None]]) ServiceTask

Decorate function to be used as background task.

Example

>>> class S(Service):
...
...     @Service.task
...     async def background_task(self):
...         while not self.should_stop:
...             await self.sleep(1.0)
...             print('Waking up')
classmethod timer(interval: Union[timedelta, int, float, str], *, exec_first: bool = False, name: Optional[str] = None, max_drift_correction: float = 0.1) Callable[[Callable], ServiceTask]

Background timer executing every n seconds.

Example

>>> class S(Service):
...
...     @Service.timer(1.0)
...     async def background_timer(self):
...         print('Waking up')
tracebacks() Mapping[str, str]
async transition_with(flag: str, fut: Awaitable, *args: Any, **kwargs: Any) Any
classmethod transitions_to(flag: str) Callable

Decorate function to set and reset diagnostic flag.

async wait(*coros: Union[Future, Generator[Any, None, Any], Awaitable, Event], timeout: Optional[Union[timedelta, int, float, str]] = None) WaitResult

Wait for coroutines to complete, or until the service stops.

async wait_first(*coros: Union[Future, Generator[Any, None, Any], Awaitable, Event], timeout: Optional[Union[timedelta, int, float, str]] = None) WaitResults
wait_for_shutdown: bool = False

Set to True if .stop must wait for the shutdown flag to be set.

async wait_for_stopped(*coros: Union[Future, Generator[Any, None, Any], Awaitable, Event], timeout: Optional[Union[timedelta, int, float, str]] = None) bool
async wait_many(coros: Iterable[Union[Future, Generator[Any, None, Any], Awaitable, Event]], *, timeout: Optional[Union[timedelta, int, float, str]] = None) WaitResult
async wait_until_stopped() None

Wait until the service is signalled to stop.

class mode.ServiceT(*, beacon: Optional[NodeT] = None, loop: Optional[AbstractEventLoop] = None)

Abstract type for an asynchronous service that can be started/stopped.

See also

mode.Service.

Diag: Type[DiagT]
abstract async add_async_context(context: AsyncContextManager) Any
abstract add_context(context: ContextManager) Any
abstract add_dependency(service: ServiceT) ServiceT
abstract async add_runtime_dependency(service: ServiceT) ServiceT
async_exit_stack: AsyncExitStack
property beacon: NodeT
abstract async crash(reason: BaseException) None
abstract property crash_reason: Optional[BaseException]
abstract property crashed: bool
diag: DiagT
exit_stack: ExitStack
abstract property label: str
abstract property loop: AbstractEventLoop
abstract async maybe_start() bool
abstract async restart() None
restart_count: int = 0
abstract service_reset() None
abstract set_shutdown() None
abstract property shortlabel: str
abstract property should_stop: bool
shutdown_timeout: float
abstract async start() None
abstract property started: bool
abstract property state: str
abstract async stop() None
supervisor: Optional[SupervisorStrategyT] = None
wait_for_shutdown: bool = False
abstract async wait_until_stopped() None
class mode.Signal(*, name: Optional[str] = None, owner: Optional[Type] = None, loop: Optional[AbstractEventLoop] = None, default_sender: Optional[Any] = None, receivers: Optional[MutableSet[Union[Callable[[], Union[Callable[[T, Any, BaseSignalT, Any], None], Callable[[T, Any, BaseSignalT, Any], Awaitable[None]]]], weakref[Union[Callable[[T, Any, mode.types.signals.BaseSignalT, Any], NoneType], Callable[[T, Any, mode.types.signals.BaseSignalT, Any], Awaitable[NoneType]]]]]]] = None, filter_receivers: Optional[MutableMapping[Any, MutableSet[Union[Callable[[], Union[Callable[[T, Any, BaseSignalT, Any], None], Callable[[T, Any, BaseSignalT, Any], Awaitable[None]]]], weakref[Union[Callable[[T, Any, mode.types.signals.BaseSignalT, Any], NoneType], Callable[[T, Any, mode.types.signals.BaseSignalT, Any], Awaitable[NoneType]]]]]]]] = None)

Asynchronous signal (using async def functions).

clone(**kwargs: Any) SignalT
async send(*args: Any, **kwargs: Any) None
with_default_sender(sender: Any = None) SignalT
class mode.SignalT(*, name: Optional[str] = None, owner: Optional[Type] = None, loop: Optional[AbstractEventLoop] = None, default_sender: Optional[Any] = None, receivers: Optional[MutableSet[Union[Callable[[], Union[Callable[[T, Any, BaseSignalT, Any], None], Callable[[T, Any, BaseSignalT, Any], Awaitable[None]]]], weakref[Union[Callable[[T, Any, mode.types.signals.BaseSignalT, Any], NoneType], Callable[[T, Any, mode.types.signals.BaseSignalT, Any], Awaitable[NoneType]]]]]]] = None, filter_receivers: Optional[MutableMapping[Any, MutableSet[Union[Callable[[], Union[Callable[[T, Any, BaseSignalT, Any], None], Callable[[T, Any, BaseSignalT, Any], Awaitable[None]]]], weakref[Union[Callable[[T, Any, mode.types.signals.BaseSignalT, Any], NoneType], Callable[[T, Any, mode.types.signals.BaseSignalT, Any], Awaitable[NoneType]]]]]]]] = None)

Base class for all async signals (using async def).

abstract clone(**kwargs: Any) SignalT
abstract async send(sender: T_contra, *args: Any, **kwargs: Any) None
abstract with_default_sender(sender: Any = None) SignalT
class mode.SupervisorStrategy(*services: ~mode.types.services.ServiceT, max_restarts: ~typing.Union[~datetime.timedelta, int, float, str] = 100.0, over: ~typing.Union[~datetime.timedelta, int, float, str] = 1.0, raises: ~typing.Type[BaseException] = <class 'mode.exceptions.MaxRestartsExceeded'>, replacement: ~typing.Optional[~typing.Callable[[~mode.types.services.ServiceT, int], ~typing.Awaitable[~mode.types.services.ServiceT]]] = None, **kwargs: ~typing.Any)

Base class for all supervisor strategies.

add(*services: ServiceT) None
discard(*services: ServiceT) None
insert(index: int, service: ServiceT) None
property label: str

Label used for graphs.

logger: logging.Logger = <Logger mode.supervisors (WARNING)>
async on_start() None

Service is starting.

async on_stop() None

Service is being stopped/restarted.

async restart_service(service: ServiceT) None
async restart_services(services: list[mode.types.services.ServiceT]) None
async run_until_complete() None
service_operational(service: ServiceT) bool
async start_service(service: ServiceT) None
async start_services(services: list[mode.types.services.ServiceT]) None
async stop_services(services: list[mode.types.services.ServiceT]) None
wakeup() None
class mode.SupervisorStrategyT(*services: ServiceT, max_restarts: Union[timedelta, int, float, str] = 100.0, over: Union[timedelta, int, float, str] = 1.0, raises: Optional[Type[BaseException]] = None, replacement: Optional[Callable[[ServiceT, int], Awaitable[ServiceT]]] = None, **kwargs: Any)

Base type for all supervisor strategies.

abstract add(*services: ServiceT) None
abstract discard(*services: ServiceT) None
max_restarts: float
over: float
raises: Type[BaseException]
abstract async restart_service(service: ServiceT) None
abstract service_operational(service: ServiceT) bool
abstract wakeup() None
class mode.SyncSignal(*, name: Optional[str] = None, owner: Optional[Type] = None, loop: Optional[AbstractEventLoop] = None, default_sender: Optional[Any] = None, receivers: Optional[MutableSet[Union[Callable[[], Union[Callable[[T, Any, BaseSignalT, Any], None], Callable[[T, Any, BaseSignalT, Any], Awaitable[None]]]], weakref[Union[Callable[[T, Any, mode.types.signals.BaseSignalT, Any], NoneType], Callable[[T, Any, mode.types.signals.BaseSignalT, Any], Awaitable[NoneType]]]]]]] = None, filter_receivers: Optional[MutableMapping[Any, MutableSet[Union[Callable[[], Union[Callable[[T, Any, BaseSignalT, Any], None], Callable[[T, Any, BaseSignalT, Any], Awaitable[None]]]], weakref[Union[Callable[[T, Any, mode.types.signals.BaseSignalT, Any], NoneType], Callable[[T, Any, mode.types.signals.BaseSignalT, Any], Awaitable[NoneType]]]]]]]] = None)

Signal that is synchronous (using regular def functions).

clone(**kwargs: Any) SyncSignalT
send(*args: Any, **kwargs: Any) None
with_default_sender(sender: Any = None) SyncSignalT
class mode.SyncSignalT(*, name: Optional[str] = None, owner: Optional[Type] = None, loop: Optional[AbstractEventLoop] = None, default_sender: Optional[Any] = None, receivers: Optional[MutableSet[Union[Callable[[], Union[Callable[[T, Any, BaseSignalT, Any], None], Callable[[T, Any, BaseSignalT, Any], Awaitable[None]]]], weakref[Union[Callable[[T, Any, mode.types.signals.BaseSignalT, Any], NoneType], Callable[[T, Any, mode.types.signals.BaseSignalT, Any], Awaitable[NoneType]]]]]]] = None, filter_receivers: Optional[MutableMapping[Any, MutableSet[Union[Callable[[], Union[Callable[[T, Any, BaseSignalT, Any], None], Callable[[T, Any, BaseSignalT, Any], Awaitable[None]]]], weakref[Union[Callable[[T, Any, mode.types.signals.BaseSignalT, Any], NoneType], Callable[[T, Any, mode.types.signals.BaseSignalT, Any], Awaitable[NoneType]]]]]]]] = None)

Base class for all synchronous signals (using regular def).

abstract clone(**kwargs: Any) SyncSignalT
abstract send(sender: T_contra, *args: Any, **kwargs: Any) None
abstract with_default_sender(sender: Any = None) SyncSignalT
class mode.Worker(*services: ServiceT, debug: bool = False, quiet: bool = False, log_level: Severity = 20, log_file: str | os.PathLike | IO | None = None, log_handlers: Iterable[Handler] | None = None, redirect_stdouts: bool = True, redirect_stdouts_level: Severity = 30, stdout: IO | None = <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>, stderr: IO | None = <_io.TextIOWrapper name='<stderr>' mode='w' encoding='utf-8'>, override_logging: bool = True, logging_config: dict | None = None, console_port: int = 50101, blocking_timeout: Seconds = 10.0, daemon: bool = True, loop: asyncio.AbstractEventLoop | None = None, **kwargs: Any)

Start mode service from the command-line.

BLOCK_DETECTOR: ClassVar[str] = 'mode.debug:BlockingDetector'
property blocking_detector: BlockingDetector
blocking_timeout: Seconds
carp(msg: str) None

Write warning to standard err.

console_port: int
debug: bool
async default_on_first_start() None
execute_from_commandline() NoReturn
install_signal_handlers() None
log_file: str | os.PathLike | IO | None
log_handlers: list[Handler]
log_level: Severity | None
logger: logging.Logger = <Logger mode.worker (WARNING)>
logging_config: dict | None
async maybe_start_blockdetection() None
async on_execute() None
async on_first_start() None

Service started for the first time in this process.

on_init_dependencies() Iterable[ServiceT]

Return list of service dependencies for this service.

on_setup_root_logger(logger: Logger, level: int) None
async on_started() None

Service has started.

on_worker_shutdown() None
quiet: bool
redirect_stdouts: bool
redirect_stdouts_level: int
say(msg: str) None

Write message to standard out.

services: Iterable[ServiceT]
stderr: IO
stdout: IO
stop_and_shutdown() None
class mode.flight_recorder(logger: Logger, *, timeout: Union[timedelta, int, float, str], loop: Optional[AbstractEventLoop] = None)

Flight Recorder context for use with with statement.

This is a logging utility to log stuff only when something times out.

For example if you have a background thread that is sometimes hanging:

class RedisCache(mode.Service):

    @mode.timer(1.0)
    def _background_refresh(self) -> None:
        self._users = await self.redis_client.get(USER_KEY)
        self._posts = await self.redis_client.get(POSTS_KEY)

You want to figure out on what line this is hanging, but logging all the time will provide way too much output, and will even change how fast the program runs and that can mask race conditions, so that they never happen.

Use the flight recorder to save the logs and only log when it times out:

logger = mode.get_logger(__name__)

class RedisCache(mode.Service):

    @mode.timer(1.0)
    def _background_refresh(self) -> None:
        with mode.flight_recorder(logger, timeout=10.0) as on_timeout:
            on_timeout.info(f'+redis_client.get({USER_KEY!r})')
            await self.redis_client.get(USER_KEY)
            on_timeout.info(f'-redis_client.get({USER_KEY!r})')

            on_timeout.info(f'+redis_client.get({POSTS_KEY!r})')
            await self.redis_client.get(POSTS_KEY)
            on_timeout.info(f'-redis_client.get({POSTS_KEY!r})')

If the body of this with statement completes before the timeout, the logs are forgotten about and never emitted – if it takes more than ten seconds to complete, we will see these messages in the log:

[2018-04-19 09:43:55,877: WARNING]: Warning: Task timed out!
[2018-04-19 09:43:55,878: WARNING]:
    Please make sure it is hanging before restarting.
[2018-04-19 09:43:55,878: INFO]: [Flight Recorder-1]
    (started at Thu Apr 19 09:43:45 2018) Replaying logs...
[2018-04-19 09:43:55,878: INFO]: [Flight Recorder-1]
    (Thu Apr 19 09:43:45 2018) +redis_client.get('user')
[2018-04-19 09:43:55,878: INFO]: [Flight Recorder-1]
    (Thu Apr 19 09:43:49 2018) -redis_client.get('user')
[2018-04-19 09:43:55,878: INFO]: [Flight Recorder-1]
    (Thu Apr 19 09:43:46 2018) +redis_client.get('posts')
[2018-04-19 09:43:55,878: INFO]: [Flight Recorder-1] -End of log-

Now we know this redis_client.get call can take too long to complete, and should consider adding a timeout to it.

activate() None
blush() None
cancel() None
enabled_by: _asyncio.Task | None
extra_context: dict[str, Any]
flush_logs(ident: Optional[str] = None) None
log(severity: int, message: str, *args: Any, **kwargs: Any) None
logger: Logger
loop: AbstractEventLoop
started_at_date: str | None
timeout: float
wrap(severity: int, obj: Any) Logwrapped
wrap_debug(obj: Any) Logwrapped
wrap_error(obj: Any) Logwrapped
wrap_info(obj: Any) Logwrapped
wrap_warn(obj: Any) Logwrapped
mode.get_logger(name: str) Logger

Get logger by name.

mode.label(s: Any) str

Return the name of an object as string.

mode.setup_logging(*, log_level: Optional[Union[int, str]] = None, log_file: Optional[Union[PathLike, str, IO]] = None, log_handlers: Optional[Iterable[Handler]] = None, logging_config: Optional[dict] = None) int

Configure logging subsystem.

mode.shortlabel(s: Any) str

Return the shortened name of an object as string.

mode.task(fun: Callable[[Any], Awaitable[None]]) ServiceTask

Decorate function to be used as background task.

Example

>>> class S(Service):
...
...     @Service.task
...     async def background_task(self):
...         while not self.should_stop:
...             await self.sleep(1.0)
...             print('Waking up')
mode.timer(interval: Union[timedelta, int, float, str], *, exec_first: bool = False, name: Optional[str] = None, max_drift_correction: float = 0.1) Callable[[Callable], ServiceTask]

Background timer executing every n seconds.

Example

>>> class S(Service):
...
...     @Service.timer(1.0)
...     async def background_timer(self):
...         print('Waking up')
mode.want_seconds(s: int | float | str | datetime.timedelta) float
mode.want_seconds(s: int | float) float
mode.want_seconds(s: int | float) float
mode.want_seconds(s: str) float
mode.want_seconds(s: timedelta) float

Convert Seconds to float.