-
Notifications
You must be signed in to change notification settings - Fork 37
Expand DocC: config-type reference, rebalances/events, error handling, observability #248
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 10 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
2b3e5b0
Document configuration types via DocC extension files
ssikka100 2fe3d7e
Document consumer rebalances and the events sequence
ssikka100 a35ea3b
Add error-handling, observability, and migration articles
ssikka100 4a768b8
Merge branch 'main' into docc-current-client
ssikka100 43ac7fa
Address review: prose abstracts, active voice, remove Migrating
ssikka100 bfdd4e8
Cross-link DocC articles and add symbol pages for consumer/producer
ssikka100 8817026
Drop librdkafka from config-type overviews
ssikka100 281386b
Remove sibling-article Topics groups to break DocC curation cycles
ssikka100 0a0bc4e
Merge branch 'main' into docc-current-client
ssikka100 c4e00aa
Address review feedback: prose abstracts, imperative headings, error-…
ssikka100 f4b2a3f
Make RDKafkaCode curation page headings parallel
ssikka100 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| # Handling errors | ||
|
|
||
| Find where Kafka errors surface and classify them to decide whether to retry, recreate the client, or fail. | ||
|
|
||
| ## Overview | ||
|
|
||
| Both the producer and the consumer report failures as ``KafkaError`` values. A ``KafkaError`` carries a ``KafkaError/code`` describing the kind of failure and, when the error originates from librdkafka, a ``KafkaError/rdKafkaCode`` with the specific underlying code. The ``KafkaError/isFatal`` and ``KafkaError/isRetriable`` flags tell you how to respond. | ||
|
|
||
| ## Find where errors surface | ||
|
|
||
| A ``KafkaError`` reaches your code in three ways: | ||
|
|
||
| - **Thrown** from throwing calls such as ``KafkaProducer/send(_:)``, ``KafkaProducer/sendAndAwait(_:)``, ``KafkaConsumer/subscribe(topics:)``, and ``KafkaConsumer/commit(_:)``. | ||
| - **On an event sequence**, as ``KafkaConsumerEvent/error(_:)`` or ``KafkaProducerEvent/error(_:)`` — for example, a broker disconnection or an authentication failure. | ||
| - **In a delivery report**, when a ``KafkaDeliveryReport``'s status is `failure` because a message could not be delivered. | ||
|
|
||
| ## Classify an error | ||
|
|
||
| Use ``KafkaError/isFatal`` and ``KafkaError/isRetriable`` to decide how to respond, and inspect ``KafkaError/rdKafkaCode`` for finer-grained handling: | ||
|
|
||
| ```swift | ||
| func handle(_ error: KafkaError, logger: Logger) { | ||
| // A fatal error means the client instance can no longer be used: | ||
| // shut it down and create a new one. | ||
| if error.isFatal { | ||
| logger.critical("Fatal Kafka error, recreate the client", metadata: ["error": "\(error)"]) | ||
| return | ||
| } | ||
|
|
||
| // A retriable error may succeed if the operation is attempted again. | ||
| if error.isRetriable { | ||
| logger.warning("Retriable Kafka error, retrying", metadata: ["error": "\(error)"]) | ||
| return | ||
| } | ||
|
|
||
| // For finer-grained handling, inspect the underlying librdkafka code. | ||
| switch error.rdKafkaCode { | ||
| case .allBrokersDown, .transport: | ||
| logger.warning("Lost connectivity to the cluster", metadata: ["error": "\(error)"]) | ||
| case .authentication, .ssl: | ||
| logger.error("Authentication or TLS failure", metadata: ["error": "\(error)"]) | ||
| default: | ||
| logger.error("Kafka error", metadata: ["kind": "\(error.code)", "error": "\(error)"]) | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ``KafkaError/rdKafkaCode`` is `nil` for errors that don't originate from librdkafka — such as configuration or lifecycle errors — in which case ``KafkaError/isFatal`` and ``KafkaError/isRetriable`` are both `false`. | ||
|
|
||
| ## Topics | ||
|
|
||
| ### Errors | ||
|
|
||
| - ``KafkaError`` | ||
| - ``KafkaError/ErrorCode`` | ||
| - ``KafkaError/RDKafkaCode`` | ||
|
|
||
| ### Error events | ||
|
|
||
| - ``KafkaConsumerEvent`` | ||
| - ``KafkaProducerEvent`` | ||
| - ``KafkaDeliveryReport`` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| # ``Kafka/KafkaConfig`` | ||
|
|
||
| A namespace of typed option values for Kafka client configuration properties. | ||
|
|
||
| ## Overview | ||
|
|
||
| Nested types provide type-safe wrappers for enum-valued configuration options such as ``KafkaConfig/SecurityProtocol``, ``KafkaConfig/CompressionCodec``, and ``KafkaConfig/GroupProtocol``. Assign these values to properties on ``KafkaConsumerConfig`` and ``KafkaProducerConfig``. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| # ``Kafka/KafkaConsumer`` | ||
|
|
||
| An object that consumes messages from a Kafka cluster as part of a service lifecycle. | ||
|
|
||
| ## Overview | ||
|
|
||
| Create a consumer from a ``KafkaConsumerConfig``, run it inside a `ServiceGroup`, and iterate ``KafkaConsumer/messages`` to receive records. The consumer conforms to `Service`, so the surrounding application controls its lifecycle; the `run()` method drives the underlying poll loop until the calling task is canceled or a graceful shutdown is triggered. | ||
|
|
||
| By default, the consumer stores and commits offsets automatically as iteration proceeds. For at-least-once delivery, disable automatic offset storage and call ``storeOffset(_:)`` after processing each record. For full control over commit timing, disable auto-commit as well and use ``commit(_:)`` or ``commit()`` explicitly. | ||
|
|
||
| For an end-to-end guide including configuration, rebalance handling, and offset patterns, see <doc:ConsumingMessages>. | ||
|
|
||
| ## Topics | ||
|
|
||
| ### Creating a consumer | ||
|
|
||
| - ``init(config:logger:)`` | ||
| - ``makeConsumerWithEvents(config:logger:)`` | ||
|
|
||
| ### Consuming messages | ||
|
|
||
| - ``messages`` | ||
| - ``KafkaConsumerMessages`` | ||
| - ``KafkaConsumerMessage`` | ||
|
|
||
| ### Running the service | ||
|
|
||
| - ``run()`` | ||
| - ``triggerGracefulShutdown()`` | ||
|
|
||
| ### Managing subscriptions | ||
|
|
||
| - ``subscribe(topics:)`` | ||
| - ``unsubscribe()`` | ||
| - ``subscribedTopics()`` | ||
|
|
||
| ### Storing and committing offsets | ||
|
|
||
| - ``storeOffset(_:)`` | ||
| - ``commit(_:)`` | ||
| - ``commit()`` | ||
| - ``scheduleCommit(_:)`` | ||
| - ``scheduleCommit()`` | ||
|
|
||
| ### Querying position | ||
|
|
||
| - ``committed(topicPartitions:timeout:)`` | ||
| - ``position(topicPartitions:)`` | ||
| - ``isAssignmentLost`` | ||
|
|
||
| ### Pausing and resuming partitions | ||
|
|
||
| - ``pause(topicPartitions:)`` | ||
| - ``resume(topicPartitions:)`` | ||
|
|
||
| ### Seeking | ||
|
|
||
| - ``seek(topicPartitionOffsets:timeout:)`` | ||
|
|
||
| ### Observing events | ||
|
|
||
| - ``KafkaConsumerEvents`` | ||
| - ``KafkaConsumerEvent`` | ||
| - ``KafkaConsumerRebalance`` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| # ``Kafka/KafkaConsumerConfig`` | ||
|
|
||
| Configuration for a Kafka consumer. | ||
|
|
||
| ## Overview | ||
|
|
||
| Provide broker addresses through ``KafkaConsumerConfig/bootstrapServers`` and a consumption strategy through ``KafkaConsumerConfig/consumptionStrategy``, then pass the configuration to a ``KafkaConsumer`` initializer. Additional properties expose the consumer's configuration options; consult individual property documentation for defaults and semantics. | ||
|
|
||
| For security options, see <doc:SecuringConnections>. For an end-to-end example, see <doc:ConsumingMessages>. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| # ``Kafka/KafkaProducer`` | ||
|
|
||
| An object that sends messages to a Kafka cluster as part of a service lifecycle. | ||
|
|
||
| ## Overview | ||
|
|
||
| Create a producer from a ``KafkaProducerConfig``, run it inside a `ServiceGroup`, and call ``send(_:)`` or ``sendAndAwait(_:)`` to publish records. The producer conforms to `Service`, so the surrounding application controls its lifecycle; the `run()` method drives the internal poll loop, dispatches delivery reports, and flushes outstanding messages on graceful shutdown. | ||
|
|
||
| Two send styles are available. Use ``sendAndAwait(_:)`` when the caller needs the delivery outcome inline — the method suspends until the broker acknowledges (or rejects) the message and returns a ``KafkaDeliveryReport``. Use ``send(_:)`` paired with ``makeProducerWithEvents(config:logger:)`` for maximum throughput, processing delivery reports asynchronously through the events sequence. | ||
|
|
||
| When messages are published to a nonexistent topic, a new topic is created using the default topic configuration (based on ``KafkaProducerConfig`` topic-level properties). | ||
|
|
||
| For an end-to-end guide including configuration, delivery patterns, and event handling, see <doc:ProducingMessages>. | ||
|
|
||
| ## Topics | ||
|
|
||
| ### Creating a producer | ||
|
|
||
| - ``init(config:logger:)`` | ||
| - ``makeProducerWithEvents(config:logger:)`` | ||
|
|
||
| ### Sending messages | ||
|
|
||
| - ``send(_:)`` | ||
| - ``sendAndAwait(_:)`` | ||
| - ``KafkaProducerMessage`` | ||
| - ``KafkaProducerMessageID`` | ||
|
|
||
| ### Running the service | ||
|
|
||
| - ``run()`` | ||
| - ``triggerGracefulShutdown()`` | ||
|
|
||
| ### Observing outcomes | ||
|
|
||
| - ``KafkaProducerEvents`` | ||
| - ``KafkaProducerEvent`` | ||
| - ``KafkaDeliveryReport`` | ||
| - ``KafkaAcknowledgedMessage`` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| # ``Kafka/KafkaProducerConfig`` | ||
|
|
||
| Configuration for a Kafka producer. | ||
|
|
||
| ## Overview | ||
|
|
||
| Provide broker addresses through ``KafkaProducerConfig/bootstrapServers``, then pass the configuration to a ``KafkaProducer`` initializer. Additional properties expose the producer's configuration options; consult individual property documentation for defaults and semantics. | ||
|
|
||
| For security options, see <doc:SecuringConnections>. For an end-to-end example, see <doc:ProducingMessages>. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| # Observing Kafka clients | ||
|
|
||
| Emit metrics and structured logs from the producer and consumer. | ||
|
|
||
| ## Overview | ||
|
|
||
| The Kafka client integrates with [swift-metrics](https://github.com/apple/swift-metrics) for runtime metrics and [swift-log](https://github.com/apple/swift-log) for structured logging. Both are opt-in through the client configuration and the `Logger` you provide. | ||
|
|
||
| ## Emit metrics | ||
|
|
||
| The client periodically samples internal statistics and records them into [swift-metrics](https://github.com/apple/swift-metrics) gauges that you supply. Configure this through the ``KafkaConsumerConfig/metrics`` (or ``KafkaProducerConfig/metrics``) property: set an update interval and assign a `Gauge` to each statistic you want to track. | ||
|
|
||
|
ssikka100 marked this conversation as resolved.
|
||
| The following example illustrates configuring a Kafka client with metrics: | ||
|
|
||
| ```swift | ||
| import Kafka | ||
| import Metrics | ||
|
|
||
| var config = KafkaConsumerConfig() | ||
| config.bootstrapServers = ["localhost:9092"] | ||
| config.consumptionStrategy = .group(id: "example-group", topics: ["topic-name"]) | ||
|
|
||
| // Sample statistics once per second into swift-metrics gauges. | ||
| config.metrics.updateInterval = .seconds(1) | ||
| config.metrics.totalKafkaBrokerRequests = Gauge(label: "kafka_consumer_broker_requests") | ||
| config.metrics.totalKafkaBrokerMessagesReceived = Gauge(label: "kafka_consumer_messages_received") | ||
| config.metrics.queuedOperation = Gauge(label: "kafka_consumer_queued_operations") | ||
|
|
||
| let consumer = try KafkaConsumer(config: config, logger: logger) | ||
| ``` | ||
|
|
||
| The client emits metrics only when ``KafkaConfiguration/ConsumerMetrics/updateInterval`` is set **and** at least one gauge is assigned; otherwise the client skips statistics collection entirely. The producer exposes the same pattern through ``KafkaProducerConfig/metrics`` with producer-specific gauges such as ``KafkaConfiguration/ProducerMetrics/queuedProducerMessages`` and ``KafkaConfiguration/ProducerMetrics/totalKafkaBrokerMessagesSent``. | ||
|
|
||
| The gauges you assign are ordinary [swift-metrics](https://github.com/apple/swift-metrics) types, so the values reach whatever metrics backend you bootstrap through `MetricsSystem`. | ||
|
|
||
| ## Emit structured logs | ||
|
|
||
| Pass a `Logger` when creating a ``KafkaProducer`` or ``KafkaConsumer``. The client logs lifecycle and operational events through it, and enriches every entry with structured metadata so you can filter and correlate logs across many clients: | ||
|
|
||
| | Metadata key | Value | | ||
| | --- | --- | | ||
| | `kafka.client.id` | the configured `clientId` | | ||
| | `kafka.client.type` | `producer` or `consumer` | | ||
| | `kafka.group.id` | the consumer group (consumers only) | | ||
|
|
||
| ```swift | ||
| import Kafka | ||
| import Logging | ||
|
|
||
| let logger = Logger(label: "kafka") | ||
|
|
||
| var config = KafkaConsumerConfig() | ||
| config.clientId = "orders-consumer" | ||
| config.consumptionStrategy = .group(id: "orders", topics: ["orders"]) | ||
|
|
||
| let consumer = try KafkaConsumer(config: config, logger: logger) | ||
| // Every log entry from this consumer now carries kafka.client.id, kafka.client.type, | ||
| // and kafka.group.id. | ||
| ``` | ||
|
|
||
| Set the `Logger`'s log level to control verbosity — the client logs routine progress at `debug` and `trace`, and surfaces problems at `info` and above. | ||
|
|
||
| ## Topics | ||
|
|
||
| ### Metrics | ||
|
|
||
| - ``KafkaConfiguration/ConsumerMetrics`` | ||
| - ``KafkaConfiguration/ProducerMetrics`` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| # ``Kafka/KafkaError/RDKafkaCode`` | ||
|
|
||
| An error code reported by the underlying C library that backs the client. | ||
|
|
||
| ## Overview | ||
|
|
||
| When a ``KafkaError`` originates from the underlying C library, its ``KafkaError/rdKafkaCode`` carries one of these codes. Match against the static constants to handle specific failures without importing the C module — for example, telling a connectivity problem (``allBrokersDown``, ``transport``) apart from an authentication problem (``authentication``, ``ssl``). | ||
|
|
||
| Each code's ``description`` includes the underlying name and numeric value, which is useful to surface in logs. | ||
|
|
||
| ## Topics | ||
|
|
||
| ### Connectivity | ||
|
|
||
| - ``allBrokersDown`` | ||
| - ``transport`` | ||
| - ``timedOut`` | ||
|
|
||
| ### Authentication and security | ||
|
|
||
| - ``authentication`` | ||
| - ``ssl`` | ||
|
|
||
| ### Producing and consuming | ||
|
|
||
| - ``messageTimedOut`` | ||
| - ``queueFull`` | ||
| - ``maxPollExceeded`` | ||
|
|
||
| ### Topics and partitions | ||
|
|
||
| - ``unknownTopic`` | ||
| - ``unknownPartition`` | ||
|
|
||
| ### Other | ||
|
|
||
| - ``fatal`` | ||
| - ``invalidArgument`` | ||
| - ``noError`` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.