Design
Where ruststream-rdkafka sits: between the RustStream runtime and the rust-rdkafka client, one
consumer per subscription, one shared producer.
The diagram as text
- Your service: #[subscriber] handlers; RustStream::new(..) .with_broker(..)
- RustStream core: Runtime: dispatch, lanes, settlement
- ruststream-rdkafka: KafkaSubscriber yields KafkaMessage; KafkaPublisher and transactional publishers; Commit tracker; EosPipeline; KafkaBroker configuration; KafkaTopic, KafkaTopics, KafkaPartitions
- rust-rdkafka and librdkafka: StreamConsumer one per subscription; FutureProducer one per connection
- #[subscriber] handlers → Runtime: dispatch, lanes, settlement: mounted
- Runtime: dispatch, lanes, settlement → KafkaSubscriber yields KafkaMessage: polls the stream
- KafkaSubscriber yields KafkaMessage → StreamConsumer one per subscription
- KafkaPublisher and transactional publishers → FutureProducer one per connection
- StreamConsumer one per subscription → Kafka cluster
- FutureProducer one per connection → Kafka cluster
The crate implements the core's broker traits over rust-rdkafka, which wraps librdkafka. The runtime above it is the same for every broker. Everything Kafka-specific is in this crate: the descriptors, what an ack means, where a retry copy goes and how a transaction commits.
Each subscription opens a librdkafka consumer of its own, so a subscription is one member of its
consumer group. The publishers of a connection share one producer, which the first publish opens. A
transactional publisher opens a producer of its own, under its transactional.id.
A setting this crate does not type is a librdkafka property. The
config passthroughs reach every one of them, and a
property left unset keeps the librdkafka default.
The commit tracker turns acknowledgements into stored offsets. The
EosPipeline commits consumed offsets inside a producer
transaction. How the pieces start and stop is on Lifecycle, and the way of one
record on Path.