popTask calls f on the most recent task in the queue, for which timestamp is in range [0, time.Now()] or blocks until such is available or context is done. group is the consumer group name. consumer is the consumer group ID. ReadyTaskKey(k) is the keys to pop from. Pipeline is executed even if f ret
( ctx context.Context, r redis.Cmdable, group, consumer string, f func(p redis.Pipeliner, payload string, startAt time.Time) error, k string, blockLimit time.Duration, )
| 554 | // Pipeline is executed even if f returns an error. |
| 555 | // Tasks are acked only if f returns without error. |
| 556 | func popTask( |
| 557 | ctx context.Context, |
| 558 | r redis.Cmdable, |
| 559 | group, consumer string, |
| 560 | f func(p redis.Pipeliner, payload string, startAt time.Time) error, |
| 561 | k string, |
| 562 | blockLimit time.Duration, |
| 563 | ) (err error) { |
| 564 | readyStream := ReadyTaskKey(k) |
| 565 | |
| 566 | processMessage := func(message redis.XMessage) error { |
| 567 | fields := make(map[string]string, len(message.Values)) |
| 568 | for k, v := range message.Values { |
| 569 | val, ok := v.(string) |
| 570 | if !ok { |
| 571 | panic(fmt.Sprintf("invalid field type %T", v)) |
| 572 | } |
| 573 | fields[k] = val |
| 574 | } |
| 575 | |
| 576 | var startAt time.Time |
| 577 | if s, ok := fields[startAtKey]; ok { |
| 578 | startAt, err = parseTime(s) |
| 579 | if err != nil { |
| 580 | return errInvalidKeyValueType.WithAttributes("key", startAtKey).WithCause(err) |
| 581 | } |
| 582 | } |
| 583 | |
| 584 | p := r.Pipeline() |
| 585 | defer func() { |
| 586 | // Ensure pipeline is executed even if f fails. |
| 587 | _, pErr := p.Exec(ctx) |
| 588 | if err == nil && pErr != nil { |
| 589 | err = ConvertError(pErr) |
| 590 | } |
| 591 | }() |
| 592 | |
| 593 | if err = f(p, fields[payloadKey], startAt); err != nil { |
| 594 | return err |
| 595 | } |
| 596 | |
| 597 | p.XAck(ctx, readyStream, group, message.ID) |
| 598 | p.XDel(ctx, readyStream, message.ID) |
| 599 | |
| 600 | return nil |
| 601 | } |
| 602 | |
| 603 | var xs []redis.XStream |
| 604 | for len(xs) == 0 { |
| 605 | xs, err = r.XReadGroup(ctx, &redis.XReadGroupArgs{ |
| 606 | Group: group, |
| 607 | Consumer: consumer, |
| 608 | Streams: []string{readyStream, ">"}, |
| 609 | Count: 1, |
| 610 | Block: blockLimit, |
| 611 | }).Result() |
| 612 | if err != nil && !errors.Is(err, redis.Nil) { |
| 613 | return ConvertError(err) |
no test coverage detected