redis-client-kit ships AsyncRedisProvider and it ships RedisMetrics, but nothing that
joins them, so every consumer writes the same provider. sqlalchemy-foundation-kit ships
exactly that join for Postgres — contrib.di.metrics.PrometheusPostgresMetricsProvider —
and the two kits are otherwise the same shape.
What we carry
class PrometheusRedisMetricsProvider(BaseMetricsProvider):
@provide
def get_metrics(
self,
metrics: PrometheusMetricsSettingsProtocol,
default_prefix: str | None,
redis: RedisMetricsSettingsProtocol | None = None,
) -> RedisMetrics | None:
if redis is None or not redis.metrics_enabled:
return None
return RedisMetrics(prefix=_infra_metrics_prefix(default_prefix))
@provide
def get_metrics_protocol(self, metrics: RedisMetrics | None) -> RedisMetricsProtocol | None:
return metrics
Everything it reads is yours: BaseRedisSettings.metrics_enabled (default False) is the
gate, RedisMetrics is the collector, RedisMetricsProtocol is the key
AsyncRedisProvider consumes. The only thing we contribute is the wiring, and it is the
same wiring for every consumer.
Registered next to yours, it reads:
make_async_container(
AsyncRedisProvider(provide_default_metrics=False),
PrometheusRedisMetricsProvider(), # ours, and it should be yours
...
)
The provide_default_metrics=False is the tell: AsyncRedisProvider already has an opinion
about who provides the metrics seam, and the alternative to its None is a provider the kit
does not ship.
The second half: the collector cannot be built twice
>>> RedisMetrics(prefix=None); RedisMetrics(prefix=None)
ValueError: Duplicated timeseries in CollectorRegistry: {'redis_pool_size', ...}
A container rebuilt per test — which is what a test suite does — asks for the collector
again and gets that. grpc-client-kit solved this with metrics.get_grpc_client_metrics():
one instance per prefix on the default registry, documented as "so a container rebuilt per
test never asks Prometheus to register the same series twice". A
get_redis_metrics(prefix=None) of the same shape would make the provider safe to register
in a fixture, and is worth having on its own even for consumers who never use dishka.
What we would use
redis_client_kit.providers.PrometheusRedisMetricsProvider, gated on
BaseRedisSettings.metrics_enabled, sourcing the collector from a cached getter — the
sqlalchemy-foundation-kit layout, since that is the one consumers already know. Then our
provider goes and dishka-providers loses another quarter of what is left of it.
Context: ai-ops, 11 services registering this provider. We have just deleted our postgres
and gRPC copies because those kits shipped theirs; Redis, inbox/outbox and idempotency are
the three left, and they are the same issue three times
(bedrock-python/omni-box, bedrock-python/idempotency-kit).
redis-client-kitshipsAsyncRedisProviderand it shipsRedisMetrics, but nothing thatjoins them, so every consumer writes the same provider.
sqlalchemy-foundation-kitshipsexactly that join for Postgres —
contrib.di.metrics.PrometheusPostgresMetricsProvider—and the two kits are otherwise the same shape.
What we carry
Everything it reads is yours:
BaseRedisSettings.metrics_enabled(defaultFalse) is thegate,
RedisMetricsis the collector,RedisMetricsProtocolis the keyAsyncRedisProviderconsumes. The only thing we contribute is the wiring, and it is thesame wiring for every consumer.
Registered next to yours, it reads:
The
provide_default_metrics=Falseis the tell:AsyncRedisProvideralready has an opinionabout who provides the metrics seam, and the alternative to its
Noneis a provider the kitdoes not ship.
The second half: the collector cannot be built twice
A container rebuilt per test — which is what a test suite does — asks for the collector
again and gets that.
grpc-client-kitsolved this withmetrics.get_grpc_client_metrics():one instance per prefix on the default registry, documented as "so a container rebuilt per
test never asks Prometheus to register the same series twice". A
get_redis_metrics(prefix=None)of the same shape would make the provider safe to registerin a fixture, and is worth having on its own even for consumers who never use dishka.
What we would use
redis_client_kit.providers.PrometheusRedisMetricsProvider, gated onBaseRedisSettings.metrics_enabled, sourcing the collector from a cached getter — thesqlalchemy-foundation-kitlayout, since that is the one consumers already know. Then ourprovider goes and
dishka-providersloses another quarter of what is left of it.Context: ai-ops, 11 services registering this provider. We have just deleted our postgres
and gRPC copies because those kits shipped theirs; Redis, inbox/outbox and idempotency are
the three left, and they are the same issue three times
(bedrock-python/omni-box, bedrock-python/idempotency-kit).