Files

65 lines
2.3 KiB
Go

package kmsvc
import (
"context"
"time"
kafkamgmtv1 "forgejo.riotpiao.com/rock/kmsvc-proto/gen/kafkamgmt/v1"
)
// MaxReceiveMessages mirrors the server-side cap (design.md §2b).
const MaxReceiveMessages = 10
// MaxWaitTimeSeconds mirrors the server-side long-poll cap (design.md §2b).
const MaxWaitTimeSeconds = 20
// ReceiveOptions configures ReceiveMessage.
type ReceiveOptions struct {
// MaxNumberOfMessages caps how many messages are returned (1-10).
MaxNumberOfMessages int32
// WaitTimeSeconds requests SQS-style long polling (0-20). The server
// blocks up to this long before returning an empty result.
WaitTimeSeconds int32
// VisibilityTimeoutSeconds overrides the queue's default visibility
// timeout for the returned messages, if non-zero.
VisibilityTimeoutSeconds int32
}
// ReceiveMessage long-polls queueName for up to opts.WaitTimeSeconds before
// returning, then returns whatever messages (zero or more) are available.
//
// At-least-once delivery: a message may be redelivered (e.g. after the
// caller's visibility timeout expires without DeleteMessage) — callers must
// be idempotent or dedup on MessageID/MessageGroupID as appropriate.
//
// ctx's deadline is extended internally by a small margin beyond
// WaitTimeSeconds so a slow network round trip doesn't truncate a poll that
// the server was about to satisfy; this margin never extends the result
// beyond what the caller's own ctx allows if ctx is already deadlined sooner.
func (c *Client) ReceiveMessage(ctx context.Context, queueName string, opts ReceiveOptions) ([]Message, error) {
callCtx := ctx
if opts.WaitTimeSeconds > 0 {
margin := 5 * time.Second
deadline := time.Now().Add(time.Duration(opts.WaitTimeSeconds)*time.Second + margin)
var cancel context.CancelFunc
callCtx, cancel = context.WithDeadline(ctx, deadline)
defer cancel()
}
resp, err := c.stub.ReceiveMessage(callCtx, &kafkamgmtv1.ReceiveMessageRequest{
QueueName: queueName,
MaxNumberOfMessages: opts.MaxNumberOfMessages,
WaitTimeSeconds: opts.WaitTimeSeconds,
VisibilityTimeoutSeconds: opts.VisibilityTimeoutSeconds,
})
if err != nil {
return nil, mapError(err)
}
out := make([]Message, 0, len(resp.Messages))
for _, m := range resp.Messages {
out = append(out, toMessage(m))
}
return out, nil
}