github.com/Jeffail/benthos/v3@v3.65.0/lib/input/azure_queue_storage.go (about) 1 //go:build !wasm 2 // +build !wasm 3 4 package input 5 6 import ( 7 "context" 8 "fmt" 9 "strconv" 10 "time" 11 12 "github.com/Jeffail/benthos/v3/internal/bloblang/field" 13 "github.com/Jeffail/benthos/v3/internal/interop" 14 15 "github.com/Azure/azure-storage-queue-go/azqueue" 16 "github.com/Jeffail/benthos/v3/internal/impl/azure" 17 "github.com/Jeffail/benthos/v3/lib/input/reader" 18 "github.com/Jeffail/benthos/v3/lib/log" 19 "github.com/Jeffail/benthos/v3/lib/message" 20 "github.com/Jeffail/benthos/v3/lib/metrics" 21 "github.com/Jeffail/benthos/v3/lib/types" 22 ) 23 24 // AzureQueueStorage is a benthos reader.Type implementation that reads messages 25 // from an Azure Queue Storage container. 26 type azureQueueStorage struct { 27 conf AzureQueueStorageConfig 28 29 queueName *field.Expression 30 serviceURL *azqueue.ServiceURL 31 dequeueVisibilityTimeout time.Duration 32 33 log log.Modular 34 stats metrics.Type 35 } 36 37 // newAzureQueueStorage creates a new Azure Storage Queue input type. 38 func newAzureQueueStorage(conf AzureQueueStorageConfig, mgr types.Manager, log log.Modular, stats metrics.Type) (*azureQueueStorage, error) { 39 serviceURL, err := azure.GetQueueServiceURL(conf.StorageAccount, conf.StorageAccessKey, conf.StorageConnectionString) 40 if err != nil { 41 return nil, err 42 } 43 44 a := &azureQueueStorage{ 45 conf: conf, 46 log: log, 47 stats: stats, 48 serviceURL: serviceURL, 49 } 50 51 if a.queueName, err = interop.NewBloblangField(mgr, conf.QueueName); err != nil { 52 return nil, fmt.Errorf("failed to parse queue name expression: %v", err) 53 } 54 55 if len(conf.DequeueVisibilityTimeout) > 0 { 56 var err error 57 if a.dequeueVisibilityTimeout, err = time.ParseDuration(conf.DequeueVisibilityTimeout); err != nil { 58 return nil, fmt.Errorf("unable to parse dequeue visibility timeout duration string: %w", err) 59 } 60 } 61 62 return a, nil 63 } 64 65 // ConnectWithContext attempts to establish a connection 66 func (a *azureQueueStorage) ConnectWithContext(ctx context.Context) error { 67 return nil 68 } 69 70 // ReadWithContext attempts to read a new message from the target Azure Storage Queue Storage container. 71 func (a *azureQueueStorage) ReadWithContext(ctx context.Context) (msg types.Message, ackFn reader.AsyncAckFn, err error) { 72 queueName := a.queueName.String(0, msg) 73 queueURL := a.serviceURL.NewQueueURL(queueName) 74 messageURL := queueURL.NewMessagesURL() 75 var approxMsgCount int32 76 if a.conf.TrackProperties { 77 if props, err := queueURL.GetProperties(ctx); err == nil { 78 approxMsgCount = props.ApproximateMessagesCount() 79 } 80 } 81 dequeue, err := messageURL.Dequeue(ctx, a.conf.MaxInFlight, a.dequeueVisibilityTimeout) 82 if err != nil { 83 if cerr, ok := err.(azqueue.StorageError); ok { 84 if cerr.ServiceCode() == azqueue.ServiceCodeQueueNotFound { 85 ctx := context.Background() 86 _, err = queueURL.Create(ctx, azqueue.Metadata{}) 87 return nil, nil, err 88 } 89 return nil, nil, fmt.Errorf("storage error message: %v", cerr) 90 } 91 return nil, nil, fmt.Errorf("error dequeing message: %v", err) 92 } 93 if n := dequeue.NumMessages(); n > 0 { 94 props, _ := queueURL.GetProperties(ctx) 95 metadata := props.NewMetadata() 96 msg := message.New(nil) 97 dqm := make([]*azqueue.DequeuedMessage, n) 98 for i := int32(0); i < n; i++ { 99 queueMsg := dequeue.Message(i) 100 part := message.NewPart([]byte(queueMsg.Text)) 101 meta := part.Metadata() 102 meta.Set("queue_storage_insertion_time", queueMsg.InsertionTime.Format(time.RFC3339)) 103 meta.Set("queue_storage_queue_name", queueName) 104 if a.conf.TrackProperties { 105 msgLag := 0 106 if approxMsgCount >= n { 107 msgLag = int(approxMsgCount - n) 108 } 109 meta.Set("queue_storage_message_lag", strconv.Itoa(msgLag)) 110 } 111 for k, v := range metadata { 112 meta.Set(k, v) 113 } 114 msg.Append(part) 115 dqm[i] = queueMsg 116 } 117 return msg, func(ctx context.Context, res types.Response) error { 118 for i := int32(0); i < n; i++ { 119 msgIDURL := messageURL.NewMessageIDURL(dqm[i].ID) 120 _, err = msgIDURL.Delete(ctx, dqm[i].PopReceipt) 121 if err != nil { 122 return fmt.Errorf("error deleting message: %v", err) 123 } 124 } 125 return nil 126 }, nil 127 } 128 return nil, nil, nil 129 } 130 131 // CloseAsync begins cleaning up resources used by this reader asynchronously. 132 func (a *azureQueueStorage) CloseAsync() { 133 } 134 135 // WaitForClose will block until either the reader is closed or a specified 136 // timeout occurs. 137 func (a *azureQueueStorage) WaitForClose(time.Duration) error { 138 return nil 139 } 140 141 //------------------------------------------------------------------------------