package kmsvc import ( "context" "time" kafkamgmtv1 "forgejo.riotpiao.homelab.com/homelab/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 }