-
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.