What to build
This is the largest of the Java-specific issues: finish the Redis operations adapter layer so that business classes (WorkerRegistry, WorkerRunner, AgentContext, GatewayClient, GatewayWorker, WorkerManager, WakeupController, AvailabilityRouter) depend only on business-level interfaces, never on Jedis/JedisCluster/Pipeline directly. A raw Pipeline-exposing interface doesn't work here — JedisCluster's pipeline capability and standalone Pipeline aren't the same abstraction (different cross-slot limits, different return types), and Phase 3 already established that cross-entity operations get split into independent business-level calls rather than generic pipelines.
Add a RedisOps interface exposing:
- single-key passthroughs (
get, set with ttl, hgetAll, sadd, expire)
- business-level batch operations named for what they do, not how (
saveSessionExecution, updateWorkerAdminState, writeTraceSpan, batchGetWorkerAdminStates, scanKeys)
isClusterMode()
Implement StandaloneRedisOps (batch ops use Pipeline+sync internally where all keys are guaranteed same-node) and ClusterRedisOps (batch ops split into independent calls per Phase 3's patterns, or use JedisCluster pipelining only where Phase 2a's hash tags guarantee same-slot).
Extend RedisStreamOps (from the Phase 4 prefactor, #12) with the remaining stream operations not yet covered: xadd taking an explicit XAddOptions type (noTrim() vs trimTo(maxLen), where trimming is always approximate — never expose a way to request exact O(N) trimming), xpendingRange (PEL range read), and xclaim returning the actual claimed StreamEntry list (not just a count — the caller needs the message contents to redispatch them, not just confirmation that claiming succeeded).
Add the cluster-aware scanKeys(pattern, limit): JedisCluster has no built-in cross-node SCAN, so this must iterate getClusterNodes() and merge results from each node's Jedis.scan(cursor, params).
Acceptance criteria
Blocked by
#11, #12
What to build
This is the largest of the Java-specific issues: finish the Redis operations adapter layer so that business classes (
WorkerRegistry,WorkerRunner,AgentContext,GatewayClient,GatewayWorker,WorkerManager,WakeupController,AvailabilityRouter) depend only on business-level interfaces, never onJedis/JedisCluster/Pipelinedirectly. A rawPipeline-exposing interface doesn't work here —JedisCluster's pipeline capability and standalonePipelinearen't the same abstraction (different cross-slot limits, different return types), and Phase 3 already established that cross-entity operations get split into independent business-level calls rather than generic pipelines.Add a
RedisOpsinterface exposing:get,setwith ttl,hgetAll,sadd,expire)saveSessionExecution,updateWorkerAdminState,writeTraceSpan,batchGetWorkerAdminStates,scanKeys)isClusterMode()Implement
StandaloneRedisOps(batch ops usePipeline+sync internally where all keys are guaranteed same-node) andClusterRedisOps(batch ops split into independent calls per Phase 3's patterns, or useJedisClusterpipelining only where Phase 2a's hash tags guarantee same-slot).Extend
RedisStreamOps(from the Phase 4 prefactor, #12) with the remaining stream operations not yet covered:xaddtaking an explicitXAddOptionstype (noTrim()vstrimTo(maxLen), where trimming is always approximate — never expose a way to request exact O(N) trimming),xpendingRange(PEL range read), andxclaimreturning the actual claimedStreamEntrylist (not just a count — the caller needs the message contents to redispatch them, not just confirmation that claiming succeeded).Add the cluster-aware
scanKeys(pattern, limit):JedisClusterhas no built-in cross-node SCAN, so this must iterategetClusterNodes()and merge results from each node'sJedis.scan(cursor, params).Acceptance criteria
RedisOpsinterface finalized with the methods above;StandaloneRedisOps/ClusterRedisOpsimplementedRedisStreamOpsextended withxadd(streamName, fields, XAddOptions),xpendingRange(streamName, groupName, count),xclaim(...)returning claimed entriesXAddOptions.trimTo(maxLen)always uses approximate trimming;noTrim()ignores the approximate flag entirely (no~emitted)scanKeysimplemented via cluster-node iteration + merge forClusterRedisOps; single-node passthrough forStandaloneRedisOpsRedisOps/RedisStreamOps, with no remaining directJedis/JedisCluster/PipelineimportsStandaloneRedisOps/ClusterRedisOps(andStandaloneRedisStreamOps/ClusterRedisStreamOps) asserting identical business semanticsBlocked by
#11, #12