Files
build-your-own-openclaw/10-websocket/src/mybot/server/worker.py
T
2026-03-10 22:35:02 -04:00

61 lines
1.8 KiB
Python

"""Base worker lifecycle management."""
import asyncio
import logging
from abc import ABC, abstractmethod
class Worker(ABC):
"""Base class for all workers with lifecycle management."""
def __init__(self, context):
self.context = context
self.logger = logging.getLogger(f"mybot.server.{self.__class__.__name__}")
self._task: asyncio.Task | None = None
@abstractmethod
async def run(self) -> None:
"""Main worker loop. Runs until cancelled."""
pass
def start(self) -> asyncio.Task:
"""Start the worker as an asyncio Task."""
self._task = asyncio.create_task(self.run())
return self._task
def is_running(self) -> bool:
"""Check if worker is actively running."""
return self._task is not None and not self._task.done()
def has_crashed(self) -> bool:
"""Check if worker crashed (done but not cancelled)."""
return (
self._task is not None and self._task.done() and not self._task.cancelled()
)
def get_exception(self) -> BaseException | None:
"""Get the exception if worker crashed, None otherwise."""
if self.has_crashed() and self._task is not None:
return self._task.exception()
return None
async def stop(self) -> None:
"""Gracefully stop the worker."""
if self._task:
self._task.cancel()
try:
await self._task
except asyncio.CancelledError:
pass
class SubscriberWorker(Worker):
"""Worker that only subscribes to events, no active loop."""
async def run(self) -> None:
"""Wait for cancellation - actual work happens in event handlers."""
try:
await asyncio.Future()
except asyncio.CancelledError:
pass