mode.services — mode-ng 0.4.0 documentation

# `mode.services`

Async I/O services that can be started/stopped/shutdown.

class mode.services.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

class mode.services.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
  async_exit_stack: AsyncExitStack
  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')

  diag: DiagT
  exit_stack: ExitStack
  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.

  log: CompositeLogger
  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.services.ServiceBase(*, loop: Optional[AbstractEventLoop] = None)

  Base class for services.

  abstract: ClassVar[bool] = True

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

  log: CompositeLogger
  logger: Logger = None
  property loop: AbstractEventLoop

mode.services.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')

mode.services.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.services.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')