|
@@ -1,4 +1,4 @@
|
|
-package main
|
|
|
|
|
|
+package services
|
|
|
|
|
|
import (
|
|
import (
|
|
"context"
|
|
"context"
|
|
@@ -11,41 +11,39 @@ import (
|
|
"strconv"
|
|
"strconv"
|
|
"time"
|
|
"time"
|
|
|
|
|
|
- "github.com/aws/aws-sdk-go-v2/aws"
|
|
|
|
"github.com/aws/aws-sdk-go-v2/service/sqs"
|
|
"github.com/aws/aws-sdk-go-v2/service/sqs"
|
|
"github.com/aws/aws-sdk-go-v2/service/sqs/types"
|
|
"github.com/aws/aws-sdk-go-v2/service/sqs/types"
|
|
"github.com/davecgh/go-spew/spew"
|
|
"github.com/davecgh/go-spew/spew"
|
|
|
|
+ "github.com/fgm/izidic"
|
|
"github.com/google/uuid"
|
|
"github.com/google/uuid"
|
|
- "gopkg.in/yaml.v2"
|
|
|
|
)
|
|
)
|
|
|
|
|
|
-func lister(ctx context.Context, w io.Writer, client *sqs.Client) string {
|
|
|
|
- lqo, err := client.ListQueues(ctx, &sqs.ListQueuesInput{
|
|
|
|
- MaxResults: aws.Int32(10),
|
|
|
|
- NextToken: nil,
|
|
|
|
- QueueNamePrefix: aws.String(""),
|
|
|
|
- })
|
|
|
|
- if err != nil {
|
|
|
|
- log.Fatalf("failed listing queues: %v", err)
|
|
|
|
- }
|
|
|
|
- y := yaml.NewEncoder(w)
|
|
|
|
- y.Encode(lqo.QueueUrls)
|
|
|
|
- return lqo.QueueUrls[0]
|
|
|
|
|
|
+type Event struct {
|
|
|
|
+ MessageID uuid.UUID `json:"MessageId"`
|
|
|
|
+ BodySum string `json:"MD5OfBody"`
|
|
|
|
+ AttrSum string `json:"MD5MofMessageAttributes"`
|
|
|
|
+
|
|
|
|
+ EventAttributes
|
|
|
|
+ MessageAttributes map[string]types.MessageAttributeValue
|
|
|
|
+ Body []byte
|
|
}
|
|
}
|
|
|
|
|
|
-func receiver(ctx context.Context, w io.Writer, client *sqs.Client, qURL string) {
|
|
|
|
- rmi := sqs.ReceiveMessageInput{
|
|
|
|
- QueueUrl: &qURL,
|
|
|
|
- AttributeNames: []types.QueueAttributeName{"All"},
|
|
|
|
- MessageAttributeNames: []string{"All"},
|
|
|
|
- VisibilityTimeout: 0,
|
|
|
|
- WaitTimeSeconds: 0,
|
|
|
|
|
|
+func (e Event) IsRetryable() bool {
|
|
|
|
+ maybeRetry, ok := e.MessageAttributes["retry"]
|
|
|
|
+ if !ok {
|
|
|
|
+ return false
|
|
}
|
|
}
|
|
- msg, err := client.ReceiveMessage(ctx, &rmi)
|
|
|
|
- if err != nil {
|
|
|
|
- log.Fatalf("failed receiving from queue %s: %v", err)
|
|
|
|
|
|
+ if maybeRetry.DataType == nil || *maybeRetry.DataType != "String" || maybeRetry.StringValue == nil {
|
|
|
|
+ return false
|
|
}
|
|
}
|
|
- spew.Fdump(w, msg.Messages)
|
|
|
|
|
|
+ return *maybeRetry.StringValue == "1"
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+type EventAttributes struct {
|
|
|
|
+ SenderID string `json:"SenderId"`
|
|
|
|
+ SentTime time.Time `json:"SentTimestamp"`
|
|
|
|
+ ApproximateReceiveCount int `json:"ApproximateReceiveCount"`
|
|
|
|
+ ApproximateFirstReceiveTimestamp time.Time `json:"ApproximateFirstReceiveTimestamp"`
|
|
}
|
|
}
|
|
|
|
|
|
type Handler func(ctx context.Context, enc *json.Encoder, msgID uuid.UUID, sent time.Time, input []byte, meta map[string]types.MessageAttributeValue) error
|
|
type Handler func(ctx context.Context, enc *json.Encoder, msgID uuid.UUID, sent time.Time, input []byte, meta map[string]types.MessageAttributeValue) error
|
|
@@ -59,7 +57,25 @@ func (m message) String() string {
|
|
return *m.MessageId
|
|
return *m.MessageId
|
|
}
|
|
}
|
|
|
|
|
|
-func consumer(ctx context.Context, w io.Writer, enc *json.Encoder, client *sqs.Client, qURL string, hdl Handler) error {
|
|
|
|
|
|
+func ConsumerService(dic *izidic.Container) (any, error) {
|
|
|
|
+ cli := dic.MustService("sqs").(*sqs.Client)
|
|
|
|
+ w := dic.MustParam(PWriter).(io.Writer)
|
|
|
|
+ hdl := dic.MustParam(PHandler).(Handler)
|
|
|
|
+ enc := json.NewEncoder(w)
|
|
|
|
+ return func(ctx context.Context, qURL string) error {
|
|
|
|
+ return consumeMessage(ctx, w, enc, cli, qURL, hdl)
|
|
|
|
+ }, nil
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func ReceiverService(dic *izidic.Container) (any, error) {
|
|
|
|
+ cli := dic.MustService("sqs").(*sqs.Client)
|
|
|
|
+ w := dic.MustParam(PWriter).(io.Writer)
|
|
|
|
+ return func(ctx context.Context, qURL string) {
|
|
|
|
+ receiveMessage(ctx, w, cli, qURL)
|
|
|
|
+ }, nil
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func consumeMessage(ctx context.Context, _ io.Writer, enc *json.Encoder, client *sqs.Client, qURL string, hdl Handler) error {
|
|
rmi := sqs.ReceiveMessageInput{
|
|
rmi := sqs.ReceiveMessageInput{
|
|
QueueUrl: &qURL,
|
|
QueueUrl: &qURL,
|
|
AttributeNames: []types.QueueAttributeName{"All"},
|
|
AttributeNames: []types.QueueAttributeName{"All"},
|
|
@@ -75,7 +91,7 @@ func consumer(ctx context.Context, w io.Writer, enc *json.Encoder, client *sqs.C
|
|
return fmt.Errorf("failed receiving from queue: %w, aborting", err)
|
|
return fmt.Errorf("failed receiving from queue: %w, aborting", err)
|
|
}
|
|
}
|
|
if len(recv.Messages) == 0 {
|
|
if len(recv.Messages) == 0 {
|
|
- fmt.Fprintf(w, "No message with %d seconds timeout\n", rmi.WaitTimeSeconds)
|
|
|
|
|
|
+ log.Printf("No message with %d seconds timeout\n", rmi.WaitTimeSeconds)
|
|
continue
|
|
continue
|
|
}
|
|
}
|
|
if len(recv.Messages) != 1 {
|
|
if len(recv.Messages) != 1 {
|
|
@@ -84,41 +100,44 @@ func consumer(ctx context.Context, w io.Writer, enc *json.Encoder, client *sqs.C
|
|
msg := message(recv.Messages[0])
|
|
msg := message(recv.Messages[0])
|
|
evt, err := validateMessage(msg)
|
|
evt, err := validateMessage(msg)
|
|
if err != nil {
|
|
if err != nil {
|
|
- fmt.Fprintf(w, "invalid message %s: %w, dropping it anyway", msg, err)
|
|
|
|
|
|
+ log.Printf("invalid message %s: %v, dropping it anyway", msg, err)
|
|
} else {
|
|
} else {
|
|
if err := hdl(ctx, enc, evt.MessageID, evt.SentTime, evt.Body, evt.MessageAttributes); err != nil {
|
|
if err := hdl(ctx, enc, evt.MessageID, evt.SentTime, evt.Body, evt.MessageAttributes); err != nil {
|
|
- fmt.Fprintf(w, "Error processing message: %s: %v, dropping it anyway\n", msg, err)
|
|
|
|
|
|
+ log.Printf("message %s failed processing : %v, dropping it anyway\n", msg, err)
|
|
} else {
|
|
} else {
|
|
- fmt.Fprintf(w, "Message %s processed successfully\n", msg)
|
|
|
|
|
|
+ log.Printf("message %s processed successfully\n", msg)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- dmi := sqs.DeleteMessageInput{
|
|
|
|
- QueueUrl: &qURL,
|
|
|
|
- ReceiptHandle: msg.ReceiptHandle,
|
|
|
|
- }
|
|
|
|
- _, err = client.DeleteMessage(ctx, &dmi)
|
|
|
|
- if err != nil {
|
|
|
|
- fmt.Fprintf(w, "Error deleting message %s after successful processing: %v\n", msg, err)
|
|
|
|
- continue
|
|
|
|
|
|
+ if evt.IsRetryable() {
|
|
|
|
+ log.Printf("message %s not deleted, for retry", msg)
|
|
|
|
+ } else {
|
|
|
|
+ dmi := sqs.DeleteMessageInput{
|
|
|
|
+ QueueUrl: &qURL,
|
|
|
|
+ ReceiptHandle: msg.ReceiptHandle,
|
|
|
|
+ }
|
|
|
|
+ _, err = client.DeleteMessage(ctx, &dmi)
|
|
|
|
+ if err != nil {
|
|
|
|
+ log.Printf("Error deleting message %s after successful processing: %v\n", msg, err)
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+ log.Printf("message %s deleted after processing\n", msg)
|
|
}
|
|
}
|
|
- fmt.Fprintf(w, "Deleted processed message %s\n", msg)
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-type EventAttributes struct {
|
|
|
|
- SenderID string `json:"SenderId"`
|
|
|
|
- SentTime time.Time `json:"SentTimestamp"`
|
|
|
|
- ApproximateReceiveCount int `json:"ApproximateReceiveCount"`
|
|
|
|
- ApproximateFirstReceiveTimestamp time.Time `json:"ApproximateFirstReceiveTimestamp"`
|
|
|
|
-}
|
|
|
|
-type Event struct {
|
|
|
|
- MessageID uuid.UUID `json:"MessageId"`
|
|
|
|
- BodySum string `json:"MD5OfBody"`
|
|
|
|
- AttrSum string `json:"MD5MofMessageAttributes"`
|
|
|
|
-
|
|
|
|
- EventAttributes
|
|
|
|
- MessageAttributes map[string]types.MessageAttributeValue
|
|
|
|
- Body []byte
|
|
|
|
|
|
+func receiveMessage(ctx context.Context, w io.Writer, client *sqs.Client, qURL string) {
|
|
|
|
+ rmi := sqs.ReceiveMessageInput{
|
|
|
|
+ QueueUrl: &qURL,
|
|
|
|
+ AttributeNames: []types.QueueAttributeName{"All"},
|
|
|
|
+ MessageAttributeNames: []string{"All"},
|
|
|
|
+ VisibilityTimeout: 1,
|
|
|
|
+ WaitTimeSeconds: 5,
|
|
|
|
+ }
|
|
|
|
+ msg, err := client.ReceiveMessage(ctx, &rmi)
|
|
|
|
+ if err != nil {
|
|
|
|
+ log.Fatalf("failed receiving from queue %s: %v", err)
|
|
|
|
+ }
|
|
|
|
+ spew.Fdump(w, msg.Messages)
|
|
}
|
|
}
|
|
|
|
|
|
func validateMessage(msg message) (*Event, error) {
|
|
func validateMessage(msg message) (*Event, error) {
|