Repository: Significant-Gravitas/Auto-GPT
File: autogpt_platform/backend/backend/util/service.py (Python)

Code before:
                secrets.supabase_url, secrets.supabase_service_role_key
            )

        # Start the FastAPI server in a separate thread.
        api_thread = threading.Thread(target=self.__start_fastapi, daemon=True)
        api_thread.start()

        # Run the main service loop (blocking).
        self.run_service()

    def cleanup(self):
        if self.use_db:
            logger.info(f"[{self.__class__.__name__}] ⏳ Disconnecting DB...")
            self.run_and_wait(db.disconnect())
        if self.use_redis:
            logger.info(f"[{self.__class__.__name__}] ⏳ Disconnecting Redis...")
            redis.disconnect()
        if self.rabbitmq_config:
            logger.info(f"[{self.__class__.__name__}] ⏳ Disconnecting RabbitMQ...")

    @conn_retry("FastAPI server", "Starting FastAPI server")
    def __start_fastapi(self):
        port = self.get_port()
        host = self.get_host()
        logger.info(
            f"[{self.service_name}] Starting FastAPI server at http://{host}:{port}"
        )
        server = uvicorn.Server(uvicorn.Config(self.fastapi_app, host=host, port=port))
        self.shared_event_loop.run_until_complete(server.serve())


# --------------------------------------------------
# HTTP Client utilities for dynamic service client abstraction
# --------------------------------------------------
AS = TypeVar("AS", bound=AppService)


class HttpClient:
    """
    A simple HTTP client abstraction for making remote calls to a FastAPI service.
    """

    def __init__(self, base_url: str):
        self.base_url = base_url.rstrip("/")
        self.client = httpx.Client()

    def call_method(self, method_name: str, **kwargs) -> Any:
        try:
            url = f"{self.base_url}/{method_name}"
            response = self.client.post(url, json=to_dict(kwargs))
            response.raise_for_status()

Review comment (suggestion):
```suggestion
            f"[{self.service_name}] Starting RPC server at http://{host}:{port}"
```

Code after:

if config.use_http_based_rpc:
    expose = fastapi_expose
    exposed_run_and_wait = fastapi_exposed_run_and_wait
else:
    expose = pyro_expose
    exposed_run_and_wait = pyro_exposed_run_and_wait

# ----- End Pyro Expose Block ---- #


# --------------------------------------------------
# AppService for IPC service based on HTTP request through FastAPI
# --------------------------------------------------
class BaseAppService(AppProcess, ABC):
    shared_event_loop: asyncio.AbstractEventLoop
    use_db: bool = False
    use_redis: bool = False
    rabbitmq_config: Optional[rabbitmq.RabbitMQConfig] = None
    rabbitmq_service: Optional[rabbitmq.AsyncRabbitMQ] = None
    use_supabase: bool = False

    @classmethod
    @abstractmethod
    def get_port(cls) -> int:
        pass

    @classmethod
    def get_host(cls) -> str:
        return os.environ.get(f"{cls.service_name.upper()}_HOST", api_host)

    @property
    def rabbit(self) -> rabbitmq.AsyncRabbitMQ:
        """Access the RabbitMQ service. Will raise if not configured."""
        if not self.rabbitmq_service:
            raise RuntimeError("RabbitMQ not configured for this service")
        return self.rabbitmq_service

    @property
    def rabbit_config(self) -> rabbitmq.RabbitMQConfig:
        """Access the RabbitMQ config. Will raise if not configured."""
        if not self.rabbitmq_config:
            raise RuntimeError("RabbitMQ not configured for this service")
        return self.rabbitmq_config

    def run_service(self) -> None:
        while True:
            time.sleep(10)

    def run_and_wait(self, coro: Coroutine[Any, Any, T]) -> T:
        return asyncio.run_coroutine_threadsafe(coro, self.shared_event_loop).result()