Skip to content

Commit f16d8d4

Browse files
committed
Enable multiple prefixes when client tracking in broadcasting mode
Signed-off-by: Philipp Zagar <p_zagar@apple.com>
1 parent f748b9f commit f16d8d4

File tree

2 files changed

+77
-1
lines changed

2 files changed

+77
-1
lines changed

Sources/Valkey/Commands/ConnectionCommands.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,7 @@ extension CLIENT {
776776
"TRACKING",
777777
status,
778778
RESPWithToken("REDIRECT", clientId),
779-
RESPWithToken("PREFIX", prefixes),
779+
prefixes.map { RESPWithToken("PREFIX", $0) },
780780
RESPPureToken("BCAST", bcast),
781781
RESPPureToken("OPTIN", optin),
782782
RESPPureToken("OPTOUT", optout),

Tests/IntegrationTests/SubscriptionIntegrationTests.swift

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,82 @@ struct PubSubIntegratedTests {
313313
}
314314
}
315315

316+
@Test
317+
@available(valkeySwift 1.0, *)
318+
func testClientTrackingBroadcastSinglePrefix() async throws {
319+
let (stream, cont) = AsyncStream.makeStream(of: Void.self)
320+
var logger = Logger(label: "Valkey")
321+
logger.logLevel = .trace
322+
try await withValkeyClient(.hostname(valkeyHostname, port: 6379), logger: logger) { client in
323+
try await client.withConnection { connection in
324+
// Enable tracking with broadcast mode and a single prefix "user:"
325+
try await connection.clientTracking(status: .on, prefixes: ["user:"], bcast: true)
326+
327+
try await withThrowingTaskGroup(of: Void.self) { group in
328+
group.addTask {
329+
try await connection.subscribeKeyInvalidations { keys in
330+
cont.finish()
331+
var iterator = keys.makeAsyncIterator()
332+
let key = try await iterator.next()
333+
#expect(key == "user:123")
334+
}
335+
}
336+
337+
await stream.first { _ in true }
338+
339+
// This should trigger invalidation (matches prefix)
340+
try await connection.set("user:123", value: "data")
341+
342+
try await group.waitForAll()
343+
}
344+
}
345+
}
346+
}
347+
348+
@Test
349+
@available(valkeySwift 1.0, *)
350+
func testClientTrackingBroadcastMultiplePrefixes() async throws {
351+
let (stream, cont) = AsyncStream.makeStream(of: Void.self)
352+
var logger = Logger(label: "Valkey")
353+
logger.logLevel = .trace
354+
try await withValkeyClient(.hostname(valkeyHostname, port: 6379), logger: logger) { client in
355+
try await client.withConnection { connection in
356+
// Enable tracking with broadcast mode and two prefixes: "user:" and "order:"
357+
try await connection.clientTracking(status: .on, prefixes: ["user:", "order:"], bcast: true)
358+
359+
try await withThrowingTaskGroup(of: Void.self) { group in
360+
group.addTask {
361+
try await connection.subscribeKeyInvalidations { keys in
362+
cont.finish()
363+
var iterator = keys.makeAsyncIterator()
364+
365+
// Should receive invalidation for user:123
366+
let key1 = try await iterator.next()
367+
#expect(key1 == "user:123")
368+
369+
// Should receive invalidation for order:789
370+
let key2 = try await iterator.next()
371+
#expect(key2 == "order:789")
372+
}
373+
}
374+
375+
await stream.first { _ in true }
376+
377+
// This should trigger invalidation (matches "user:" prefix)
378+
try await connection.set("user:123", value: "user_data")
379+
380+
// This should NOT trigger invalidation
381+
try await connection.set("not-matching-prefix:123", value: "not_matching_data")
382+
383+
// This should trigger invalidation (matches "order:" prefix)
384+
try await connection.set("order:789", value: "order_data")
385+
386+
try await group.waitForAll()
387+
}
388+
}
389+
}
390+
}
391+
316392
@Test
317393
@available(valkeySwift 1.0, *)
318394
func testKeyspaceSubscription() async throws {

0 commit comments

Comments
 (0)