Files
thamanyah/cms/internal/services/sqs.go
T

81 lines
2.5 KiB
Go

package services
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go-v2/service/sqs"
)
var SQSClient SQS
// QueueMessage is one message taken off the queue. ReceiptHandle is what
// identifies it for deletion — it belongs to this delivery, not to the
// message, so it cannot be held across receives.
type QueueMessage struct {
Body string
ReceiptHandle string
}
type SQS interface {
ReceiveMessages(ctx context.Context) ([]QueueMessage, error)
DeleteMessage(ctx context.Context, receiptHandle string) error
}
type SQSConcrete struct {
SQSClient *sqs.Client
QueueURL string
}
// receiveWaitSeconds turns every receive into a long poll: the call parks on
// the server until a message arrives or this elapses, so an event is picked up
// within milliseconds of being published while an idle consumer costs one
// request every twenty seconds rather than spinning. 20 is the AWS maximum.
const receiveWaitSeconds = 20
func (svc SQSConcrete) ReceiveMessages(ctx context.Context) ([]QueueMessage, error) {
output, err := svc.SQSClient.ReceiveMessage(ctx, &sqs.ReceiveMessageInput{
QueueUrl: &svc.QueueURL,
MaxNumberOfMessages: 10,
WaitTimeSeconds: receiveWaitSeconds,
})
if err != nil {
return nil, err
}
messages := make([]QueueMessage, 0, len(output.Messages))
for _, message := range output.Messages {
if message.Body == nil || message.ReceiptHandle == nil {
continue
}
messages = append(messages, QueueMessage{
Body: *message.Body,
ReceiptHandle: *message.ReceiptHandle,
})
}
return messages, nil
}
// DeleteMessage acknowledges a message. Until this is called the message is
// merely invisible, and it returns to the queue when its visibility timeout
// expires — which is how a handler that failed gets another attempt.
func (svc SQSConcrete) DeleteMessage(ctx context.Context, receiptHandle string) error {
_, err := svc.SQSClient.DeleteMessage(ctx, &sqs.DeleteMessageInput{
QueueUrl: &svc.QueueURL,
ReceiptHandle: &receiptHandle,
})
return err
}
// AssertSuccessfulConnection verifies the queue is reachable and readable with
// the configured credentials. It panics on failure, since a service whose
// consumer cannot start would silently leave every video stuck "processing".
func (svc SQSConcrete) AssertSuccessfulConnection(ctx context.Context) {
if _, err := svc.SQSClient.GetQueueAttributes(ctx, &sqs.GetQueueAttributesInput{
QueueUrl: &svc.QueueURL,
}); err != nil {
panic(fmt.Errorf("sqs: cannot connect to queue %q: %w", svc.QueueURL, err))
}
}