Skip to content

If the first command in a pipeline fails with an non-nil error, all the results are replaced with that error #3534

@sgp

Description

@sgp

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

return cmdsFirstErr(cmds)
).

Steps to Reproduce

Using a ring client with a few shards:

  1. Create 100 items in Redis with keys named (key0, key1, ... key99). Put all the key names in a slice.
  2. Delete every key except for key0 and key99.
  3. 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.
  4. 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 be nil

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions