Repository navigation
DOC-7226 Move prefetch-cache, time-series-dashboard, pub-sub and streaming Jedis use cases to RedisClient - #4389
Conversation
Prefetch cache, time-series dashboard, pub/sub and streaming (java-jedis) take a RedisClient instead of a JedisPool. As in the first batch, getResource() blocks are gone, pipelines and MULTI transactions are in try-with-resources, demo servers build the client with RedisClient.create or RedisClient.builder() plus a ConnectionPoolConfig where they size the pool, and each page's Maven/Gradle version, prose and javac/java commands move to Jedis 8.0.2 with the six runtime jars. The three directories that used APIs RedisClient lacks needed more than a rename: - time-series-dashboard reached for jedis.getConnection() and wrote raw commands to it. It now goes through jedis.executeCommand(new CommandArguments(cmd).addObjects(args)). UnifiedJedis.sendCommand(ProtocolCommand, String...) is the obvious swap, but Jedis 8 deprecates it, which would trade one deprecated call for another. - pub-sub used Jedis.pubsubChannels/pubsubNumSub/pubsubNumPat, which exist only on the legacy Jedis class. They are now executeCommand(new CommandObject<>( new CommandArguments(Protocol.Command.PUBSUB).add(Protocol.Keyword.X), BuilderFactory.Y)). Each Subscription no longer owns a Jedis; its worker thread calls jedis.subscribe(listener, ...) on the shared client, which borrows and holds a pooled connection until unsubscribe. The "close the Jedis to force subscribe() to return" fallback is removed because closing the shared client would be wrong. - streaming's XAUTOCLAIM raw-reply path moves from sendCommand to executeCommand, and StreamEntryID.UNRECEIVED_ENTRY (deprecated) becomes XREADGROUP_UNDELIVERED_ENTRY. The page's claim that the typed xautoclaim drops the deleted-ids slot still holds in 8.0.2 (checked with javap), so the hand parsing stays. Verification, compiled with -Xlint:deprecation (0 warnings) against Jedis 8.0.2 and run on redis:8.10. Prefetch: bulk load, sync-worker transaction, add, delete, 200 concurrent mixed calls. Time series: snapshot parsing matches the original on Jedis 5.2.0 (types and min<=avg<=max), 200 concurrent snapshots. Pub/sub: exact and pattern delivery counts exact (203 = 3 + 200), PUBSUB introspection correct, 150 subscribe/unsubscribe cycles against a pool of 64 (a leak would hang by ~60). Streaming: the same scenario on the original (5.2.0) and migrated builds gives identical output for produce, consume, crash, pending=3, XAUTOCLAIM claimed=3, add/remove worker, trim and replay; only the final concurrent-load tail differs, which is timing. Every page's javac/java commands were extracted and run literally in a clean directory with only the six jars; all four compile and serve. Constraint: RedisClient has no pubsubChannels/NumSub/NumPat, getConnection(), or non-deprecated sendCommand; use executeCommand(CommandArguments) or executeCommand(CommandObject) Constraint: a subscribe()/psubscribe() on a RedisClient holds one pooled connection for the subscription's life, so maxTotal must cover subscribers plus command traffic Learned: JedisPubSub needs redis.clients.authentication.core.Token (redis-authx-core) at class-load time, so a three-jar classpath serves every other demo and fails only pub/sub Learned: an unrelated JVM left deadlocked from an earlier probe held 8 pooled connections and inflated every later "clients: N" count; check pgrep before reading connection counts Learned: the streaming "crash" button drops the next N deliveries, so a scenario must crash before producing or nothing is ever pending Ticket: DOC-7226 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
🧠 Redis MemoryFound 6 related items from repository history (1 new this commit):
Memory updated at 3ef1c87 |
…BE never completes Cursor Bugbot found that Subscription.close() could no longer force a stuck subscribe() to return. The earlier change in this PR called jedis.subscribe(listener, ...) on the shared RedisClient, which borrows its connection internally, so close() had no handle on it. On a half-open socket UNSUBSCRIBE never completes and the pooled connection stays checked out for the life of the process. Each Subscription now borrows its own Connection with jedis.getPool().getResource() and runs listener.proceed(connection, ...) or proceedWithPatterns(...) on it, which is what UnifiedJedis.subscribe does internally. The worker thread returns the connection in a finally block, and close() restores the last resort the pre-migration code had: if the thread has not exited a second after UNSUBSCRIBE, it disconnects the connection so the blocked read fails. Reproduced first, then fixed. A TCP proxy between the demo and Redis was frozen to make a half-open link: before, close() returned after about 1 s and the pool still showed 1 active connection; after, close() takes about 1.5 s and the pool shows 0. The normal path is unchanged: delivery counts exact (203 = 3 + 200), PUBSUB introspection correct, 150 subscribe/unsubscribe cycles against a pool of 64, no deprecation warnings, nested-borrow check clean. The page text that described subscribe() borrowing the connection now describes the borrow. Constraint: UnifiedJedis.subscribe() borrows its connection internally; a caller that needs to break a stuck subscription must borrow the Connection itself and call JedisPubSub.proceed(connection, ...) Learned: to reproduce a stuck unsubscribe, freeze a TCP proxy between the client and Redis rather than killing either end; a dead socket makes subscribe() throw and masks the bug Ticket: DOC-7226 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 3ef1c87. Configure here.
| */ | ||
| public long deleteConsumer(String group, String consumer) { | ||
| try (Jedis jedis = pool.getResource()) { | ||
| try { |
There was a problem hiding this comment.
XAUTOCLAIM parser drops RESP3 fields
High Severity
Jedis 8 negotiates RESP3 by default, so XAUTOCLAIM entry fields arrive as maps rather than flat lists. decodeFieldArray only walks a List and returns an empty map otherwise, so claimed entries lose their payload and the crash-recovery path cannot process them.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 3ef1c87. Configure here.


Moves four more
java-jedisuse cases fromJedisPooltoRedisClient(Jedis 8.0.2).RedisClientlacks (getConnection(),pubsubChannels/NumSub/NumPat, deprecatedsendCommand); they now useexecuteCommand.UNRECEIVED_ENTRYbecomesXREADGROUP_UNDELIVERED_ENTRY.subscribe()holds one pooled connection; the shared client is never closed by a subscription. Prose and the sharded pub/sub sentence updated.redis-authx-core).Verified: 0 deprecation warnings; streaming scenario output identical to the original on Jedis 5.2.0 (produce, consume, crash, XAUTOCLAIM, replay); pub/sub 150 subscribe/unsubscribe cycles against a pool of 64; page commands run in a clean directory. Not run: Hugo build.
Part of DOC-7226.
🤖 Generated with Claude Code
Note
Low Risk
Changes are limited to documentation and local demo Java sources; behavior was manually verified for pub/sub and streaming per the PR description.
Overview
Updates the prefetch-cache, pub-sub, streaming, and time-series-dashboard
java-jedisdemos and docs fromJedisPool/ Jedis 5–6 toRedisClient/ Jedis 8.0.2, including compile/run instructions that list the full runtime classpath (e.g.redis-authx-core).Prefetch-cache and most helpers now hold a shared
RedisClientinstead of borrowing aJedisper call; pipelines andmulti()use try-with-resources on the pipeline/transaction types (AbstractTransactionfor upserts).Pub-sub passes a dedicated pooled
ConnectionintoJedisPubSub.proceed()/proceedWithPatterns()(so shutdown candisconnect()if needed), and sendsPUBSUBintrospection viaexecuteCommandbecause those helpers are not onRedisClient.Streaming switches the undelivered read sentinel to
StreamEntryID.XREADGROUP_UNDELIVERED_ENTRY, drops per-call pool checkout, and usesexecuteCommandfor rawXAUTOCLAIMreplies (deleted-ID list). Time-series routes TimeSeries module commands throughjedis.executeCommand(CommandArguments)instead ofConnection.sendCommand.Prose changes cover
ConnectionPoolConfig/RedisClient.builder()tuning and updated Maven/Gradle versions.Reviewed by Cursor Bugbot for commit 3ef1c87. Bugbot is set up for automated code reviews on this repo. Configure here.