docs: async def component_coro_wrapper(coro_func: CoroutineFunction[T],
                                   *args: Any, commands: PipeEnd, events: PipeEnd, **kwargs: Any) -> T:
      """\
      This function wraps a component workload to conform to the required lifecycle.
      The following behavior is the passed coroutine function's responsibility:
  
      - it must send `Component.EVENT_START` to its owner after the task is initialized;
      - it must not send EOF on the event pipe;
      - when `Component.COMMAND_STOP` is received, it should either stop eventually, or send an event to its owner;
      - when it is cancelled, it should either stop eventually, or send an event to its owner.
  
      Also, any `Component.LifecycleError` raised will be wrapped in `Component.Failure`.
      """
      try:
          return await coro_func(*args, commands=commands, events=events, **kwargs)
      except Exception as err:
          raise Component.Failure(err) from None
      finally:
          try:
              await events.send(eof=True)
          except EOFError as err:
              raise Component.LifecycleError("component closed events pipe manually") from err