-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Description
Expected Behavior
I am using the ring client and Pipelined to implement MGET, since it MGET doesn't work across shards:
responses, pipeErr := iter.rdb.Pipelined(iter.ctx, func(p redis.Pipeline) error {
for _, jobKey := range iter.jobKeys {
_, _ = p.Get(iter.ctx, jobKey)
}
return nil
})
if pipeErr != nil && !errors.Is(pipeErr, redislib.Nil) {
return nil, pipeErr
}
iter.jobs = iter.jobs[:0]
for i, response := range responses {
jobString, err := response.(*redislib.StringCmd).Result()
if errors.Is(err, redislib.Nil) {
continue // skip any job not found
}
iter.jobs = append(iter.jobs, job)
}
return iter.jobs, nil
}
I have a test that creates a bunch of keys, deletes all but the first and last one, and then fetches them using the pipelined get.
Prior to the upgrade to 9.14.0, I would always correctly get the first and last item in iter.jobs
.
Current Behavior
Now, I always get the first, but sometimes not the last item.
Possible Solution
Reverting the change in 78be750 fixes the issue.
However, I don't think that is the fix. I think what's happening here is that the ring client's generalProcessPipeline
is taking the first error in the pipeline and surfacing that as the entire error (see
Line 870 in 7405cff
return cmdsFirstErr(cmds) |
Steps to Reproduce
Using a ring client with a few shards:
- Create 100 items in Redis with keys named (key0, key1, ... key99). Put all the key names in a slice.
- Delete every key except for key0 and key99.
- Using Pipelined, issue GET commands for all keys, including the ones that were deleted. Make sure key0 is the first key in the pipeline and key99 is the last.
- Check the results from the pipeline. If working properly, the error response for all keys except for key0 and key99 should be
redis.Nil
, while key0 and key.99 should benil
Note: I suspect that this problem may be non-deterministic due to sharding, as well, as I've had this test case sometimes work, but often fail.