community-of-python / microbootstrap

Bootstrap your microservices in a second!
27 stars 2 forks source link

Add ability to configure an application that doesn't expose an HTTP API #36

Closed vrslev closed 1 week ago

vrslev commented 2 weeks ago

Currently microbootstrap doesn't handle apps that are not Litestar or FastAPI apps, moreover, do not expose any HTTP API.

An example is a worker: it just does some things without serving an API. This kind of applications still need logging, Sentry and OpenTelemetry.

We can change bootstrapper hierarchy into something like this:

class BaseBootstrapper:
    def use_instrument(cls): ...
    def configure_instrument(self, ...): ...
    def configure_instruments(self, ...): ...
    def teardown(self): ...

class ApplicationBootstrapper(BaseBootstrapper):
    ...

class LitestarBootstrapper(ApplicationBootstrapper):
    ...

class FastApiBootstrapper(ApplicationBootstrapper):
    ...

class WorkerBootstrapper(ApplicationBootstrapper):
    @contextlib.contextmanager
    def bootstrap(self): ...

And settings hierarchy as well:

class BaseServiceSettings: ...

class BaseApplicationSettings(BaseServiceSettings):
    server_host: str = "0.0.0.0"
    server_port: int = 8000
    server_reload: bool = True
    server_workers_count: int = 1

class LitestarSettings(
    BaseApplicationSettings,
    LoggingConfig,
    OpentelemetryConfig,
    SentryConfig,
    LitestarPrometheusConfig,
    SwaggerConfig,
    CorsConfig,
    HealthChecksConfig,
):
    ...

class FastApiSettings(
    BaseApplicationSettings,
    LoggingConfig,
    OpentelemetryConfig,
    SentryConfig,
    FastApiPrometheusConfig,
    SwaggerConfig,
    CorsConfig,
    HealthChecksConfig,
):
    ...

class WorkerSettings(
    BaseServiceSettings,
    LoggingConfig,
    OpentelemetryConfig,
    SentryConfig,
):
    ...

This way we would have a framework-agnostic bootstrapper. Of course, it would have only a subset of what Litestar/FastAPI bootstrappers can do.

vrslev commented 2 weeks ago

I see that OpentelemetryInstrument assumes that we are running an HTTP application. Can we make split it into OpentelemetryInstrument and ApplicationOpentelemetryInstrument?

vrslev commented 2 weeks ago

In the inner source package we have the enter_bootstrapper_context() context manager which I introduced while back:

def run_main() -> None:
    with enter_bootstrapper_context(
        LoggingBootstrapper, OpenTelemetryBootstrapper, SentryBootstrapper, settings=settings
    ):
        uvloop.run(worker_application.run_consumer())

The inner source package has quite different architecture underneath, though. I'm sure we won't be able to do something as simple as that.

insani7y commented 2 weeks ago

Hm, sounds good, but actually, there are no limitations to the bootstrapper, you can bootstrap literally everything you want. What kind of worker are you talking about? Our innersource has it's own mq library, but we are moving towards faststream step by step. Can you provide a worker example, that requires bootstrapping?

vrslev commented 2 weeks ago

Actually, I will be working on moving some services in my team to FastStream. The main issue with FastStream would be that it often enough is ran alongside an HTTP application.

vrslev commented 2 weeks ago

On our “workers”: they’re handwritten (no framework such as FastStream) application, that are executed in separate containers. They process message streams

vrslev commented 2 weeks ago

Hm, sounds good, but actually, there are no limitations to the bootstrapper, you can bootstrap literally everything you want.

You mean that there’s no need to have another bootstrapper? I second that: there’re plenty of “generic” applications, not Litestar/FastAPI, that can benefit from microbootstrap