Skip to content

Commit 63ffb51

Browse files
Merge remote-tracking branch 'origin/statistics+transactions+rebalance' into feature/sc-2764/gsoc-support-for-transactions
2 parents 8c77ea1 + c9aef12 commit 63ffb51

17 files changed

+497
-53
lines changed

Package.swift

+12
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ let package = Package(
3939
name: "SwiftKafka",
4040
targets: ["SwiftKafka"]
4141
),
42+
.library(
43+
name: "KafkaFoundationCompat",
44+
targets: ["KafkaFoundationCompat"]
45+
),
4246
],
4347
dependencies: [
4448
.package(url: "https://github.com/apple/swift-nio.git", from: "2.55.0"),
@@ -47,6 +51,7 @@ let package = Package(
4751
// The zstd Swift package produces warnings that we cannot resolve:
4852
// https://github.com/facebook/zstd/issues/3328
4953
.package(url: "https://github.com/facebook/zstd.git", from: "1.5.0"),
54+
.package(url: "https://github.com/swift-extras/swift-extras-json.git", .upToNextMajor(from: "0.6.0")),
5055
],
5156
targets: [
5257
.target(
@@ -76,6 +81,13 @@ let package = Package(
7681
.product(name: "NIOCore", package: "swift-nio"),
7782
.product(name: "ServiceLifecycle", package: "swift-service-lifecycle"),
7883
.product(name: "Logging", package: "swift-log"),
84+
.product(name: "ExtrasJSON", package: "swift-extras-json"),
85+
]
86+
),
87+
.target(
88+
name: "KafkaFoundationCompat",
89+
dependencies: [
90+
"SwiftKafka",
7991
]
8092
),
8193
.systemLibrary(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the swift-kafka-gsoc open source project
4+
//
5+
// Copyright (c) 2023 Apple Inc. and the swift-kafka-gsoc project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of swift-kafka-gsoc project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import Foundation
16+
import SwiftKafka
17+
18+
extension Data: KafkaContiguousBytes {}

Sources/SwiftKafka/Configuration/KafkaConfiguration.swift

+14
Original file line numberDiff line numberDiff line change
@@ -206,3 +206,17 @@ public enum KafkaConfiguration {
206206
public static let v6 = IPAddressFamily(description: "v6")
207207
}
208208
}
209+
210+
extension Duration {
211+
// Internal usage only: librdkafka accepts Int32 as timeouts
212+
internal var totalMilliseconds: Int32 {
213+
return Int32(self.components.seconds * 1000 + self.components.attoseconds / 1_000_000_000_000_000)
214+
}
215+
216+
internal var totalMillisecondsOrMinusOne: Int32 {
217+
return max(self.totalMilliseconds, -1)
218+
}
219+
220+
public static var kafkaUntilEndOfTransactionTimeout: Duration = .milliseconds(-1)
221+
public static var kafkaNoWaitTransaction: Duration = .zero
222+
}

Sources/SwiftKafka/Configuration/KafkaConsumerConfiguration.swift

+13
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,18 @@ public struct KafkaConsumerConfiguration {
2323
/// Default: `.milliseconds(100)`
2424
public var pollInterval: Duration = .milliseconds(100)
2525

26+
/// Interval for librdkafka statistics reports
27+
/// 0ms - disabled
28+
/// >= 1ms - statistics provided every specified interval
29+
public var statisticsInterval: Duration = .zero {
30+
didSet {
31+
precondition(
32+
self.statisticsInterval.totalMilliseconds > 0 || self.statisticsInterval == .zero /*self.statisticsInterval.canBeRepresentedAsMilliseconds*/,
33+
"Lowest granularity is milliseconds"
34+
)
35+
}
36+
}
37+
2638
/// The strategy used for consuming messages.
2739
/// See ``KafkaConfiguration/ConsumptionStrategy`` for more information.
2840
public var consumptionStrategy: KafkaConfiguration.ConsumptionStrategy
@@ -128,6 +140,7 @@ extension KafkaConsumerConfiguration {
128140
resultDict["group.id"] = groupID
129141
}
130142

143+
resultDict["statistics.interval.ms"] = String(self.statisticsInterval.totalMilliseconds)
131144
resultDict["session.timeout.ms"] = String(session.timeoutMilliseconds)
132145
resultDict["heartbeat.interval.ms"] = String(heartbeatIntervalMilliseconds)
133146
resultDict["max.poll.interval.ms"] = String(maxPollInvervalMilliseconds)

Sources/SwiftKafka/Configuration/KafkaProducerConfiguration.swift

+12
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@ public struct KafkaProducerConfiguration {
2020
/// Default: `.milliseconds(100)`
2121
public var pollInterval: Duration = .milliseconds(100)
2222

23+
/// Interval for librdkafka statistics reports
24+
/// 0ms - disabled
25+
/// >= 1ms - statistics provided every specified interval
26+
public var statisticsInterval: Duration = .zero {
27+
didSet {
28+
precondition(
29+
self.statisticsInterval.totalMilliseconds > 0 || self.statisticsInterval == .zero /*self.statisticsInterval.canBeRepresentedAsMilliseconds*/,
30+
"Lowest granularity is milliseconds"
31+
)
32+
}
33+
}
34+
2335
/// Maximum timeout for flushing outstanding produce requests when the ``KakfaProducer`` is shutting down.
2436
/// Default: `10000`
2537
public var flushTimeoutMilliseconds: Int = 10000 {

Sources/SwiftKafka/Configuration/KafkaProducerSharedProperties.swift

+6
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ internal protocol KafkaProducerSharedProperties: Sendable, Hashable {
2323
/// Maximum timeout for flushing outstanding produce requests when the ``KakfaProducer`` is shutting down.
2424
/// Default: `10000`
2525
var flushTimeoutMilliseconds: Int { get }
26+
27+
/// Interval for librdkafka statistics reports
28+
/// 0ms - disabled
29+
/// >= 1ms - statistics provided every specified interval
30+
var statisticsInterval: Duration { get }
2631

2732
// MARK: - Producer-specific Config Properties
2833

@@ -98,6 +103,7 @@ extension KafkaProducerSharedProperties {
98103
internal var sharedPropsDictionary: [String: String] {
99104
var resultDict: [String: String] = [:]
100105

106+
resultDict["statistics.interval.ms"] = String(self.statisticsInterval.totalMilliseconds)
101107
resultDict["enable.idempotence"] = String(self.enableIdempotence)
102108
resultDict["queue.buffering.max.messages"] = String(self.queue.bufferingMaxMessages)
103109
resultDict["queue.buffering.max.kbytes"] = String(self.queue.bufferingMaxKBytes)

Sources/SwiftKafka/Configuration/KafkaTransactionalProducerConfiguration.swift

+12
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,18 @@ public struct KafkaTransactionalProducerConfiguration {
3333
}
3434
}
3535

36+
/// Interval for librdkafka statistics reports
37+
/// 0ms - disabled
38+
/// >= 1ms - statistics provided every specified interval
39+
public var statisticsInterval: Duration = .zero {
40+
didSet {
41+
precondition(
42+
self.statisticsInterval.totalMilliseconds > 0 || self.statisticsInterval == .zero /*self.statisticsInterval.canBeRepresentedAsMilliseconds*/,
43+
"Lowest granularity is milliseconds"
44+
)
45+
}
46+
}
47+
3648
// MARK: - Producer-specific Config Properties
3749

3850
/// When set to true, the producer will ensure that messages are successfully produced exactly once and in the original produce order. The following configuration properties are adjusted automatically (if not modified by the user) when idempotence is enabled: max.in.flight.requests.per.connection=5 (must be less than or equal to 5), retries=INT32_MAX (must be greater than 0), acks=all, queuing.strategy=fifo. Producer instantation will fail if user-supplied configuration is incompatible.

Sources/SwiftKafka/Data/String+KafkaContiguousBytes.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ extension String: KafkaContiguousBytes {
1818
public func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R {
1919
if let read = try self.utf8.withContiguousStorageIfAvailable({ unsafePointer in
2020
// Fast Path
21-
let unsafeRawBufferPointer = UnsafeRawBufferPointer(start: unsafePointer.baseAddress, count: self.count)
21+
let unsafeRawBufferPointer = UnsafeRawBufferPointer(start: unsafePointer.baseAddress, count: self.utf8.count)
2222
return try body(unsafeRawBufferPointer)
2323
}) {
2424
return read

0 commit comments

Comments
 (0)