Repository navigation
feat(transport)!: make the Redis and Kafka brokers optional extras - #321
sebastianwessel wants to merge 1 commit into
Conversation
An application uses one broker, but every install pulled in FastStream with both its Redis and its Kafka client, and `import eggai` loaded aiokafka even for a Redis-only service. - `pip install "eggai[redis]"` or `pip install "eggai[kafka]"` installs one broker client; `pip install eggai` is the core (Agent, Channel, InMemoryTransport) with neither. - KafkaTransport and RedisTransport are imported on first use, from `eggai` and `eggai.transport` as before; without their extra they raise an ImportError naming it. A missing module of the SDK itself is not taken for a missing extra. - The Redis-independent part of `transport.lease` (option keys, option resolution, LeaseLostError, ProcessingTimeoutError) moves unchanged to `transport.lease_options`, so Agent imports without the Redis client; `transport.lease` re-exports it. - CI's wheel check installs the core, `[redis]` and `[kafka]` separately and checks that each brings only its own broker client. - The CLI's Kafka template requires `eggai[kafka]`; README and the transport docs show the extras. BREAKING CHANGE: a plain `pip install eggai` no longer installs a broker; add the extra the application uses (`eggai[redis]`, `eggai[kafka]`). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
QualOps Code Quality AnalysisStatus: Summary
🟡 Medium Issues (4)
...and 1 more medium issues 📊 Full ReportPowered by QualOps |
Description
An application uses one broker, but every
pip install eggaipulls in FastStream with both its Redis and its Kafka client, andimport eggailoads aiokafka even in a Redis-only service (eggai.transportimportedKafkaTransporteagerly). That is extra code to install, scan and patch in every image.This makes each broker an extra:
eggai[redis]installs FastStream and redis-py,eggai[kafka]installs FastStream and aiokafka, and plaineggaiis the core (Agent,Channel,InMemoryTransport) with neither.Type of Change
Related Issue
None.
Changes Made
sdk/pyproject.toml):faststream,redisandaiokafkaare optional;redis = ["faststream", "redis"],kafka = ["faststream", "aiokafka"]. aiokafka's range is the one FastStream 0.7 declares for its ownkafkaextra (>=0.9,<0.15); redis keeps the SDK's>=7.2,<9.0.eggai/__init__.py,eggai/transport/__init__.py):KafkaTransportandRedisTransportare resolved on first use, fromeggaiandeggai.transportas before (module__getattr__,TYPE_CHECKINGimports for type checkers and mkdocstrings). Without their extra they raiseImportError: KafkaTransport needs the 'kafka' extra: pip install 'eggai[kafka]'. A missing module of the SDK itself is re-raised as it is, never reported as a missing extra.transport.lease_options:Agentimportedtransport.lease, which imports redis-py at module level, so the core needed the Redis client. The Redis-independent part (LEASE_OPTION_KEYS,LeaseOptions,resolve_lease_options,LeaseLostError,ProcessingTimeoutError) moves unchanged (byte-identical) totransport/lease_options.py;transport.leasere-exports it, so existing imports and the tests that patchlease.open_clientkeep working.ci.yaml, wheel check): installs the built wheel three times (core,[redis],[kafka]) and checks that the core has no broker package and names the missing extra, that[redis]has no aiokafka, and that[kafka]has no redis-py.requirements.txtrequireseggai[kafka]>=0.8.0instead of a separatefaststream[kafka](0.8.0 still bundles Kafka, later versions use the extra).redis-transport.mdandkafka-transport.md.[Unreleased]→ Changed, marked BREAKING, with the migration.Migration
Add the extra wherever eggai is required:
eggai[redis],eggai[kafka], oreggai[redis,kafka]for both. No code change.Testing
make test)tests/test_optional_brokers.pyruns fresh interpreters with broker packages blocked: the core runs an in-memory publish/subscribe round trip with no broker installed; each transport names its extra when its client or FastStream is missing; one broker installed is enough for its transport; a missing SDK module is not mistaken for a missing extra; both names resolve to the same classes as before and appear indir(). Againstmainthe three behaviour tests fail and the two regression guards pass. The test names and sources avoid the broker names, becauseconftest.pyskips such tests when the broker is not running.Manual Testing Steps
poetry install --all-extraswith a throwaway Redis 7: 245 passed, 12 skipped; all 12 skips are Kafka tests (Kafka is not wired into CI either).ruff check,ruff format --check,mypy: clean.poetry check --lock: lock consistent.[redis]= 11 (no aiokafka),[kafka]= 13 (no redis-py).eggai.transport.KafkaTransport,RedisTransport,LeaseLostErrorandProcessingTimeoutErrorto their classes with docstrings. The full docs build could not run locally: it needs the eggai-examples checkout.Changelog
sdk/CHANGELOG.mdunder[Unreleased]section (required for code changes)Checklist
make lintpasses)make formatapplied)Additional Notes
async-timeout,packaging).🤖 Generated with Claude Code