github.com/Jeffail/benthos/v3@v3.65.0/lib/output/writer/azure_queue_storage.go (about)

     1  //go:build !wasm
     2  // +build !wasm
     3  
     4  package writer
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"time"
    10  
    11  	"github.com/Azure/azure-storage-queue-go/azqueue"
    12  	"github.com/Jeffail/benthos/v3/internal/bloblang/field"
    13  	"github.com/Jeffail/benthos/v3/internal/impl/azure"
    14  	"github.com/Jeffail/benthos/v3/internal/interop"
    15  	"github.com/Jeffail/benthos/v3/lib/log"
    16  	"github.com/Jeffail/benthos/v3/lib/metrics"
    17  	"github.com/Jeffail/benthos/v3/lib/types"
    18  )
    19  
    20  // AzureQueueStorage is a benthos writer.Type implementation that writes messages to an
    21  // Azure Queue Storage queue.
    22  type AzureQueueStorage struct {
    23  	conf AzureQueueStorageConfig
    24  
    25  	queueName  *field.Expression
    26  	ttl        *field.Expression
    27  	serviceURL *azqueue.ServiceURL
    28  
    29  	log   log.Modular
    30  	stats metrics.Type
    31  }
    32  
    33  // NewAzureQueueStorage creates a new Azure Queue Storage writer type.
    34  //
    35  // Deprecated: use the V2 API instead.
    36  func NewAzureQueueStorage(
    37  	conf AzureQueueStorageConfig,
    38  	log log.Modular,
    39  	stats metrics.Type,
    40  ) (*AzureQueueStorage, error) {
    41  	return NewAzureQueueStorageV2(conf, types.NoopMgr(), log, stats)
    42  }
    43  
    44  // NewAzureQueueStorageV2 creates a new Azure Queue Storage writer type.
    45  func NewAzureQueueStorageV2(
    46  	conf AzureQueueStorageConfig,
    47  	mgr types.Manager,
    48  	log log.Modular,
    49  	stats metrics.Type,
    50  ) (*AzureQueueStorage, error) {
    51  	serviceURL, err := azure.GetQueueServiceURL(conf.StorageAccount, conf.StorageAccessKey, conf.StorageConnectionString)
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  	s := &AzureQueueStorage{
    56  		conf:       conf,
    57  		log:        log,
    58  		stats:      stats,
    59  		serviceURL: serviceURL,
    60  	}
    61  
    62  	if s.ttl, err = interop.NewBloblangField(mgr, conf.TTL); err != nil {
    63  		return nil, fmt.Errorf("failed to parse ttl expression: %v", err)
    64  	}
    65  
    66  	if s.queueName, err = interop.NewBloblangField(mgr, conf.QueueName); err != nil {
    67  		return nil, fmt.Errorf("failed to parse queue name expression: %v", err)
    68  	}
    69  
    70  	return s, nil
    71  }
    72  
    73  // ConnectWithContext attempts to establish a connection to the target
    74  // queue.
    75  func (a *AzureQueueStorage) ConnectWithContext(ctx context.Context) error {
    76  	return nil
    77  }
    78  
    79  // Connect attempts to establish a connection to the target
    80  func (a *AzureQueueStorage) Connect() error {
    81  	return nil
    82  }
    83  
    84  // Write attempts to write message contents to a target Azure Queue Storage queue.
    85  func (a *AzureQueueStorage) Write(msg types.Message) error {
    86  	return a.WriteWithContext(context.Background(), msg)
    87  }
    88  
    89  // WriteWithContext attempts to write message contents to a target Queue Storage
    90  func (a *AzureQueueStorage) WriteWithContext(ctx context.Context, msg types.Message) error {
    91  	return IterateBatchedSend(msg, func(i int, p types.Part) error {
    92  		queueURL := a.serviceURL.NewQueueURL(a.queueName.String(i, msg))
    93  		msgURL := queueURL.NewMessagesURL()
    94  		var ttl *time.Duration
    95  		if ttls := a.ttl.String(i, msg); ttls != "" {
    96  			td, err := time.ParseDuration(ttls)
    97  			if err != nil {
    98  				a.log.Debugf("TTL must be a duration: %v\n", err)
    99  				return err
   100  			}
   101  			ttl = &td
   102  		}
   103  		timeToLive := func() time.Duration {
   104  			if ttl != nil {
   105  				return *ttl
   106  			}
   107  			return 0
   108  		}()
   109  		message := string(p.Get())
   110  		_, err := msgURL.Enqueue(ctx, message, 0, timeToLive)
   111  		if err != nil {
   112  			if cerr, ok := err.(azqueue.StorageError); ok {
   113  				if cerr.ServiceCode() == azqueue.ServiceCodeQueueNotFound {
   114  					ctx := context.Background()
   115  					_, err = queueURL.Create(ctx, azqueue.Metadata{})
   116  					if err != nil {
   117  						return fmt.Errorf("error creating queue: %v", err)
   118  					}
   119  					_, err := msgURL.Enqueue(ctx, message, 0, 0)
   120  					if err != nil {
   121  						return fmt.Errorf("error retrying to enqueue message: %v", err)
   122  					}
   123  				} else {
   124  					return fmt.Errorf("storage error message: %v", err)
   125  				}
   126  			} else {
   127  				return fmt.Errorf("error enqueuing message: %v", err)
   128  			}
   129  		}
   130  		return nil
   131  	})
   132  }
   133  
   134  // CloseAsync begins cleaning up resources used by this reader asynchronously.
   135  func (a *AzureQueueStorage) CloseAsync() {
   136  }
   137  
   138  // WaitForClose will block until either the reader is closed or a specified
   139  // timeout occurs.
   140  func (a *AzureQueueStorage) WaitForClose(time.Duration) error {
   141  	return nil
   142  }
   143  
   144  //------------------------------------------------------------------------------