core.strangler_router module
DEPRECATED (Phase T3, 2026-06-02) — retained for historical reference.
The strangler-fig router used to decide, per channel/guild, whether a
message was handled by the legacy monolith or the new microservices.
Now that the monolith is gone and all traffic routes over the event
bus, StranglerRouter is no longer instantiated by any
service. Do not import or use it in new code; it is documented
only to explain the migration history.
- class core.strangler_router.StranglerRouter(redis)[source]
Bases:
objectDEPRECATED strangler-fig router for monolith-vs-microservice traffic.
During the migration this decided, per channel / guild / platform, whether an inbound message was handled by the legacy monolith or the new microservices, using a cached rule hierarchy plus a percentage rollout knob so traffic could be shifted gradually and safely. As of Phase T3 (2026-06-02) the monolith is gone and all traffic routes over the event bus, so no live service constructs this class – it is retained only to document the migration and is exercised solely by
tests/core/migration/test_strangler_router.py.Reads its rules from the
sg:strangler:routesRedis hash, subscribes to thesg:pubsub:configchannel to invalidate its in-memory cache when an operator script (scripts/canary_rollout.py,scripts/enable_shadow_mode.py) republishes routes, and shields the cache-miss path with aCircuitBreakerso a flaky Redis falls back to a safe default rather than failing routing. Do not import or instantiate it in new code.- __init__(redis)[source]
Initialize the router with a Redis handle and an empty route cache.
Sets up the in-memory
_cachedict that holds routing rules pulled from Redis, aCircuitBreaker(failure_threshold=3,reset_timeout=30.0) guarding the cache-miss path against a flaky Redis, an unset_listen_taskhandle for the background invalidation listener, and a_default_routeof"monolith"used as the safe fallback.This only stores the passed
redishandle and constructs the circuit breaker; it performs no I/O, so the cache is populated lazily on the first_fetch_route()call. Since the module is deprecated (Phase T3) no live service constructs this class; the only caller is the test suite (tests/core/migration/test_strangler_router.py).- Parameters:
redis – An async Redis client (e.g.
redis.asyncio.Redis) used forhgetallof the routes hash and for pub/sub subscription to config-change notifications.
- async start()[source]
Launch the background cache-invalidation listener.
Schedules
_listen_for_invalidations()as a fire-and-forgetasynciotask and stores its handle onself._listen_tasksostop()can cancel it later. Returns immediately without awaiting the listener.This calls
asyncio.create_task(); the spawned task subscribes to thesg:pubsub:configRedis channel and clearsself._cacheon any published message. Historically called byGatewayServiceduring startup; as of Phase T3 there are no live callers (the router was removed from the gateway), so only the test suite exercises it.
- async stop()[source]
Cancel and join the background cache-invalidation listener.
Idempotent teardown counterpart to
start(): if a listener task is running it is cancelled and awaited, swallowing the resultingasyncio.CancelledErrorso shutdown completes cleanly. When no task was ever started this is a no-op.This cancels the task created by
start()(which holds thesg:pubsub:configpub/sub subscription). Historically called byGatewayServiceduring shutdown; as of Phase T3 only the test suite invokes it.
- async get_route(channel=None, guild=None, platform=None)[source]
Resolve the route for a message, failing safe on any error.
Public entry point of the router: it delegates the real decision to
_fetch_route()but runs it inside the instance’sCircuitBreakerso a Redis outage during a cache refresh trips the breaker instead of stalling every message. On either an open breaker or any other exception it logs and returns the safeself._default_route("monolith"), so routing degrades rather than throws.Touches Redis only indirectly, through
_fetch_route()/_refresh_cache()readingsg:strangler:routes. Since the module is deprecated (Phase T3) it has no live callers; onlytests/core/migration/test_strangler_router.pyinvokes it.- Parameters:
- Returns:
The resolved route (typically
"microservice"or"monolith"), falling back toself._default_routeon breaker open or error.- Return type: