github.com/aldelo/common@v1.5.1/wrapper/sqs/sqs.go (about) 1 package sqs 2 3 /* 4 * Copyright 2020-2023 Aldelo, LP 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 // ================================================================================================================= 20 // AWS CREDENTIAL: 21 // use $> aws configure (to set aws access key and secret to target machine) 22 // Store AWS Access ID and Secret Key into Default Profile Using '$ aws configure' cli 23 // 24 // To Install & Setup AWS CLI on Host: 25 // 1) https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-linux.html 26 // On Ubuntu, if host does not have zip and unzip: 27 // $> sudo apt install zip 28 // $> sudo apt install unzip 29 // On Ubuntu, to install AWS CLI v2: 30 // $> curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" 31 // $> unzip awscliv2.zip 32 // $> sudo ./aws/install 33 // 2) $> aws configure set region awsRegionName --profile default 34 // 3) $> aws configure 35 // follow prompts to enter Access ID and Secret Key 36 // 37 // AWS Region Name Reference: 38 // us-west-2, us-east-1, ap-northeast-1, etc 39 // See: https://docs.aws.amazon.com/general/latest/gr/rande.html 40 // ================================================================================================================= 41 42 import ( 43 "context" 44 "errors" 45 util "github.com/aldelo/common" 46 awshttp2 "github.com/aldelo/common/wrapper/aws" 47 "github.com/aldelo/common/wrapper/aws/awsregion" 48 "github.com/aldelo/common/wrapper/sqs/sqscreatequeueattribute" 49 "github.com/aldelo/common/wrapper/sqs/sqsgetqueueattribute" 50 "github.com/aldelo/common/wrapper/sqs/sqssetqueueattribute" 51 "github.com/aldelo/common/wrapper/sqs/sqssystemattribute" 52 "github.com/aldelo/common/wrapper/xray" 53 "github.com/aws/aws-sdk-go/aws" 54 "github.com/aws/aws-sdk-go/aws/session" 55 awssqs "github.com/aws/aws-sdk-go/service/sqs" 56 awsxray "github.com/aws/aws-xray-sdk-go/xray" 57 "net/http" 58 "strings" 59 "time" 60 ) 61 62 // ================================================================================================================ 63 // STRUCTS 64 // ================================================================================================================ 65 66 // SQS struct encapsulates the AWS SQS access functionality 67 type SQS struct { 68 // define the AWS region that SQS is located at 69 AwsRegion awsregion.AWSRegion 70 71 // custom http2 client options 72 HttpOptions *awshttp2.HttpClientSettings 73 74 // store SQS client object 75 sqsClient *awssqs.SQS 76 77 _parentSegment *xray.XRayParentSegment 78 } 79 80 // SQSMessageResult struct contains the message result via Send... operations 81 // 82 // MessageId = Message ID from SQS after send... operation 83 // MD5of... = MD5 of given data from SQS, PRIOR TO DATA URL-ENCODED by SQS, 84 // 85 // use this MD5 from SQS response to verify local value MD5 to check if SQS received data properly 86 // 87 // FifoSequenceNumber = For FIFO SQS Queue only 88 type SQSMessageResult struct { 89 MessageId string 90 MD5ofMessageBody string 91 MD5ofMessageAttributes string 92 FifoSequenceNumber string 93 } 94 95 // SQSStandardMessage struct represents a standard queue message to be used in Send... operations 96 // 97 // Id = up to 80 characters, alpha-numeric / dash, and unique, identifies the message within batch 98 type SQSStandardMessage struct { 99 Id string 100 MessageBody string 101 MessageAttributes map[string]*awssqs.MessageAttributeValue 102 DelaySeconds int64 103 } 104 105 // SQSFifoMessage struct represents a fifo queue message to be used in Send... operations 106 // 107 // Id = up to 80 characters, alpha-numeric / dash, and unique, identifies the message within batch 108 type SQSFifoMessage struct { 109 Id string 110 MessageDeduplicationId string 111 MessageGroupId string 112 MessageBody string 113 MessageAttributes map[string]*awssqs.MessageAttributeValue 114 } 115 116 // SQSSuccessResult struct represents a Send... batch operation success result 117 // 118 // Id = up to 80 characters, alpha-numeric / dash, and unique, identifies the message within batch 119 type SQSSuccessResult struct { 120 Id string 121 MessageId string 122 MD5ofMessageBody string 123 MD5ofMessageAttributes string 124 SequenceNumber string 125 } 126 127 // SQSFailResult struct represents a Send... batch operation failure result 128 // 129 // Id = up to 80 characters, alpha-numeric / dash, and unique, identifies the message within batch 130 type SQSFailResult struct { 131 Id string 132 Code string 133 Message string 134 SenderFault bool 135 } 136 137 // SQSReceivedMessage struct represents received message content elements 138 type SQSReceivedMessage struct { 139 MessageId string 140 Body string 141 MessageAttributes map[string]*awssqs.MessageAttributeValue 142 SystemAttributes map[sqssystemattribute.SQSSystemAttribute]string 143 MD5ofBody string 144 MD5ofMessageAttributes string 145 ReceiptHandle string 146 } 147 148 // SQSChangeVisibilityRequest struct represents the request data for change visibility for a message in sqs queue 149 type SQSChangeVisibilityRequest struct { 150 Id string 151 ReceiptHandle string 152 VisibilityTimeOutSeconds int64 153 } 154 155 // SQSDeleteMessageRequest struct represents the request data to delete a message from sqs queue 156 type SQSDeleteMessageRequest struct { 157 Id string 158 ReceiptHandle string 159 } 160 161 // ================================================================================================================ 162 // STRUCTS FUNCTIONS 163 // ================================================================================================================ 164 165 // ---------------------------------------------------------------------------------------------------------------- 166 // utility functions 167 // ---------------------------------------------------------------------------------------------------------------- 168 169 // Connect will establish a connection to the SQS service 170 func (s *SQS) Connect(parentSegment ...*xray.XRayParentSegment) (err error) { 171 if xray.XRayServiceOn() { 172 if len(parentSegment) > 0 { 173 s._parentSegment = parentSegment[0] 174 } 175 176 seg := xray.NewSegment("SQS-Connect", s._parentSegment) 177 defer seg.Close() 178 defer func() { 179 _ = seg.Seg.AddMetadata("SQS-AWS-Region", s.AwsRegion) 180 181 if err != nil { 182 _ = seg.Seg.AddError(err) 183 } 184 }() 185 186 err = s.connectInternal() 187 188 if err == nil { 189 awsxray.AWS(s.sqsClient.Client) 190 } 191 192 return err 193 } else { 194 return s.connectInternal() 195 } 196 } 197 198 // Connect will establish a connection to the SQS service 199 func (s *SQS) connectInternal() error { 200 // clean up prior sqs client reference 201 s.sqsClient = nil 202 203 if !s.AwsRegion.Valid() || s.AwsRegion == awsregion.UNKNOWN { 204 return errors.New("Connect to SQS Failed: (AWS Session Error) " + "Region is Required") 205 } 206 207 // create custom http2 client if needed 208 var httpCli *http.Client 209 var httpErr error 210 211 if s.HttpOptions == nil { 212 s.HttpOptions = new(awshttp2.HttpClientSettings) 213 } 214 215 // use custom http2 client 216 h2 := &awshttp2.AwsHttp2Client{ 217 Options: s.HttpOptions, 218 } 219 220 if httpCli, httpErr = h2.NewHttp2Client(); httpErr != nil { 221 return errors.New("Connect to SQS Failed: (AWS Session Error) " + "Create Custom http2 Client Errored = " + httpErr.Error()) 222 } 223 224 // establish aws session connection 225 if sess, err := session.NewSession( 226 &aws.Config{ 227 Region: aws.String(s.AwsRegion.Key()), 228 HTTPClient: httpCli, 229 }); err != nil { 230 // aws session error 231 return errors.New("Connect to SQS Failed: (AWS Session Error) " + err.Error()) 232 } else { 233 // create cached objects for shared use 234 s.sqsClient = awssqs.New(sess) 235 236 if s.sqsClient == nil { 237 return errors.New("Connect to SQS Client Failed: (New SQS Client Connection) " + "Connection Object Nil") 238 } 239 240 // connect successful 241 return nil 242 } 243 } 244 245 // Disconnect will clear sqs client 246 func (s *SQS) Disconnect() { 247 s.sqsClient = nil 248 } 249 250 // UpdateParentSegment updates this struct's xray parent segment, if no parent segment, set nil 251 func (s *SQS) UpdateParentSegment(parentSegment *xray.XRayParentSegment) { 252 s._parentSegment = parentSegment 253 } 254 255 // ---------------------------------------------------------------------------------------------------------------- 256 // internal helper methods 257 // ---------------------------------------------------------------------------------------------------------------- 258 259 // toAwsCreateQueueAttributes will convert from strongly typed to aws accepted map 260 func (s *SQS) toAwsCreateQueueAttributes(attributes map[sqscreatequeueattribute.SQSCreateQueueAttribute]string) (newMap map[string]*string) { 261 // validate 262 if attributes == nil { 263 return nil 264 } 265 266 // make map 267 newMap = make(map[string]*string) 268 269 for k, v := range attributes { 270 if k.Valid() && k != sqscreatequeueattribute.UNKNOWN { 271 newMap[k.Key()] = aws.String(v) 272 } 273 } 274 275 return newMap 276 } 277 278 // fromAwsCreateQueueAttributes will convert from aws map to strongly typed map 279 func (s *SQS) fromAwsCreateQueueAttributes(attributes map[string]*string) (newMap map[sqscreatequeueattribute.SQSCreateQueueAttribute]string) { 280 // validate 281 if attributes == nil { 282 return nil 283 } 284 285 // make map 286 newMap = make(map[sqscreatequeueattribute.SQSCreateQueueAttribute]string) 287 var conv sqscreatequeueattribute.SQSCreateQueueAttribute 288 289 for k, v := range attributes { 290 if util.LenTrim(k) > 0 { 291 v1 := aws.StringValue(v) 292 293 if k1, err := conv.ParseByKey(k); err == nil { 294 newMap[k1] = v1 295 } 296 } 297 } 298 299 return newMap 300 } 301 302 // toAwsGetQueueAttributes will convert from strongly typed to aws accepted map 303 func (s *SQS) toAwsGetQueueAttributes(attributes map[sqsgetqueueattribute.SQSGetQueueAttribute]string) (newMap map[string]*string) { 304 // validate 305 if attributes == nil { 306 return nil 307 } 308 309 // make map 310 newMap = make(map[string]*string) 311 312 for k, v := range attributes { 313 if k.Valid() && k != sqsgetqueueattribute.UNKNOWN { 314 newMap[k.Key()] = aws.String(v) 315 } 316 } 317 318 return newMap 319 } 320 321 // fromAwsGetQueueAttributes will convert from aws map to strongly typed map 322 func (s *SQS) fromAwsGetQueueAttributes(attributes map[string]*string) (newMap map[sqsgetqueueattribute.SQSGetQueueAttribute]string) { 323 // validate 324 if attributes == nil { 325 return nil 326 } 327 328 // make map 329 newMap = make(map[sqsgetqueueattribute.SQSGetQueueAttribute]string) 330 var conv sqsgetqueueattribute.SQSGetQueueAttribute 331 332 for k, v := range attributes { 333 if util.LenTrim(k) > 0 { 334 v1 := aws.StringValue(v) 335 336 if k1, err := conv.ParseByKey(k); err == nil { 337 newMap[k1] = v1 338 } 339 } 340 } 341 342 return newMap 343 } 344 345 // toAwsSetQueueAttributes will convert from strongly typed to aws accepted map 346 func (s *SQS) toAwsSetQueueAttributes(attributes map[sqssetqueueattribute.SQSSetQueueAttribute]string) (newMap map[string]*string) { 347 // validate 348 if attributes == nil { 349 return nil 350 } 351 352 // make map 353 newMap = make(map[string]*string) 354 355 for k, v := range attributes { 356 if k.Valid() && k != sqssetqueueattribute.UNKNOWN { 357 newMap[k.Key()] = aws.String(v) 358 } 359 } 360 361 return newMap 362 } 363 364 // fromAwsSetQueueAttributes will convert from aws map to strongly typed map 365 func (s *SQS) fromAwsSetQueueAttributes(attributes map[string]*string) (newMap map[sqssetqueueattribute.SQSSetQueueAttribute]string) { 366 // validate 367 if attributes == nil { 368 return nil 369 } 370 371 // make map 372 newMap = make(map[sqssetqueueattribute.SQSSetQueueAttribute]string) 373 var conv sqssetqueueattribute.SQSSetQueueAttribute 374 375 for k, v := range attributes { 376 if util.LenTrim(k) > 0 { 377 v1 := aws.StringValue(v) 378 379 if k1, err := conv.ParseByKey(k); err == nil { 380 newMap[k1] = v1 381 } 382 } 383 } 384 385 return newMap 386 } 387 388 // toAwsSystemAttributes will convert from strongly typed to aws accepted map 389 func (s *SQS) toAwsSystemAttributes(attributes map[sqssystemattribute.SQSSystemAttribute]string) (newMap map[string]*string) { 390 // validate 391 if attributes == nil { 392 return nil 393 } 394 395 // make map 396 newMap = make(map[string]*string) 397 398 for k, v := range attributes { 399 if k.Valid() && k != sqssystemattribute.UNKNOWN { 400 newMap[k.Key()] = aws.String(v) 401 } 402 } 403 404 return newMap 405 } 406 407 // fromAwsSystemAttributes will convert from aws map to strongly typed map 408 func (s *SQS) fromAwsSystemAttributes(attributes map[string]*string) (newMap map[sqssystemattribute.SQSSystemAttribute]string) { 409 // validate 410 if attributes == nil { 411 return nil 412 } 413 414 // make map 415 newMap = make(map[sqssystemattribute.SQSSystemAttribute]string) 416 var conv sqssystemattribute.SQSSystemAttribute 417 418 for k, v := range attributes { 419 if util.LenTrim(k) > 0 { 420 v1 := aws.StringValue(v) 421 422 if k1, err := conv.ParseByKey(k); err == nil { 423 newMap[k1] = v1 424 } 425 } 426 } 427 428 return newMap 429 } 430 431 // ---------------------------------------------------------------------------------------------------------------- 432 // queue management methods 433 // ---------------------------------------------------------------------------------------------------------------- 434 435 // GetQueueArnFromQueueUrl encodes arn from url data 436 func (s *SQS) GetQueueArnFromQueue(queueUrl string, timeoutDuration ...time.Duration) (arn string, err error) { 437 seg := xray.NewSegmentNullable("SQS-GetQueueArnFromQueue", s._parentSegment) 438 439 if seg != nil { 440 defer seg.Close() 441 defer func() { 442 _ = seg.Seg.AddMetadata("SQS-GetQueueArnFromQueue-QueueURL", queueUrl) 443 _ = seg.Seg.AddMetadata("SQS-GetQueueArnFromQueue-Result-ARN", arn) 444 445 if err != nil { 446 _ = seg.Seg.AddError(err) 447 } 448 }() 449 } 450 451 if attr, err := s.GetQueueAttributes(queueUrl, []sqsgetqueueattribute.SQSGetQueueAttribute{ 452 sqsgetqueueattribute.QueueArn, 453 }, timeoutDuration...); err != nil { 454 // error 455 return "", err 456 } else { 457 // found attribute 458 arn = attr[sqsgetqueueattribute.QueueArn] 459 return arn, nil 460 } 461 } 462 463 // CreateQueue will create a queue in SQS, 464 // if Queue is a FIFO, then queueName must suffix with .fifo, otherwise name it without .fifo suffix 465 // 466 // Parameters: 467 // 1. queueName = required, up to 80 characters alpha-numeric and dash, case-sensitive 468 // if fifo queue, must suffix name with '.fifo' (fifo queue guarantees fifo and delivery once but only 300 / second rate) 469 // 2. attributes = optional, map of create queue attribute key value pairs 470 // 3. timeOutDuration = optional, time out duration to use for context if applicable 471 // 472 // Return Values: 473 // 1. queueUrl = the queue url after queue was created 474 // 2. err = error info if any 475 // 476 // Create Queue Attributes: (Key = Expected Value) 477 // 478 // The following lists the names, descriptions, and values of the special request parameters that the CreateQueue action uses: 479 // 1) DelaySeconds = The length of time, in seconds, for which the delivery of all messages in the queue is delayed. 480 // Valid values: An integer from 0 to 900 seconds (15 minutes). Default: 0. 481 // 2)MaximumMessageSize = The limit of how many bytes a message can contain before Amazon SQS rejects it. 482 // Valid values: An integer from 1,024 bytes (1 KiB) to 262,144 bytes (256 KiB). Default: 262,144 (256 KiB). 483 // 3) MessageRetentionPeriod = The length of time, in seconds, for which Amazon SQS retains a message. 484 // Valid values: An integer from 60 seconds (1 minute) to 1,209,600 seconds (14 days). Default: 345,600 (4 days). 485 // 4) Policy = The queue's policy. A valid AWS policy. 486 // For more information about policy structure, 487 // see Overview of AWS IAM Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/PoliciesOverview.html) 488 // in the Amazon IAM User Guide. 489 // 5) ReceiveMessageWaitTimeSeconds = The length of time, in seconds, for which a ReceiveMessage action waits for a message to arrive. 490 // Valid values: An integer from 0 to 20 (seconds). Default: 0. 491 // 6) RedrivePolicy = The string that includes the parameters for the dead-letter queue functionality of the source queue as a JSON object. 492 // For more information about the redrive policy and dead-letter queues, 493 // see Using Amazon SQS Dead-Letter Queues (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html) 494 // in the Amazon Simple Queue Service Developer Guide. 495 // 7) deadLetterTargetArn = The Amazon Resource Name (ARN) of the dead-letter queue, 496 // to which Amazon SQS moves messages after the value of maxReceiveCount is exceeded. 497 // 8) maxReceiveCount = The number of times a message is delivered to the source queue before being moved to the dead-letter queue. 498 // When the ReceiveCount for a message exceeds the maxReceiveCount for a queue, 499 // Amazon SQS moves the message to the dead-letter-queue. 500 // The dead-letter queue of a FIFO queue must also be a FIFO queue. 501 // Similarly, the dead-letter queue of a standard queue must also be a standard queue. 502 // 9) VisibilityTimeout = The visibility timeout for the queue, in seconds. 503 // Valid values: An integer from 0 to 43,200 (12 hours). Default: 30. 504 // For more information about the visibility timeout, 505 // see Visibility Timeout (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html) 506 // in the Amazon Simple Queue Service Developer Guide. 507 // 508 // The following attributes apply only to server-side-encryption, 509 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html): 510 // 10) KmsMasterKeyId = The ID of an AWS-managed customer master key (CMK) for Amazon SQS or a custom CMK. 511 // For more information, see Key Terms (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html#sqs-sse-key-terms). 512 // While the alias of the AWS-managed CMK for Amazon SQS is always alias/aws/sqs, 513 // the alias of a custom CMK can, for example, be alias/MyAlias . 514 // For more examples, see KeyId (https://docs.aws.amazon.com/kms/latest/APIReference/API_DescribeKey.html#API_DescribeKey_RequestParameters) 515 // in the AWS Key Management Service API Reference. 516 // 11)KmsDataKeyReusePeriodSeconds = The length of time, in seconds, for which Amazon SQS can reuse a data key (https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#data-keys) 517 // to encrypt or decrypt messages before calling AWS KMS again. 518 // An integer representing seconds, 519 // between 60 seconds (1 minute) and 86,400 seconds (24 hours). Default: 300 (5 minutes). 520 // A shorter time period provides better security but results in more calls to KMS, 521 // which might incur charges after Free Tier. 522 // For more information, see How Does the Data Key Reuse Period Work? 523 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html#sqs-how-does-the-data-key-reuse-period-work). 524 // 525 // The following attributes apply only to FIFO (first-in-first-out) queues, 526 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html): 527 // 12) FifoQueue = (AT NEW QUEUE CREATION ONLY) Designates a queue as FIFO. Valid values: true, false. 528 // If you don't specify the FifoQueue attribute, Amazon SQS creates a standard queue. 529 // You can provide this attribute only during queue creation. You can't change it for an existing queue. 530 // When you set this attribute, you must also provide the MessageGroupId for your messages explicitly. 531 // For more information, see FIFO Queue Logic 532 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html#FIFO-queues-understanding-logic) 533 // in the Amazon Simple Queue Service Developer Guide. 534 // 13) ContentBasedDeduplication = Enables content-based deduplication. Valid values: true, false. 535 // For more information, see Exactly-Once Processing 536 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html#FIFO-queues-exactly-once-processing) 537 // in the Amazon Simple Queue Service Developer Guide. 538 // Every message must have a unique MessageDeduplicationId, You may provide a MessageDeduplicationId explicitly. 539 // If you aren't able to provide a MessageDeduplicationId 540 // and you enable ContentBasedDeduplication for your queue, 541 // Amazon SQS uses a SHA-256 hash to generate the MessageDeduplicationId 542 // using the body of the message (but not the attributes of the message). 543 // If you don't provide a MessageDeduplicationId and the queue doesn't have ContentBasedDeduplication set, 544 // the action fails with an error. 545 // If the queue has ContentBasedDeduplication set, your MessageDeduplicationId overrides the generated one. 546 // When ContentBasedDeduplication is in effect, 547 // messages with identical content sent within the deduplication interval are treated as duplicates, 548 // and only one copy of the message is delivered. 549 // If you send one message with ContentBasedDeduplication enabled, 550 // and then another message with a MessageDeduplicationId that is the same as the one generated, 551 // for the first MessageDeduplicationId, the two messages are treated as duplicates, 552 // and only one copy of the message is delivered. 553 func (s *SQS) CreateQueue(queueName string, 554 attributes map[sqscreatequeueattribute.SQSCreateQueueAttribute]string, 555 timeOutDuration ...time.Duration) (queueUrl string, err error) { 556 segCtx := context.Background() 557 segCtxSet := false 558 559 seg := xray.NewSegmentNullable("SQS-CreateQueue", s._parentSegment) 560 561 if seg != nil { 562 segCtx = seg.Ctx 563 segCtxSet = true 564 565 defer seg.Close() 566 defer func() { 567 _ = seg.Seg.AddMetadata("SQS-CreateQueue-QueueName", queueName) 568 _ = seg.Seg.AddMetadata("SQS-CreateQueue-Attributes", attributes) 569 _ = seg.Seg.AddMetadata("SQS-CreateQueue-Result-QueueURL", queueUrl) 570 571 if err != nil { 572 _ = seg.Seg.AddError(err) 573 } 574 }() 575 } 576 577 // validate 578 if s.sqsClient == nil { 579 err = errors.New("CreateQueue Failed: " + "SQS Client is Required") 580 return "", err 581 } 582 583 if util.LenTrim(queueName) <= 0 { 584 err = errors.New("CreateQueue Failed: " + "Queue Name is Required") 585 return "", err 586 } 587 588 // create input object 589 input := &awssqs.CreateQueueInput{ 590 QueueName: aws.String(queueName), 591 } 592 593 if attributes != nil { 594 input.Attributes = s.toAwsCreateQueueAttributes(attributes) 595 } 596 597 // perform action 598 var output *awssqs.CreateQueueOutput 599 600 if len(timeOutDuration) > 0 { 601 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 602 defer cancel() 603 604 output, err = s.sqsClient.CreateQueueWithContext(ctx, input) 605 } else { 606 if segCtxSet { 607 output, err = s.sqsClient.CreateQueueWithContext(segCtx, input) 608 } else { 609 output, err = s.sqsClient.CreateQueue(input) 610 } 611 } 612 613 // evaluate result 614 if err != nil { 615 err = errors.New("CreateQueue Failed: (Create Action) " + err.Error()) 616 return "", err 617 } else { 618 queueUrl = aws.StringValue(output.QueueUrl) 619 return queueUrl, nil 620 } 621 } 622 623 // GetQueueUrl returns the queue url for specific SQS queue 624 // 625 // queueName = required, case-sensitive 626 func (s *SQS) GetQueueUrl(queueName string, timeOutDuration ...time.Duration) (queueUrl string, notFound bool, err error) { 627 segCtx := context.Background() 628 segCtxSet := false 629 630 seg := xray.NewSegmentNullable("SQS-GetQueueUrl", s._parentSegment) 631 632 if seg != nil { 633 segCtx = seg.Ctx 634 segCtxSet = true 635 636 defer seg.Close() 637 defer func() { 638 _ = seg.Seg.AddMetadata("SQS-GetQueueUrl-QueueName", queueName) 639 _ = seg.Seg.AddMetadata("SQS-GetQueueUrl-Result-Not-Found", notFound) 640 _ = seg.Seg.AddMetadata("SQS-GetQueueUrl-Result-QueueURL", queueUrl) 641 642 if err != nil { 643 _ = seg.Seg.AddError(err) 644 } 645 }() 646 } 647 648 // validate 649 if s.sqsClient == nil { 650 notFound = true 651 err = errors.New("GetQueueUrl Failed: " + "SQS Client is Required") 652 return "", notFound, err 653 } 654 655 if util.LenTrim(queueName) <= 0 { 656 notFound = true 657 err = errors.New("GetQueueUrl Failed: " + "Queue Name is Required") 658 return "", notFound, err 659 } 660 661 // create input object 662 input := &awssqs.GetQueueUrlInput{ 663 QueueName: aws.String(queueName), 664 } 665 666 // perform action 667 var output *awssqs.GetQueueUrlOutput 668 669 if len(timeOutDuration) > 0 { 670 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 671 defer cancel() 672 673 output, err = s.sqsClient.GetQueueUrlWithContext(ctx, input) 674 } else { 675 if segCtxSet { 676 output, err = s.sqsClient.GetQueueUrlWithContext(segCtx, input) 677 } else { 678 output, err = s.sqsClient.GetQueueUrl(input) 679 } 680 } 681 682 // evaluate result 683 if err != nil { 684 if awshttp2.ToAwsError(err).Code() == awssqs.ErrCodeQueueDoesNotExist { 685 // queue does not exist - based on error code 686 notFound = true 687 return "", notFound, nil 688 689 } else if strings.Contains(strings.ToUpper(err.Error()), "THE SPECIFIED QUEUE DOES NOT EXIST") { 690 // queue does not exist - based on error message 691 notFound = true 692 return "", notFound, nil 693 694 } else { 695 // error 696 notFound = true 697 err = errors.New("GetQueueUrl Failed: (Get Action) " + err.Error()) 698 return "", notFound, err 699 700 } 701 } else { 702 queueUrl = aws.StringValue(output.QueueUrl) 703 return queueUrl, false, nil 704 705 } 706 } 707 708 // PurgeQueue will delete all messages within the SQS queue indicated by the queueUrl, 709 // deletion of messages will take up to 60 seconds, 710 // it is advisable to wait 60 seconds before attempting to use the queue again (to ensure purge completion) 711 // 712 // queueUrl = required, case-sensitive 713 func (s *SQS) PurgeQueue(queueUrl string, timeOutDuration ...time.Duration) (err error) { 714 segCtx := context.Background() 715 segCtxSet := false 716 717 seg := xray.NewSegmentNullable("SQS-PurgeQueue", s._parentSegment) 718 719 if seg != nil { 720 segCtx = seg.Ctx 721 segCtxSet = true 722 723 defer seg.Close() 724 defer func() { 725 _ = seg.Seg.AddMetadata("SQS-PurgeQueue-QueueURL", queueUrl) 726 727 if err != nil { 728 _ = seg.Seg.AddError(err) 729 } 730 }() 731 } 732 733 // validate 734 if s.sqsClient == nil { 735 err = errors.New("PurgeQueue Failed: " + "SQS Client is Required") 736 return err 737 } 738 739 if util.LenTrim(queueUrl) <= 0 { 740 err = errors.New("PurgeQueue Failed: " + "Queue Url is Required") 741 return err 742 } 743 744 // create input object 745 input := &awssqs.PurgeQueueInput{ 746 QueueUrl: aws.String(queueUrl), 747 } 748 749 // perform action 750 if len(timeOutDuration) > 0 { 751 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 752 defer cancel() 753 754 _, err = s.sqsClient.PurgeQueueWithContext(ctx, input) 755 } else { 756 if segCtxSet { 757 _, err = s.sqsClient.PurgeQueueWithContext(segCtx, input) 758 } else { 759 _, err = s.sqsClient.PurgeQueue(input) 760 } 761 } 762 763 // evaluate result 764 if err != nil { 765 err = errors.New("PurgeQueue Failed: (Purge Action) " + err.Error()) 766 return err 767 } else { 768 return nil 769 } 770 } 771 772 // DeleteQueue will delete the given SQS queue based on the queueUrl, 773 // there is a 60 second backoff time for the queue deletion to complete, 774 // do not send more messages to the queue within the 60 second deletion window of time 775 // 776 // queueUrl = required, case-sensitive 777 func (s *SQS) DeleteQueue(queueUrl string, timeOutDuration ...time.Duration) (err error) { 778 segCtx := context.Background() 779 segCtxSet := false 780 781 seg := xray.NewSegmentNullable("SQS-DeleteQueue", s._parentSegment) 782 783 if seg != nil { 784 segCtx = seg.Ctx 785 segCtxSet = true 786 787 defer seg.Close() 788 defer func() { 789 _ = seg.Seg.AddMetadata("SQS-DeleteQueue-QueueURL", queueUrl) 790 791 if err != nil { 792 _ = seg.Seg.AddError(err) 793 } 794 }() 795 } 796 797 // validate 798 if s.sqsClient == nil { 799 err = errors.New("DeleteQueue Failed: " + "SQS Client is Required") 800 return err 801 } 802 803 if util.LenTrim(queueUrl) <= 0 { 804 err = errors.New("DeleteQueue Failed: " + "Queue Url is Required") 805 return err 806 } 807 808 // create input object 809 input := &awssqs.DeleteQueueInput{ 810 QueueUrl: aws.String(queueUrl), 811 } 812 813 // perform action 814 if len(timeOutDuration) > 0 { 815 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 816 defer cancel() 817 818 _, err = s.sqsClient.DeleteQueueWithContext(ctx, input) 819 } else { 820 if segCtxSet { 821 _, err = s.sqsClient.DeleteQueueWithContext(segCtx, input) 822 } else { 823 _, err = s.sqsClient.DeleteQueue(input) 824 } 825 } 826 827 // evaluate result 828 if err != nil { 829 err = errors.New("DeleteQueue Failed: (Delete Action) " + err.Error()) 830 return err 831 } else { 832 return nil 833 } 834 } 835 836 // ListQueues will return a string slice of queue Urls 837 // 838 // Parameters: 839 // 1. queueNamePrefix = optional, match queues based on the queue name that starts with the specified prefix value, case-sensitive 840 // 2. nextToken = optional, if the prior call to ListQueues expected more values, a more...token is returned, to be used in this parameter 841 // 3. maxResults = optional, if > 0, the maximum results limited to 842 // 4. timeOutDuration = optional, timeout value to use within context 843 // 844 // Return Values: 845 // 1. queueUrlsList = string slice of queue urls 846 // 2. moreQueueUrlsNextToken = if more queue urls expected, use this token in the next method call by passing into nextToken parameter 847 // 3. err = error info if any 848 func (s *SQS) ListQueues(queueNamePrefix string, 849 nextToken string, 850 maxResults int64, 851 timeOutDuration ...time.Duration) (queueUrlsList []string, moreQueueUrlsNextToken string, err error) { 852 segCtx := context.Background() 853 segCtxSet := false 854 855 seg := xray.NewSegmentNullable("SQS-ListQueues", s._parentSegment) 856 857 if seg != nil { 858 segCtx = seg.Ctx 859 segCtxSet = true 860 861 defer seg.Close() 862 defer func() { 863 _ = seg.Seg.AddMetadata("SQS-ListQueues-QueueNamePrefix", queueNamePrefix) 864 _ = seg.Seg.AddMetadata("SQS-ListQueues-NextToken", nextToken) 865 _ = seg.Seg.AddMetadata("SQS-ListQueues-MaxResults", maxResults) 866 _ = seg.Seg.AddMetadata("SQS-ListQueues-Result-QueueUrlsList", queueUrlsList) 867 _ = seg.Seg.AddMetadata("SQS-ListQueues-Result-NextToken", moreQueueUrlsNextToken) 868 869 if err != nil { 870 _ = seg.Seg.AddError(err) 871 } 872 }() 873 } 874 875 // validate 876 if s.sqsClient == nil { 877 err = errors.New("ListQueues Failed: " + "SQS Client is Required") 878 return nil, "", err 879 } 880 881 // create input object 882 input := &awssqs.ListQueuesInput{} 883 884 if util.LenTrim(queueNamePrefix) > 0 { 885 input.QueueNamePrefix = aws.String(queueNamePrefix) 886 } 887 888 if util.LenTrim(nextToken) > 0 { 889 input.NextToken = aws.String(nextToken) 890 } 891 892 if maxResults > 0 { 893 input.MaxResults = aws.Int64(maxResults) 894 } 895 896 // perform action 897 var output *awssqs.ListQueuesOutput 898 899 if len(timeOutDuration) > 0 { 900 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 901 defer cancel() 902 903 output, err = s.sqsClient.ListQueuesWithContext(ctx, input) 904 } else { 905 if segCtxSet { 906 output, err = s.sqsClient.ListQueuesWithContext(segCtx, input) 907 } else { 908 output, err = s.sqsClient.ListQueues(input) 909 } 910 } 911 912 // evaluate result 913 if err != nil { 914 err = errors.New("ListQueues Failed: (List Action) " + err.Error()) 915 return nil, "", err 916 } else { 917 queueUrlsList = aws.StringValueSlice(output.QueueUrls) 918 moreQueueUrlsNextToken = aws.StringValue(output.NextToken) 919 return queueUrlsList, moreQueueUrlsNextToken, nil 920 } 921 } 922 923 // ListDeadLetterSourceQueues will retrieve a list of source queue urls, 924 // that have its RedrivePolicy set to the given Dead Letter Queue as specified in queueUrl parameter 925 // 926 // Parameters: 927 // 1. queueUrl= required, the dead letter queue url for which to list the dead letter source queues, case-sensitive 928 // 2. nextToken = optional, if the prior call to ListDeadLetterSourceQueues expected more values, a more...token is returned, to be used in this parameter 929 // 3. maxResults = optional, if > 0, the maximum results limited to 930 // 4. timeOutDuration = optional, timeout value to use within context 931 // 932 // Return Values: 933 // 1. queueUrlsList = string slice of source queue urls that points to the dead letter queue as indicated in queueUrl parameter 934 // 2. moreQueueUrlsNextToken = if more queue urls expected, use this token in the next method call by passing into nextToken parameter 935 // 3. err = error info if any 936 func (s *SQS) ListDeadLetterSourceQueues(queueUrl string, 937 nextToken string, 938 maxResults int64, 939 timeOutDuration ...time.Duration) (queueUrlsList []string, moreQueueUrlsNextToken string, err error) { 940 segCtx := context.Background() 941 segCtxSet := false 942 943 seg := xray.NewSegmentNullable("SQS-ListDeadLetterSourceQueues", s._parentSegment) 944 945 if seg != nil { 946 segCtx = seg.Ctx 947 segCtxSet = true 948 949 defer seg.Close() 950 defer func() { 951 _ = seg.Seg.AddMetadata("SQS-ListDeadLetterSourceQueues-QueueURL", queueUrl) 952 _ = seg.Seg.AddMetadata("SQS-ListDeadLetterSourceQueues-NextToken", nextToken) 953 _ = seg.Seg.AddMetadata("SQS-ListDeadLetterSourceQueues-MaxResults", maxResults) 954 _ = seg.Seg.AddMetadata("SQS-ListDeadLetterSourceQueues-Result-QueueUrlsList", queueUrlsList) 955 _ = seg.Seg.AddMetadata("SQS-ListDeadLetterSourceQueues-Result-NextToken", moreQueueUrlsNextToken) 956 957 if err != nil { 958 _ = seg.Seg.AddError(err) 959 } 960 }() 961 } 962 963 // validate 964 if s.sqsClient == nil { 965 err = errors.New("ListDeadLetterSourceQueues Failed: " + "SQS Client is Required") 966 return nil, "", err 967 } 968 969 if util.LenTrim(queueUrl) <= 0 { 970 err = errors.New("ListDeadLetterSourceQueues Failed: " + "Dead Letter Queue Url is Required") 971 return nil, "", err 972 } 973 974 // create input object 975 input := &awssqs.ListDeadLetterSourceQueuesInput{ 976 QueueUrl: aws.String(queueUrl), 977 } 978 979 if util.LenTrim(nextToken) > 0 { 980 input.NextToken = aws.String(nextToken) 981 } 982 983 if maxResults > 0 { 984 input.MaxResults = aws.Int64(maxResults) 985 } 986 987 // perform action 988 var output *awssqs.ListDeadLetterSourceQueuesOutput 989 990 if len(timeOutDuration) > 0 { 991 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 992 defer cancel() 993 994 output, err = s.sqsClient.ListDeadLetterSourceQueuesWithContext(ctx, input) 995 } else { 996 if segCtxSet { 997 output, err = s.sqsClient.ListDeadLetterSourceQueuesWithContext(segCtx, input) 998 } else { 999 output, err = s.sqsClient.ListDeadLetterSourceQueues(input) 1000 } 1001 } 1002 1003 // evaluate result 1004 if err != nil { 1005 err = errors.New("ListDeadLetterSourceQueues Failed: (List Action) " + err.Error()) 1006 return nil, "", err 1007 } else { 1008 queueUrlsList = aws.StringValueSlice(output.QueueUrls) 1009 moreQueueUrlsNextToken = aws.StringValue(output.NextToken) 1010 return queueUrlsList, moreQueueUrlsNextToken, nil 1011 } 1012 } 1013 1014 // GetQueueAttributes will retrieve queue attributes for a given queueUrl, filtered by the attributeNames slice parameter 1015 // 1016 // Parameters: 1017 // 1. queueUrl = required, the queue url for which queue attributes are retrieved against, case-sensitive 1018 // 2. attributeNames = required, slice of attribute names to filter attributes for (see notes below for allowed attribute name values) 1019 // 3. timeOutDuration = optional, timeout duration for context if applicable 1020 // 1021 // Return Values: 1022 // 1. attributes = map of get queue attributes key value pairs retrieved 1023 // 2. err = error info if any 1024 // 1025 // Get Queue Attributes: (Key = Expected Value) 1026 // 1027 // 1. All = Returns all values. 1028 // 1029 // 2. ApproximateNumberOfMessages = Returns the approximate number of messages available for retrieval from the queue. 1030 // 1031 // 3. ApproximateNumberOfMessagesDelayed = Returns the approximate number of messages in the queue that are delayed 1032 // and not available for reading immediately. 1033 // This can happen when the queue is configured as a delay queue 1034 // or when a message has been sent with a delay parameter. 1035 // 1036 // 4. ApproximateNumberOfMessagesNotVisible = Returns the approximate number of messages that are in flight. 1037 // Messages are considered to be in flight if they have been sent to a client 1038 // but have not yet been deleted, or have not yet reached the end of their visibility window. 1039 // 1040 // 5. CreatedTimestamp = Returns the time when the queue was created in seconds (epoch time (http://en.wikipedia.org/wiki/Unix_time)). 1041 // 1042 // 6. DelaySeconds = Returns the default delay on the queue in seconds. 1043 // 1044 // 7. LastModifiedTimestamp = Returns the time when the queue was last changed in seconds (epoch time (http://en.wikipedia.org/wiki/Unix_time)). 1045 // 1046 // 8. MaximumMessageSize = Returns the limit of how many bytes a message can contain before Amazon SQS rejects it. 1047 // 1048 // 9. MessageRetentionPeriod = Returns the length of time, in seconds, for which Amazon SQS retains a message. 1049 // 1050 // 10. Policy = Returns the policy of the queue. 1051 // 1052 // 11. QueueArn = Returns the Amazon resource name (ARN) of the queue. 1053 // 1054 // 12. ReceiveMessageWaitTimeSeconds = Returns the length of time, in seconds, 1055 // for which the ReceiveMessage action waits for a message to arrive. 1056 // 1057 // 13. RedrivePolicy = The string that includes the parameters for the dead-letter queue functionality of the source queue as a JSON object. 1058 // For more information about the redrive policy and dead-letter queues, 1059 // see Using Amazon SQS Dead-Letter Queues (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html) 1060 // in the Amazon Simple Queue Service Developer Guide. 1061 // 1062 // 14. deadLetterTargetArn = The Amazon Resource Name (ARN) of the dead-letter queue to which 1063 // Amazon SQS moves messages after the value of maxReceiveCount is exceeded. 1064 // 1065 // 15. maxReceiveCount = The number of times a message is delivered to the source queue before being moved to the dead-letter queue. 1066 // When the ReceiveCount for a message exceeds the maxReceiveCount for a queue, 1067 // Amazon SQS moves the message to the dead-letter-queue. 1068 // 1069 // 16. VisibilityTimeout = Returns the visibility timeout for the queue. 1070 // For more information about the visibility timeout, see Visibility Timeout 1071 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html) 1072 // in the Amazon Simple Queue Service Developer Guide. 1073 // 1074 // The following attributes apply only to server-side-encryption 1075 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html): 1076 // 1077 // 17. KmsMasterKeyId = Returns the ID of an AWS-managed customer master key (CMK) for Amazon SQS or a custom CMK. 1078 // For more information, see Key Terms 1079 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html#sqs-sse-key-terms). 1080 // 18)KmsDataKeyReusePeriodSeconds = Returns the length of time, in seconds, 1081 // for which Amazon SQS can reuse a data key to encrypt or decrypt messages before calling AWS KMS again. 1082 // For more information, see How Does the Data Key Reuse Period Work? 1083 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html#sqs-how-does-the-data-key-reuse-period-work). 1084 // 1085 // The following attributes apply only to FIFO (first-in-first-out) queues 1086 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html): 1087 // 1088 // 19. FifoQueue = Returns whether the queue is FIFO. 1089 // For more information, see FIFO Queue Logic 1090 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html#FIFO-queues-understanding-logic) 1091 // in the Amazon Simple Queue Service Developer Guide. 1092 // To determine whether a queue is FIFO 1093 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html), 1094 // you can check whether QueueName ends with the .fifo suffix. 1095 // 1096 // 20. ContentBasedDeduplication = Returns whether content-based deduplication is enabled for the queue. 1097 // For more information, see Exactly-Once Processing 1098 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html#FIFO-queues-exactly-once-processing) 1099 // in the Amazon Simple Queue Service Developer Guide. 1100 func (s *SQS) GetQueueAttributes(queueUrl string, 1101 attributeNames []sqsgetqueueattribute.SQSGetQueueAttribute, 1102 timeOutDuration ...time.Duration) (attributes map[sqsgetqueueattribute.SQSGetQueueAttribute]string, err error) { 1103 segCtx := context.Background() 1104 segCtxSet := false 1105 1106 seg := xray.NewSegmentNullable("SQS-GetQueueAttributes", s._parentSegment) 1107 1108 if seg != nil { 1109 segCtx = seg.Ctx 1110 segCtxSet = true 1111 1112 defer seg.Close() 1113 defer func() { 1114 _ = seg.Seg.AddMetadata("SQS-GetQueueAttributes-QueueURL", queueUrl) 1115 _ = seg.Seg.AddMetadata("SQS-GetQueueAttributes-AttributeNames", attributeNames) 1116 _ = seg.Seg.AddMetadata("SQS-GetQueueAttributes-Result-Attributes", attributes) 1117 1118 if err != nil { 1119 _ = seg.Seg.AddError(err) 1120 } 1121 }() 1122 } 1123 1124 // validate 1125 if s.sqsClient == nil { 1126 err = errors.New("GetQueueAttributes Failed: " + "SQS Client is Required") 1127 return nil, err 1128 } 1129 1130 if util.LenTrim(queueUrl) <= 0 { 1131 err = errors.New("GetQueueAttributes Failed: " + "Queue Url is Required") 1132 return nil, err 1133 } 1134 1135 if attributeNames == nil { 1136 err = errors.New("GetQueueAttributes Failed: " + "Attribute Names Map is Required (nil)") 1137 return nil, err 1138 } 1139 1140 if len(attributeNames) <= 0 { 1141 err = errors.New("GetQueueAttributes Failed: " + "Attribute Names Map is Required (len = 0)") 1142 return nil, err 1143 } 1144 1145 // create input object 1146 var keys []*string 1147 1148 for _, v := range attributeNames { 1149 if v.Valid() && v != sqsgetqueueattribute.UNKNOWN { 1150 keys = append(keys, aws.String(v.Key())) 1151 } 1152 } 1153 1154 input := &awssqs.GetQueueAttributesInput{ 1155 QueueUrl: aws.String(queueUrl), 1156 AttributeNames: keys, 1157 } 1158 1159 // perform action 1160 var output *awssqs.GetQueueAttributesOutput 1161 1162 if len(timeOutDuration) > 0 { 1163 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 1164 defer cancel() 1165 1166 output, err = s.sqsClient.GetQueueAttributesWithContext(ctx, input) 1167 } else { 1168 if segCtxSet { 1169 output, err = s.sqsClient.GetQueueAttributesWithContext(segCtx, input) 1170 } else { 1171 output, err = s.sqsClient.GetQueueAttributes(input) 1172 } 1173 } 1174 1175 // evaluate result 1176 if err != nil { 1177 err = errors.New("GetQueueAttributes Failed: (Get Action) " + err.Error()) 1178 return nil, err 1179 } else { 1180 attributes = s.fromAwsGetQueueAttributes(output.Attributes) 1181 return attributes, nil 1182 } 1183 } 1184 1185 // SetQueueAttributes will set attributes for a given queueUrl 1186 // 1187 // Parameters: 1188 // 1. queueUrl = required, the queue to set attributes for, case-sensitive 1189 // 2. attributes = required, map of attribute key value pairs to set for a queue based on the queueUrl 1190 // 3. timeOutDuration = optional, timeout duration for context if applicable 1191 // 1192 // Return Values: 1193 // 1. if successful, nil is returned 1194 // 2. otherwise, error info is returned 1195 // 1196 // Set Queue Attributes: (Key = Expected Value) 1197 // 1198 // 1. DelaySeconds = The length of time, in seconds, for which the delivery of all messages in the queue is delayed. 1199 // Valid values: An integer from 0 to 900 (15 minutes). Default: 0. 1200 // 1201 // 2. MaximumMessageSize = The limit of how many bytes a message can contain before Amazon SQS rejects it. 1202 // Valid values: An integer from 1,024 bytes (1 KiB) up to 262,144 bytes (256 KiB). Default: 262,144 (256 KiB). 1203 // 1204 // 3. MessageRetentionPeriod = The length of time, in seconds, for which Amazon SQS retains a message. 1205 // Valid values: An integer representing seconds, 1206 // from 60 (1 minute) to 1,209,600 (14 days). Default: 345,600 (4 days). 1207 // 1208 // 4. Policy = The queue's policy. A valid AWS policy. For more information about policy structure, 1209 // see Overview of AWS IAM Policies 1210 // (https://docs.aws.amazon.com/IAM/latest/UserGuide/PoliciesOverview.html) 1211 // in the Amazon IAM User Guide. 1212 // 1213 // 5. ReceiveMessageWaitTimeSeconds = The length of time, in seconds, for which a ReceiveMessage action waits for a message to arrive. 1214 // Valid values: An integer from 0 to 20 (seconds). Default: 0. 1215 // 1216 // 6. RedrivePolicy = The string that includes the parameters for the dead-letter queue functionality of the source queue as a JSON object. 1217 // For more information about the redrive policy and dead-letter queues, see Using Amazon SQS Dead-Letter Queues 1218 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html ) 1219 // in the Amazon Simple Queue Service Developer Guide. 1220 // 1221 // 7. deadLetterTargetArn = The Amazon Resource Name (ARN) of the dead-letter queue to which Amazon SQS moves messages 1222 // after the value of maxReceiveCount is exceeded. 1223 // 1224 // 8. maxReceiveCount = The number of times a message is delivered to the source queue before being moved to the dead-letter queue. 1225 // When the ReceiveCount for a message exceeds the maxReceiveCount for a queue, 1226 // Amazon SQS moves the message to the dead-letter-queue. 1227 // The dead-letter queue of a FIFO queue must also be a FIFO queue. 1228 // Similarly, the dead-letter queue of a standard queue must also be a standard queue. 1229 // 1230 // 9. VisibilityTimeout = The visibility timeout for the queue, in seconds. 1231 // Valid values: An integer from 0 to 43,200 (12 hours). Default: 30. 1232 // For more information about the visibility timeout, see Visibility Timeout 1233 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html) 1234 // in the Amazon Simple Queue Service Developer Guide. 1235 // 1236 // The following attributes apply only to server-side-encryption 1237 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html): 1238 // 1239 // 10. KmsMasterKeyId = The ID of an AWS-managed customer master key (CMK) for Amazon SQS or a custom CMK. 1240 // For more information, see Key Terms 1241 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html#sqs-sse-key-terms). 1242 // While the alias of the AWS-managed CMK for Amazon SQS is always alias/aws/sqs, 1243 // the alias of a custom CMK can, for example, be alias/MyAlias. 1244 // For more examples, see KeyId (https://docs.aws.amazon.com/kms/latest/APIReference/API_DescribeKey.html#API_DescribeKey_RequestParameters) 1245 // in the AWS Key Management Service API Reference. 1246 // 1247 // 11. KmsDataKeyReusePeriodSeconds = The length of time, in seconds, for which Amazon SQS can reuse a data key, 1248 // to encrypt or decrypt messages before calling AWS KMS again. 1249 // See more info at (https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#data-keys) 1250 // Valid Value is an integer representing seconds, 1251 // between 60 seconds (1 minute) and 86,400 seconds (24 hours). 1252 // Default: 300 (5 minutes). 1253 // A shorter time period provides better security but results in more calls to KMS 1254 // which might incur charges after Free Tier. 1255 // For more information, see How Does the Data Key Reuse Period Work? 1256 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html#sqs-how-does-the-data-key-reuse-period-work). 1257 // 1258 // The following attribute applies only to FIFO (first-in-first-out) queues 1259 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html): 1260 // 1261 // 12. ContentBasedDeduplication = Enables content-based deduplication. 1262 // For more information, see Exactly-Once Processing 1263 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html#FIFO-queues-exactly-once-processing) 1264 // in the Amazon Simple Queue Service Developer Guide. 1265 // Every message must have a unique MessageDeduplicationId, 1266 // You may provide a MessageDeduplicationId explicitly. 1267 // If you aren't able to provide a MessageDeduplicationId and you enable ContentBasedDeduplication 1268 // for your queue, Amazon SQS uses a SHA-256 hash to generate the MessageDeduplicationId 1269 // using the body of the message (but not the attributes of the message). 1270 // If you don't provide a MessageDeduplicationId and the queue doesn't have ContentBasedDeduplication set, 1271 // the action fails with an error. 1272 // If the queue has ContentBasedDeduplication set, your MessageDeduplicationId overrides the generated one. 1273 // When ContentBasedDeduplication is in effect, 1274 // messages with identical content sent within the deduplication interval 1275 // are treated as duplicates and only one copy of the message is delivered. 1276 // If you send one message with ContentBasedDeduplication enabled 1277 // and then another message with a MessageDeduplicationId that is the same as the one generated 1278 // for the first MessageDeduplicationId, the two messages are treated as duplicates 1279 // and only one copy of the message is delivered. 1280 func (s *SQS) SetQueueAttributes(queueUrl string, 1281 attributes map[sqssetqueueattribute.SQSSetQueueAttribute]string, 1282 timeOutDuration ...time.Duration) (err error) { 1283 segCtx := context.Background() 1284 segCtxSet := false 1285 1286 seg := xray.NewSegmentNullable("SQS-SetQueueAttributes", s._parentSegment) 1287 1288 if seg != nil { 1289 segCtx = seg.Ctx 1290 segCtxSet = true 1291 1292 defer seg.Close() 1293 defer func() { 1294 _ = seg.Seg.AddMetadata("SQS-SetQueueAttributes-QueueURL", queueUrl) 1295 _ = seg.Seg.AddMetadata("SQS-SetQueueAttributes-Attributes", attributes) 1296 1297 if err != nil { 1298 _ = seg.Seg.AddError(err) 1299 } 1300 }() 1301 } 1302 1303 // validate 1304 if s.sqsClient == nil { 1305 err = errors.New("SetQueueAttributes Failed: " + "SQS Client is Required") 1306 return err 1307 } 1308 1309 if util.LenTrim(queueUrl) <= 0 { 1310 err = errors.New("SetQueueAttributes Failed: " + "Queue Url is Required") 1311 return err 1312 } 1313 1314 if attributes == nil { 1315 err = errors.New("SetQueueAttributes Failed: " + "Attributes Map is Required") 1316 return err 1317 } 1318 1319 // create input object 1320 input := &awssqs.SetQueueAttributesInput{ 1321 QueueUrl: aws.String(queueUrl), 1322 Attributes: s.toAwsSetQueueAttributes(attributes), 1323 } 1324 1325 // perform action 1326 if len(timeOutDuration) > 0 { 1327 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 1328 defer cancel() 1329 1330 _, err = s.sqsClient.SetQueueAttributesWithContext(ctx, input) 1331 } else { 1332 if segCtxSet { 1333 _, err = s.sqsClient.SetQueueAttributesWithContext(segCtx, input) 1334 } else { 1335 _, err = s.sqsClient.SetQueueAttributes(input) 1336 } 1337 } 1338 1339 // evaluate result 1340 if err != nil { 1341 err = errors.New("SetQueueAttributes Failed: (Set Action) " + err.Error()) 1342 return err 1343 } else { 1344 return nil 1345 } 1346 } 1347 1348 // ---------------------------------------------------------------------------------------------------------------- 1349 // messaging related methods 1350 // ---------------------------------------------------------------------------------------------------------------- 1351 1352 // SendMessage will send a standard message to SQS standard queue via queue url 1353 // 1354 // Parameters: 1355 // 1. queueUrl = required, the queue to send message to 1356 // 2. messageBody = required, the message to send to the queue 1357 // 3. messageAttributes = optional, map of message attribute key value pairs. 1358 // Each message attribute consists of a Name, Type, and Value. 1359 // For more information, see Amazon SQS Message Attributes: 1360 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-message-attributes.html) 1361 // in the Amazon Simple Queue Service Developer Guide. 1362 // Example: use message attributes to define meta data about the message being sent: 1363 // a) { 1364 // "Title": { DataType: "String", StringValue: "The Whistler"}, 1365 // "Author": { DataType: "String", StringValue: "John Grisham"}, 1366 // "WeeksOn": { DataType: "Number", StringValue: "6"} 1367 // } 1368 // 4. delaySeconds = optional, if greater than 0, indicates how many seconds to delay before message is available to consumers 1369 // 5. timeOutDuration = optional, timeout value for context if any 1370 // 1371 // Return Values: 1372 // 1. result = struct containing Send... action message result 1373 // 2. err = error info if any 1374 func (s *SQS) SendMessage(queueUrl string, 1375 messageBody string, 1376 messageAttributes map[string]*awssqs.MessageAttributeValue, 1377 delaySeconds int64, 1378 timeOutDuration ...time.Duration) (result *SQSMessageResult, err error) { 1379 segCtx := context.Background() 1380 segCtxSet := false 1381 1382 seg := xray.NewSegmentNullable("SQS-SendMessage", s._parentSegment) 1383 1384 if seg != nil { 1385 segCtx = seg.Ctx 1386 segCtxSet = true 1387 1388 defer seg.Close() 1389 defer func() { 1390 _ = seg.Seg.AddMetadata("SQS-SendMessage-QueueURL", queueUrl) 1391 _ = seg.Seg.AddMetadata("SQS-SendMessage-MessageBody", messageBody) 1392 _ = seg.Seg.AddMetadata("SQS-SendMessage-MessageAttributes", messageAttributes) 1393 _ = seg.Seg.AddMetadata("SQS-SendMessage-DelaySeconds", delaySeconds) 1394 _ = seg.Seg.AddMetadata("SQS-SendMessage-Result", result) 1395 1396 if err != nil { 1397 _ = seg.Seg.AddError(err) 1398 } 1399 }() 1400 } 1401 1402 // validate 1403 if s.sqsClient == nil { 1404 err = errors.New("SendMessage Failed: " + "SQS Client is Required") 1405 return nil, err 1406 } 1407 1408 if util.LenTrim(queueUrl) <= 0 { 1409 err = errors.New("SendMessage Failed: " + "Queue Url is Required") 1410 return nil, err 1411 } 1412 1413 if util.LenTrim(messageBody) <= 0 { 1414 err = errors.New("SendMessage Failed: " + "Message Body is Required") 1415 return nil, err 1416 } 1417 1418 // create input object 1419 input := &awssqs.SendMessageInput{ 1420 QueueUrl: aws.String(queueUrl), 1421 MessageBody: aws.String(messageBody), 1422 } 1423 1424 if messageAttributes != nil { 1425 input.MessageAttributes = messageAttributes 1426 } 1427 1428 if delaySeconds > 0 { 1429 input.DelaySeconds = aws.Int64(delaySeconds) 1430 } 1431 1432 // perform action 1433 var output *awssqs.SendMessageOutput 1434 1435 if len(timeOutDuration) > 0 { 1436 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 1437 defer cancel() 1438 1439 output, err = s.sqsClient.SendMessageWithContext(ctx, input) 1440 } else { 1441 if segCtxSet { 1442 output, err = s.sqsClient.SendMessageWithContext(segCtx, input) 1443 } else { 1444 output, err = s.sqsClient.SendMessage(input) 1445 } 1446 } 1447 1448 // evaluate result 1449 if err != nil { 1450 err = errors.New("SendMessage Failed: (Send Action) " + err.Error()) 1451 return nil, err 1452 } else { 1453 result = &SQSMessageResult{ 1454 MessageId: aws.StringValue(output.MessageId), 1455 MD5ofMessageBody: aws.StringValue(output.MD5OfMessageBody), 1456 MD5ofMessageAttributes: aws.StringValue(output.MD5OfMessageAttributes), 1457 FifoSequenceNumber: "", 1458 } 1459 return result, nil 1460 } 1461 } 1462 1463 // SendMessageFifo will send a fifo message to SQS fifo queue via queue url 1464 // 1465 // Parameters: 1466 // 1. queueUrl = required, the queue to send message to 1467 // 2. messageDeduplicationId = required, The token used for deduplication of sent messages. 1468 // If a message with a particular MessageDeduplicationId is sent successfully, 1469 // any messages sent with the same MessageDeduplicationId are accepted successfully 1470 // but aren't delivered during the 5-minute deduplication interval. 1471 // For more information, see Exactly-Once Processing 1472 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html#FIFO-queues-exactly-once-processing) 1473 // in the Amazon Simple Queue Service Developer Guide. 1474 // Every message must have a unique MessageDeduplicationId, You may provide a MessageDeduplicationId explicitly. 1475 // If you aren't able to provide a MessageDeduplicationId, 1476 // and you enable ContentBasedDeduplication for your queue, 1477 // Amazon SQS uses a SHA-256 hash to generate the MessageDeduplicationId, 1478 // using the body of the message (but not the attributes of the message). 1479 // If you don't provide a MessageDeduplicationId and the queue doesn't have ContentBasedDeduplication set, 1480 // the action fails with an error. 1481 // If the queue has ContentBasedDeduplication set, your MessageDeduplicationId overrides the generated one. 1482 // When ContentBasedDeduplication is in effect, 1483 // messages with identical content sent within the deduplication interval are treated as duplicates 1484 // and only one copy of the message is delivered. 1485 // If you send one message with ContentBasedDeduplication enabled, 1486 // and then another message with a MessageDeduplicationId that is 1487 // the same as the one generated for the first MessageDeduplicationId, 1488 // the two messages are treated as duplicates and only one copy of the message is delivered. 1489 // The MessageDeduplicationId is available to the consumer of the message, 1490 // (this can be useful for troubleshooting delivery issues). 1491 // If a message is sent successfully but the acknowledgement is lost and the message is resent 1492 // with the same MessageDeduplicationId after the deduplication interval, 1493 // Amazon SQS can't detect duplicate messages. 1494 // Amazon SQS continues to keep track of the message deduplication ID, 1495 // even after the message is received and deleted. 1496 // The maximum length of MessageDeduplicationId is 128 characters. 1497 // MessageDeduplicationId can contain alphanumeric characters (a-z, A-Z, 0-9) 1498 // and punctuation (!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~). 1499 // For best practices of using MessageDeduplicationId, 1500 // see Using the MessageDeduplicationId Property 1501 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/using-messagededuplicationid-property.html) 1502 // in the Amazon Simple Queue Service Developer Guide. 1503 // 3. messageGroupId = required, The tag that specifies that a message belongs to a specific message group. 1504 // Messages that belong to the same message group are processed in a FIFO manner, 1505 // however, messages in different message groups might be processed out of order. 1506 // To interleave multiple ordered streams within a single queue, 1507 // use MessageGroupId values (for example, session data for multiple users). 1508 // In this scenario, multiple consumers can process the queue, 1509 // but the session data of each user is processed in a FIFO fashion. 1510 // You must associate a non-empty MessageGroupId with a message, 1511 // if you don't provide a MessageGroupId, the action fails. 1512 // ReceiveMessage might return messages with multiple MessageGroupId values, 1513 // For each MessageGroupId, the messages are sorted by time sent, 1514 // The caller can't specify a MessageGroupId. 1515 // The length of MessageGroupId is 128 characters, 1516 // Valid values: alphanumeric characters and punctuation (!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~). 1517 // For best practices of using MessageGroupId, 1518 // see Using the MessageGroupId Property 1519 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/using-messagegroupid-property.html) 1520 // in the Amazon Simple Queue Service Developer Guide. 1521 // MessageGroupId is required for FIFO queues. You can't use it for Standard queues. 1522 // 4. messageBody = required, the message to send to the queue 1523 // 5. messageAttributes = optional, map of message attribute key value pairs. 1524 // Each message attribute consists of a Name, Type, and Value. 1525 // For more information, see Amazon SQS Message Attributes: 1526 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-message-attributes.html) 1527 // in the Amazon Simple Queue Service Developer Guide. 1528 // Example: use message attributes to define meta data about the message being sent: 1529 // a) { 1530 // "Title": { DataType: "String", StringValue: "The Whistler"}, 1531 // "Author": { DataType: "String", StringValue: "John Grisham"}, 1532 // "WeeksOn": { DataType: "Number", StringValue: "6"} 1533 // } 1534 // 6. timeOutDuration = optional, timeout value for context if any 1535 // 1536 // Return Values: 1537 // 1. result = struct containing Send... action message result 1538 // 2. err = error info if any 1539 func (s *SQS) SendMessageFifo(queueUrl string, 1540 messageDeduplicationId string, 1541 messageGroupId string, 1542 messageBody string, 1543 messageAttributes map[string]*awssqs.MessageAttributeValue, 1544 timeOutDuration ...time.Duration) (result *SQSMessageResult, err error) { 1545 segCtx := context.Background() 1546 segCtxSet := false 1547 1548 seg := xray.NewSegmentNullable("SQS-SendMessageFifo", s._parentSegment) 1549 1550 if seg != nil { 1551 segCtx = seg.Ctx 1552 segCtxSet = true 1553 1554 defer seg.Close() 1555 defer func() { 1556 _ = seg.Seg.AddMetadata("SQS-SendMessageFifo-QueueURL", queueUrl) 1557 _ = seg.Seg.AddMetadata("SQS-SendMessageFifo-MessageDeduplicationID", messageDeduplicationId) 1558 _ = seg.Seg.AddMetadata("SQS-SendMessageFifo-MessageGroupID", messageGroupId) 1559 _ = seg.Seg.AddMetadata("SQS-SendMessageFifo-MessageBody", messageBody) 1560 _ = seg.Seg.AddMetadata("SQS-SendMessageFifo-MessageAttributes", messageAttributes) 1561 _ = seg.Seg.AddMetadata("SQS-SendMessageFifo-Result", result) 1562 1563 if err != nil { 1564 _ = seg.Seg.AddError(err) 1565 } 1566 }() 1567 } 1568 1569 // validate 1570 if s.sqsClient == nil { 1571 err = errors.New("SendMessageFifo Failed: " + "SQS Client is Required") 1572 return nil, err 1573 } 1574 1575 if util.LenTrim(queueUrl) <= 0 { 1576 err = errors.New("SendMessageFifo Failed: " + "Queue Url is Required") 1577 return nil, err 1578 } 1579 1580 if util.LenTrim(messageDeduplicationId) <= 0 { 1581 err = errors.New("SendMessageFifo Failed: " + "Message Deduplication Id is Required") 1582 return nil, err 1583 } 1584 1585 if util.LenTrim(messageGroupId) <= 0 { 1586 err = errors.New("SendMessageFifo Failed: " + "Message Group Id is Required") 1587 return nil, err 1588 } 1589 1590 if util.LenTrim(messageBody) <= 0 { 1591 err = errors.New("SendMessageFifo Failed: " + "Message Body is Required") 1592 return nil, err 1593 } 1594 1595 // create input object 1596 input := &awssqs.SendMessageInput{ 1597 QueueUrl: aws.String(queueUrl), 1598 MessageDeduplicationId: aws.String(messageDeduplicationId), 1599 MessageGroupId: aws.String(messageGroupId), 1600 MessageBody: aws.String(messageBody), 1601 } 1602 1603 if messageAttributes != nil { 1604 input.MessageAttributes = messageAttributes 1605 } 1606 1607 // perform action 1608 var output *awssqs.SendMessageOutput 1609 1610 if len(timeOutDuration) > 0 { 1611 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 1612 defer cancel() 1613 1614 output, err = s.sqsClient.SendMessageWithContext(ctx, input) 1615 } else { 1616 if segCtxSet { 1617 output, err = s.sqsClient.SendMessageWithContext(segCtx, input) 1618 } else { 1619 output, err = s.sqsClient.SendMessage(input) 1620 } 1621 } 1622 1623 // evaluate result 1624 if err != nil { 1625 err = errors.New("SendMessageFifo Failed: (Send Action) " + err.Error()) 1626 return nil, err 1627 } else { 1628 result = &SQSMessageResult{ 1629 MessageId: aws.StringValue(output.MessageId), 1630 MD5ofMessageBody: aws.StringValue(output.MD5OfMessageBody), 1631 MD5ofMessageAttributes: aws.StringValue(output.MD5OfMessageAttributes), 1632 FifoSequenceNumber: aws.StringValue(output.SequenceNumber), 1633 } 1634 return result, nil 1635 } 1636 } 1637 1638 // SendMessageBatch will send up to 10 standard messages in a batch to SQS standard queue as indicated by queueUrl 1639 func (s *SQS) SendMessageBatch(queueUrl string, 1640 messageEntries []*SQSStandardMessage, 1641 timeOutDuration ...time.Duration) (successList []*SQSSuccessResult, failedList []*SQSFailResult, err error) { 1642 segCtx := context.Background() 1643 segCtxSet := false 1644 1645 seg := xray.NewSegmentNullable("SQS-SendMessageBatch", s._parentSegment) 1646 1647 if seg != nil { 1648 segCtx = seg.Ctx 1649 segCtxSet = true 1650 1651 defer seg.Close() 1652 defer func() { 1653 _ = seg.Seg.AddMetadata("SQS-SendMessageBatch-QueueURL", queueUrl) 1654 _ = seg.Seg.AddMetadata("SQS-SendMessageBatch-MessageEntries", messageEntries) 1655 _ = seg.Seg.AddMetadata("SQS-SendMessageBatch-Result-SuccessList", successList) 1656 _ = seg.Seg.AddMetadata("SQS-SendMessageBatch-Result-FailedList", failedList) 1657 1658 if err != nil { 1659 _ = seg.Seg.AddError(err) 1660 } 1661 }() 1662 } 1663 1664 // validate 1665 if s.sqsClient == nil { 1666 err = errors.New("SendMessageBatch Failed: " + "SQS Client is Required") 1667 return nil, nil, err 1668 } 1669 1670 if util.LenTrim(queueUrl) <= 0 { 1671 err = errors.New("SendMessageBatch Failed: " + "Queue Url is Required") 1672 return nil, nil, err 1673 } 1674 1675 if messageEntries == nil { 1676 err = errors.New("SendMessageBatch Failed: " + "Message Entries Required (nil)") 1677 return nil, nil, err 1678 } 1679 1680 if len(messageEntries) <= 0 { 1681 err = errors.New("SendMessageBatch Failed: " + "Message Entries Required (count = 0)") 1682 return nil, nil, err 1683 } 1684 1685 if len(messageEntries) > 10 { 1686 err = errors.New("SendMessageBatch Failed: " + "Message Entries Per Batch Limited to 10") 1687 return nil, nil, err 1688 } 1689 1690 // create input object 1691 var entries []*awssqs.SendMessageBatchRequestEntry 1692 1693 for _, v := range messageEntries { 1694 if util.LenTrim(v.Id) > 0 && util.LenTrim(v.MessageBody) > 0 { 1695 entries = append(entries, &awssqs.SendMessageBatchRequestEntry{ 1696 Id: aws.String(v.Id), 1697 MessageBody: aws.String(v.MessageBody), 1698 MessageAttributes: v.MessageAttributes, 1699 DelaySeconds: aws.Int64(v.DelaySeconds), 1700 }) 1701 } 1702 } 1703 1704 if len(entries) <= 0 { 1705 err = errors.New("SendMessageBatch Failed: " + "Message Entries Elements Count Must Not Be Zero") 1706 return nil, nil, err 1707 } 1708 1709 input := &awssqs.SendMessageBatchInput{ 1710 QueueUrl: aws.String(queueUrl), 1711 Entries: entries, 1712 } 1713 1714 // perform action 1715 var output *awssqs.SendMessageBatchOutput 1716 1717 if len(timeOutDuration) > 0 { 1718 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 1719 defer cancel() 1720 1721 output, err = s.sqsClient.SendMessageBatchWithContext(ctx, input) 1722 } else { 1723 if segCtxSet { 1724 output, err = s.sqsClient.SendMessageBatchWithContext(segCtx, input) 1725 } else { 1726 output, err = s.sqsClient.SendMessageBatch(input) 1727 } 1728 } 1729 1730 // evaluate result 1731 if err != nil { 1732 err = errors.New("SendMessageBatch Failed: (Send Action) " + err.Error()) 1733 return nil, nil, err 1734 } else { 1735 if len(output.Successful) > 0 { 1736 for _, v := range output.Successful { 1737 successList = append(successList, &SQSSuccessResult{ 1738 Id: aws.StringValue(v.Id), 1739 MessageId: aws.StringValue(v.MessageId), 1740 MD5ofMessageBody: aws.StringValue(v.MD5OfMessageBody), 1741 MD5ofMessageAttributes: aws.StringValue(v.MD5OfMessageAttributes), 1742 }) 1743 } 1744 } 1745 1746 if len(output.Failed) > 0 { 1747 for _, v := range output.Failed { 1748 failedList = append(failedList, &SQSFailResult{ 1749 Id: aws.StringValue(v.Id), 1750 Code: aws.StringValue(v.Code), 1751 Message: aws.StringValue(v.Message), 1752 SenderFault: aws.BoolValue(v.SenderFault), 1753 }) 1754 } 1755 } 1756 1757 return successList, failedList, nil 1758 } 1759 } 1760 1761 // SendMessageBatchFifo will send up to 10 fifo messages in a batch to SQS fifo queue as indicated by queueUrl 1762 func (s *SQS) SendMessageBatchFifo(queueUrl string, 1763 messageEntries []*SQSFifoMessage, 1764 timeOutDuration ...time.Duration) (successList []*SQSSuccessResult, failedList []*SQSFailResult, err error) { 1765 segCtx := context.Background() 1766 segCtxSet := false 1767 1768 seg := xray.NewSegmentNullable("SQS-SendMessageBatchFifo", s._parentSegment) 1769 1770 if seg != nil { 1771 segCtx = seg.Ctx 1772 segCtxSet = true 1773 1774 defer seg.Close() 1775 defer func() { 1776 _ = seg.Seg.AddMetadata("SQS-SendMessageBatchFifo-QueueURL", queueUrl) 1777 _ = seg.Seg.AddMetadata("SQS-SendMessageBatchFifo-MessageEntries", messageEntries) 1778 _ = seg.Seg.AddMetadata("SQS-SendMessageBatchFifo-Result-SuccessList", successList) 1779 _ = seg.Seg.AddMetadata("SQS-SendMessageBatchFifo-Result-FailedList", failedList) 1780 1781 if err != nil { 1782 _ = seg.Seg.AddError(err) 1783 } 1784 }() 1785 } 1786 1787 // validate 1788 if s.sqsClient == nil { 1789 err = errors.New("SendMessageBatchFifo Failed: " + "SQS Client is Required") 1790 return nil, nil, err 1791 } 1792 1793 if util.LenTrim(queueUrl) <= 0 { 1794 err = errors.New("SendMessageBatchFifo Failed: " + "Queue Url is Required") 1795 return nil, nil, err 1796 } 1797 1798 if messageEntries == nil { 1799 err = errors.New("SendMessageBatchFifo Failed: " + "Message Entries Required (nil)") 1800 return nil, nil, err 1801 } 1802 1803 if len(messageEntries) <= 0 { 1804 err = errors.New("SendMessageBatchFifo Failed: " + "Message Entries Required (count = 0)") 1805 return nil, nil, err 1806 } 1807 1808 if len(messageEntries) > 10 { 1809 err = errors.New("SendMessageBatchFifo Failed: " + "Message Entries Per Batch Limited to 10") 1810 return nil, nil, err 1811 } 1812 1813 // create input object 1814 var entries []*awssqs.SendMessageBatchRequestEntry 1815 1816 for _, v := range messageEntries { 1817 if util.LenTrim(v.Id) > 0 && util.LenTrim(v.MessageBody) > 0 && util.LenTrim(v.MessageGroupId) > 0 && util.LenTrim(v.MessageDeduplicationId) > 0 { 1818 entries = append(entries, &awssqs.SendMessageBatchRequestEntry{ 1819 Id: aws.String(v.Id), 1820 MessageDeduplicationId: aws.String(v.MessageDeduplicationId), 1821 MessageGroupId: aws.String(v.MessageGroupId), 1822 MessageBody: aws.String(v.MessageBody), 1823 MessageAttributes: v.MessageAttributes, 1824 }) 1825 } 1826 } 1827 1828 if len(entries) <= 0 { 1829 err = errors.New("SendMessageBatchFifo Failed: " + "Message Entries Elements Count Must Not Be Zero") 1830 return nil, nil, err 1831 } 1832 1833 input := &awssqs.SendMessageBatchInput{ 1834 QueueUrl: aws.String(queueUrl), 1835 Entries: entries, 1836 } 1837 1838 // perform action 1839 var output *awssqs.SendMessageBatchOutput 1840 1841 if len(timeOutDuration) > 0 { 1842 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 1843 defer cancel() 1844 1845 output, err = s.sqsClient.SendMessageBatchWithContext(ctx, input) 1846 } else { 1847 if segCtxSet { 1848 output, err = s.sqsClient.SendMessageBatchWithContext(segCtx, input) 1849 } else { 1850 output, err = s.sqsClient.SendMessageBatch(input) 1851 } 1852 } 1853 1854 // evaluate result 1855 if err != nil { 1856 err = errors.New("SendMessageBatchFifo Failed: (Send Action) " + err.Error()) 1857 return nil, nil, err 1858 } else { 1859 if len(output.Successful) > 0 { 1860 for _, v := range output.Successful { 1861 successList = append(successList, &SQSSuccessResult{ 1862 Id: aws.StringValue(v.Id), 1863 MessageId: aws.StringValue(v.MessageId), 1864 MD5ofMessageBody: aws.StringValue(v.MD5OfMessageBody), 1865 MD5ofMessageAttributes: aws.StringValue(v.MD5OfMessageAttributes), 1866 SequenceNumber: aws.StringValue(v.SequenceNumber), 1867 }) 1868 } 1869 } 1870 1871 if len(output.Failed) > 0 { 1872 for _, v := range output.Failed { 1873 failedList = append(failedList, &SQSFailResult{ 1874 Id: aws.StringValue(v.Id), 1875 Code: aws.StringValue(v.Code), 1876 Message: aws.StringValue(v.Message), 1877 SenderFault: aws.BoolValue(v.SenderFault), 1878 }) 1879 } 1880 } 1881 1882 return successList, failedList, nil 1883 } 1884 } 1885 1886 // ReceiveMessage will retrieve 1 or more (up to 10) messages from the SQS (standard or fifo) queue indicated by queueUrl, 1887 // note that this method retrieves the message(s), and blocks them from other consumer view for a short time, but does not delete such messages, 1888 // to delete the messages, consumer must call the DeleteMessage methods accordingly 1889 // 1890 // Parameters: 1891 // 1. queueUrl = required, retrieve message(s) from this queue as indicated by queueUrl, either standard or fifo queue, case-sensitive 1892 // 2. maxNumberOfMessages = required, valid value is 1 - 10, indicates the maximum number of messages to retrieve during the method call 1893 // 3. messageAttributeNames = optional, string slice of message attribute names to retrieve as related to the received messages. 1894 // Attribute names are case-sensitive, alphanumeric, -, _, . are allowed. 1895 // To receive all message attributes, use filter name as 'All' or '.*'. 1896 // To receive all message attributes with a prefix pattern, use filter name as 'xyz.*', 1897 // where attribute names prefix with xyz are included in the return list. 1898 // 4. systemAttributeNames = optional, string slice of system attribute names to retrieve as related to the received messages. 1899 // Attribute names are case-sensitive, alphanumeric, -, _, . are allowed. 1900 // Key-Value Pairs: 1901 // a) All = Return all system attributes and values. 1902 // b) ApproximateFirstReceiveTimestamp = Returns the time the message was first received 1903 // from the queue in milliseconds. 1904 // (epoch time (http://en.wikipedia.org/wiki/Unix_time) 1905 // c) ApproximateReceiveCount = Returns the number of times a message has been received 1906 // across all queues but not deleted. 1907 // d) AWSTraceHeader = Returns the AWS X-Ray trace header string. 1908 // e) SenderId = For an IAM user, returns the IAM user ID, for example ABCDEFGHI1JKLMNOPQ23R. 1909 // For an IAM role, returns the IAM role ID, for example ABCDE1F2GH3I4JK5LMNOP:i-a123b456. 1910 // f) SentTimestamp = Returns the time the message was sent to the queue, 1911 // Epoch time = http://en.wikipedia.org/wiki/Unix_time in milliseconds. 1912 // g) MessageDeduplicationId = Returns the value provided by the producer that calls the SendMessage action. 1913 // h) MessageGroupId = Returns the value provided by the producer that calls the SendMessage action. 1914 // Messages with the same MessageGroupId are returned in sequence. 1915 // i) SequenceNumber = Returns the value provided by Amazon SQS. 1916 // 5. visibilityTimeOutSeconds = optional, The duration (in seconds) that the received messages are hidden 1917 // from subsequent retrieve requests after being retrieved by a ReceiveMessage request. 1918 // 6. waitTimeSeconds = optional, The duration (in seconds) for which the call waits for a message to arrive in the queue before returning. 1919 // If a message is available, the call returns sooner than WaitTimeSeconds. 1920 // If no messages are available and the wait time expires, 1921 // the call returns successfully with an empty list of messages. 1922 // To avoid HTTP errors, ensure that the HTTP response timeout 1923 // for ReceiveMessage requests is longer than the WaitTimeSeconds parameter. 1924 // 7. receiveRequestAttemptId = optional, applies to FIFO queue ONLY. The token used for deduplication of ReceiveMessage calls. 1925 // If a networking issue occurs after a ReceiveMessage action, 1926 // and instead of a response you receive a generic error. 1927 // It is possible to retry the same action with an identical ReceiveRequestAttemptId, 1928 // to retrieve the same set of messages, even if their visibility timeout has not yet expired. 1929 // 1930 // More About FIFO's receiveRequestAttemptId: 1931 // 1932 // a) You can use ReceiveRequestAttemptId only for 5 minutes after a ReceiveMessage action. 1933 // b) When you set FifoQueue, a caller of the ReceiveMessage action can provide a ReceiveRequestAttemptId explicitly. 1934 // c) If a caller of the ReceiveMessage action doesn't provide a ReceiveRequestAttemptId, Amazon SQS generates a ReceiveRequestAttemptId. 1935 // d) It is possible to retry the ReceiveMessage action with the same ReceiveRequestAttemptId, 1936 // if none of the messages have been modified (deleted or had their visibility changes). 1937 // e) During a visibility timeout, subsequent calls with the same ReceiveRequestAttemptId return the same messages and receipt handles. 1938 // If a retry occurs within the deduplication interval, it resets the visibility timeout. 1939 // For more information, see Visibility Timeout in the Amazon Simple Queue Service Developer Guide. 1940 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html) 1941 // If a caller of the ReceiveMessage action still processes messages when the visibility timeout expires 1942 // and messages become visible, another worker consuming from the same queue can receive the same messages 1943 // and therefore process duplicates. 1944 // Also, if a consumer whose message processing time is longer than the visibility timeout tries to delete the processed messages, 1945 // the action fails with an error. To mitigate this effect, ensure that your application observes 1946 // a safe threshold before the visibility timeout expires and extend the visibility timeout as necessary. 1947 // f) While messages with a particular MessageGroupId are invisible, 1948 // no more messages belonging to the same MessageGroupId are returned until the visibility timeout expires. 1949 // You can still receive messages with another MessageGroupId as long as it is also visible. 1950 // g) If a caller of ReceiveMessage can't track the ReceiveRequestAttemptId, no retries work until the original visibility timeout expires. 1951 // As a result, delays might occur but the messages in the queue remain in a strict order. 1952 // h) The maximum length of ReceiveRequestAttemptId is 128 characters. 1953 // ReceiveRequestAttemptId can contain alphanumeric characters (a-z, A-Z, 0-9) and punctuation (!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~). 1954 // i) For best practices of using ReceiveRequestAttemptId, 1955 // see Using the ReceiveRequestAttemptId Request Parameter in the Amazon Simple Queue Service Developer Guide. 1956 // (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/using-receiverequestattemptid-request-parameter.html) 1957 func (s *SQS) ReceiveMessage(queueUrl string, 1958 maxNumberOfMessages int64, 1959 messageAttributeNames []string, 1960 systemAttributeNames []sqssystemattribute.SQSSystemAttribute, 1961 visibilityTimeOutSeconds int64, 1962 waitTimeSeconds int64, 1963 receiveRequestAttemptId string, 1964 timeOutDuration ...time.Duration) (messagesList []*SQSReceivedMessage, err error) { 1965 segCtx := context.Background() 1966 segCtxSet := false 1967 1968 seg := xray.NewSegmentNullable("SQS-ReceiveMessage", s._parentSegment) 1969 1970 if seg != nil { 1971 segCtx = seg.Ctx 1972 segCtxSet = true 1973 1974 defer seg.Close() 1975 defer func() { 1976 _ = seg.Seg.AddMetadata("SQS-ReceiveMessage-QueueURL", queueUrl) 1977 _ = seg.Seg.AddMetadata("SQS-ReceiveMessage-MaxNumberOfMessages", maxNumberOfMessages) 1978 _ = seg.Seg.AddMetadata("SQS-ReceiveMessage-MessageAttributeNames", messageAttributeNames) 1979 _ = seg.Seg.AddMetadata("SQS-ReceiveMessage-SystemAttributeNames", systemAttributeNames) 1980 _ = seg.Seg.AddMetadata("SQS-ReceiveMessage-VisibilityTimeOutSeconds", visibilityTimeOutSeconds) 1981 _ = seg.Seg.AddMetadata("SQS-ReceiveMessage-WaitTimeSeconds", waitTimeSeconds) 1982 _ = seg.Seg.AddMetadata("SQS-ReceiveMessage-ReceiveRequestAttemptID", receiveRequestAttemptId) 1983 _ = seg.Seg.AddMetadata("SQS-ReceiveMessage-Result-MessagesList", messagesList) 1984 1985 if err != nil { 1986 _ = seg.Seg.AddError(err) 1987 } 1988 }() 1989 } 1990 1991 // validate 1992 if s.sqsClient == nil { 1993 err = errors.New("ReceiveMessage Failed: " + "SQS Client is Required") 1994 return nil, err 1995 } 1996 1997 if util.LenTrim(queueUrl) <= 0 { 1998 err = errors.New("ReceiveMessage Failed: " + "Queue Url is Required") 1999 return nil, err 2000 } 2001 2002 if maxNumberOfMessages <= 0 || maxNumberOfMessages > 10 { 2003 err = errors.New("ReceiveMessage Failed: " + "Max Number of Messages Must Be 1 to 10") 2004 return nil, err 2005 } 2006 2007 if visibilityTimeOutSeconds < 0 { 2008 visibilityTimeOutSeconds = 0 2009 } 2010 2011 if waitTimeSeconds < 0 { 2012 waitTimeSeconds = 0 2013 } 2014 2015 // create input object 2016 input := &awssqs.ReceiveMessageInput{ 2017 QueueUrl: aws.String(queueUrl), 2018 MaxNumberOfMessages: aws.Int64(maxNumberOfMessages), 2019 } 2020 2021 if len(messageAttributeNames) > 0 { 2022 input.MessageAttributeNames = aws.StringSlice(messageAttributeNames) 2023 } 2024 2025 if len(systemAttributeNames) > 0 { 2026 var keys []*string 2027 2028 for _, v := range systemAttributeNames { 2029 if v.Valid() && v != sqssystemattribute.UNKNOWN { 2030 keys = append(keys, aws.String(v.Key())) 2031 } 2032 } 2033 2034 input.AttributeNames = keys 2035 } 2036 2037 if visibilityTimeOutSeconds > 0 { 2038 input.VisibilityTimeout = aws.Int64(visibilityTimeOutSeconds) 2039 } 2040 2041 if waitTimeSeconds > 0 { 2042 input.WaitTimeSeconds = aws.Int64(waitTimeSeconds) 2043 } 2044 2045 if util.LenTrim(receiveRequestAttemptId) > 0 { 2046 input.ReceiveRequestAttemptId = aws.String(receiveRequestAttemptId) 2047 } 2048 2049 // perform action 2050 var output *awssqs.ReceiveMessageOutput 2051 2052 if len(timeOutDuration) > 0 { 2053 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 2054 defer cancel() 2055 2056 output, err = s.sqsClient.ReceiveMessageWithContext(ctx, input) 2057 } else { 2058 if segCtxSet { 2059 output, err = s.sqsClient.ReceiveMessageWithContext(segCtx, input) 2060 } else { 2061 output, err = s.sqsClient.ReceiveMessage(input) 2062 } 2063 } 2064 2065 // evaluate result 2066 if err != nil { 2067 err = errors.New("ReceiveMessage Failed: (Receive Action) " + err.Error()) 2068 return nil, err 2069 } else { 2070 for _, v := range output.Messages { 2071 if v != nil { 2072 messagesList = append(messagesList, &SQSReceivedMessage{ 2073 MessageId: aws.StringValue(v.MessageId), 2074 Body: aws.StringValue(v.Body), 2075 MessageAttributes: v.MessageAttributes, 2076 SystemAttributes: s.fromAwsSystemAttributes(v.Attributes), 2077 MD5ofBody: aws.StringValue(v.MD5OfBody), 2078 MD5ofMessageAttributes: aws.StringValue(v.MD5OfMessageAttributes), 2079 ReceiptHandle: aws.StringValue(v.ReceiptHandle), 2080 }) 2081 } 2082 } 2083 2084 return messagesList, nil 2085 } 2086 } 2087 2088 // ChangeMessageVisibility will update a message's visibility time out seconds, 2089 // the message's receiptHandle is used along with queueUrl to identify which message in which queue is to be updated the new timeout value 2090 func (s *SQS) ChangeMessageVisibility(queueUrl string, 2091 receiptHandle string, 2092 visibilityTimeOutSeconds int64, 2093 timeOutDuration ...time.Duration) (err error) { 2094 segCtx := context.Background() 2095 segCtxSet := false 2096 2097 seg := xray.NewSegmentNullable("SQS-ChangeMessageVisibility", s._parentSegment) 2098 2099 if seg != nil { 2100 segCtx = seg.Ctx 2101 segCtxSet = true 2102 2103 defer seg.Close() 2104 defer func() { 2105 _ = seg.Seg.AddMetadata("SQS-ChangeMessageVisibility-QueueURL", queueUrl) 2106 _ = seg.Seg.AddMetadata("SQS-ChangeMessageVisibility-ReceiptHandle", receiptHandle) 2107 _ = seg.Seg.AddMetadata("SQS-ChangeMessageVisibility-VisibilityTimeOutSeconds", visibilityTimeOutSeconds) 2108 2109 if err != nil { 2110 _ = seg.Seg.AddError(err) 2111 } 2112 }() 2113 } 2114 2115 // validate 2116 if s.sqsClient == nil { 2117 err = errors.New("ChangeMessageVisibility Failed: " + "SQS Client is Required") 2118 return err 2119 } 2120 2121 if util.LenTrim(queueUrl) <= 0 { 2122 err = errors.New("ChangeMessageVisibility Failed: " + "Queue Url is Required") 2123 return err 2124 } 2125 2126 if util.LenTrim(receiptHandle) <= 0 { 2127 err = errors.New("ChangeMessageVisibility Failed: " + "Receipt Handle is Required") 2128 return err 2129 } 2130 2131 if visibilityTimeOutSeconds < 0 { 2132 visibilityTimeOutSeconds = 0 2133 } 2134 2135 // create input object 2136 input := &awssqs.ChangeMessageVisibilityInput{ 2137 QueueUrl: aws.String(queueUrl), 2138 ReceiptHandle: aws.String(receiptHandle), 2139 } 2140 2141 if visibilityTimeOutSeconds > 0 { 2142 input.VisibilityTimeout = aws.Int64(visibilityTimeOutSeconds) 2143 } 2144 2145 // perform action 2146 if len(timeOutDuration) > 0 { 2147 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 2148 defer cancel() 2149 2150 _, err = s.sqsClient.ChangeMessageVisibilityWithContext(ctx, input) 2151 } else { 2152 if segCtxSet { 2153 _, err = s.sqsClient.ChangeMessageVisibilityWithContext(segCtx, input) 2154 } else { 2155 _, err = s.sqsClient.ChangeMessageVisibility(input) 2156 } 2157 } 2158 2159 // evaluate result 2160 if err != nil { 2161 err = errors.New("ChangeMessageVisibility Failed: (Change Action) " + err.Error()) 2162 return err 2163 } else { 2164 return nil 2165 } 2166 } 2167 2168 // ChangeMessageVisibilityBatch will update up to 10 messages' visibility time out values in a batch 2169 func (s *SQS) ChangeMessageVisibilityBatch(queueUrl string, 2170 messageEntries []*SQSChangeVisibilityRequest, 2171 timeOutDuration ...time.Duration) (successIDsList []string, failedList []*SQSFailResult, err error) { 2172 segCtx := context.Background() 2173 segCtxSet := false 2174 2175 seg := xray.NewSegmentNullable("SQS-ChangeMessageVisibilityBatch", s._parentSegment) 2176 2177 if seg != nil { 2178 segCtx = seg.Ctx 2179 segCtxSet = true 2180 2181 defer seg.Close() 2182 defer func() { 2183 _ = seg.Seg.AddMetadata("SQS-ChangeMessageVisibilityBatch-QueueURL", queueUrl) 2184 _ = seg.Seg.AddMetadata("SQS-ChangeMessageVisibilityBatch-MessageEntries", messageEntries) 2185 _ = seg.Seg.AddMetadata("SQS-ChangeMessageVisibilityBatch-Result-SuccessIDsList", successIDsList) 2186 _ = seg.Seg.AddMetadata("SQS-ChangeMessageVisibilityBatch-Result-FailedList", failedList) 2187 2188 if err != nil { 2189 _ = seg.Seg.AddError(err) 2190 } 2191 }() 2192 } 2193 2194 // validate 2195 if s.sqsClient == nil { 2196 err = errors.New("ChangeMessageVisibilityBatch Failed: " + "SQS Client is Required") 2197 return nil, nil, err 2198 } 2199 2200 if util.LenTrim(queueUrl) <= 0 { 2201 err = errors.New("ChangeMessageVisibilityBatch Failed: " + "Queue Url is Required") 2202 return nil, nil, err 2203 } 2204 2205 if messageEntries == nil { 2206 err = errors.New("ChangeMessageVisibilityBatch Failed: " + "Message Entries Required (nil)") 2207 return nil, nil, err 2208 } 2209 2210 if len(messageEntries) <= 0 { 2211 err = errors.New("ChangeMessageVisibilityBatch Failed: " + "Message Entries Required (count = 0") 2212 return nil, nil, err 2213 } 2214 2215 if len(messageEntries) > 10 { 2216 err = errors.New("ChangeMessageVisibilityBatch Failed: " + "Message Entries Per Batch Limited to 10") 2217 return nil, nil, err 2218 } 2219 2220 // create input object 2221 var entries []*awssqs.ChangeMessageVisibilityBatchRequestEntry 2222 2223 for _, v := range messageEntries { 2224 if v != nil { 2225 if util.LenTrim(v.Id) > 0 && util.LenTrim(v.ReceiptHandle) > 0 { 2226 timeout := v.VisibilityTimeOutSeconds 2227 2228 if timeout < 0 { 2229 timeout = 0 2230 } 2231 2232 entries = append(entries, &awssqs.ChangeMessageVisibilityBatchRequestEntry{ 2233 Id: aws.String(v.Id), 2234 ReceiptHandle: aws.String(v.ReceiptHandle), 2235 VisibilityTimeout: aws.Int64(timeout), 2236 }) 2237 } 2238 } 2239 } 2240 2241 if len(entries) <= 0 { 2242 err = errors.New("ChangeMessageVisibilityBatch Failed: " + "Message Entries Elements Count Must Not Be Zero") 2243 return nil, nil, err 2244 } 2245 2246 input := &awssqs.ChangeMessageVisibilityBatchInput{ 2247 QueueUrl: aws.String(queueUrl), 2248 Entries: entries, 2249 } 2250 2251 // perform action 2252 var output *awssqs.ChangeMessageVisibilityBatchOutput 2253 2254 if len(timeOutDuration) > 0 { 2255 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 2256 defer cancel() 2257 2258 output, err = s.sqsClient.ChangeMessageVisibilityBatchWithContext(ctx, input) 2259 } else { 2260 if segCtxSet { 2261 output, err = s.sqsClient.ChangeMessageVisibilityBatchWithContext(segCtx, input) 2262 } else { 2263 output, err = s.sqsClient.ChangeMessageVisibilityBatch(input) 2264 } 2265 } 2266 2267 // evaluate result 2268 if err != nil { 2269 err = errors.New("ChangeMessageVisibilityBatch Failed: (Change Action) " + err.Error()) 2270 return nil, nil, err 2271 } else { 2272 if len(output.Successful) > 0 { 2273 for _, v := range output.Successful { 2274 if v != nil { 2275 successIDsList = append(successIDsList, aws.StringValue(v.Id)) 2276 } 2277 } 2278 } 2279 2280 if len(output.Failed) > 0 { 2281 for _, v := range output.Failed { 2282 if v != nil { 2283 failedList = append(failedList, &SQSFailResult{ 2284 Id: aws.StringValue(v.Id), 2285 Code: aws.StringValue(v.Code), 2286 Message: aws.StringValue(v.Message), 2287 SenderFault: aws.BoolValue(v.SenderFault), 2288 }) 2289 } 2290 } 2291 } 2292 2293 return successIDsList, failedList, nil 2294 } 2295 } 2296 2297 // DeleteMessage will delete a message from sqs queue based on receiptHandle and queueUrl specified 2298 func (s *SQS) DeleteMessage(queueUrl string, 2299 receiptHandle string, 2300 timeOutDuration ...time.Duration) (err error) { 2301 segCtx := context.Background() 2302 segCtxSet := false 2303 2304 seg := xray.NewSegmentNullable("SQS-DeleteMessage", s._parentSegment) 2305 2306 if seg != nil { 2307 segCtx = seg.Ctx 2308 segCtxSet = true 2309 2310 defer seg.Close() 2311 defer func() { 2312 _ = seg.Seg.AddMetadata("SQS-DeleteMessage-QueueURL", queueUrl) 2313 _ = seg.Seg.AddMetadata("SQS-DeleteMessage-ReceiptHandle", receiptHandle) 2314 2315 if err != nil { 2316 _ = seg.Seg.AddError(err) 2317 } 2318 }() 2319 } 2320 2321 // validate 2322 if s.sqsClient == nil { 2323 err = errors.New("DeleteMessage Failed: " + "SQS Client is Required") 2324 return err 2325 } 2326 2327 if util.LenTrim(queueUrl) <= 0 { 2328 err = errors.New("DeleteMessage Failed: " + "Queue Url is Required") 2329 return err 2330 } 2331 2332 if util.LenTrim(receiptHandle) <= 0 { 2333 err = errors.New("DeleteMessage Failed: " + "Receipt Handle is Required") 2334 return err 2335 } 2336 2337 // create input object 2338 input := &awssqs.DeleteMessageInput{ 2339 QueueUrl: aws.String(queueUrl), 2340 ReceiptHandle: aws.String(receiptHandle), 2341 } 2342 2343 // perform action 2344 if len(timeOutDuration) > 0 { 2345 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 2346 defer cancel() 2347 2348 _, err = s.sqsClient.DeleteMessageWithContext(ctx, input) 2349 } else { 2350 if segCtxSet { 2351 _, err = s.sqsClient.DeleteMessageWithContext(segCtx, input) 2352 } else { 2353 _, err = s.sqsClient.DeleteMessage(input) 2354 } 2355 } 2356 2357 // evaluate result 2358 if err != nil { 2359 err = errors.New("DeleteMessage Failed: (Delete Action) " + err.Error()) 2360 return err 2361 } else { 2362 return nil 2363 } 2364 } 2365 2366 // DeleteMessageBatch will delete up to 10 messages from given queue by queueUrl and message receiptHandles 2367 func (s *SQS) DeleteMessageBatch(queueUrl string, 2368 messageEntries []*SQSDeleteMessageRequest, 2369 timeOutDuration ...time.Duration) (successIDsList []string, failedList []*SQSFailResult, err error) { 2370 segCtx := context.Background() 2371 segCtxSet := false 2372 2373 seg := xray.NewSegmentNullable("SQS-DeleteMessageBatch", s._parentSegment) 2374 2375 if seg != nil { 2376 segCtx = seg.Ctx 2377 segCtxSet = true 2378 2379 defer seg.Close() 2380 defer func() { 2381 _ = seg.Seg.AddMetadata("SQS-DeleteMessageBatch-QueueURL", queueUrl) 2382 _ = seg.Seg.AddMetadata("SQS-DeleteMessageBatch-MessageEntries", messageEntries) 2383 _ = seg.Seg.AddMetadata("SQS-DeleteMessageBatch-Result-SuccessIDsList", successIDsList) 2384 _ = seg.Seg.AddMetadata("SQS-DeleteMessageBatch-Result-FailedList", failedList) 2385 2386 if err != nil { 2387 _ = seg.Seg.AddError(err) 2388 } 2389 }() 2390 } 2391 2392 // validate 2393 if s.sqsClient == nil { 2394 err = errors.New("DeleteMessageBatch Failed: " + "SQS Client is Required") 2395 return nil, nil, err 2396 } 2397 2398 if util.LenTrim(queueUrl) <= 0 { 2399 err = errors.New("DeleteMessageBatch Failed: " + "Queue Url is Required") 2400 return nil, nil, err 2401 } 2402 2403 if messageEntries == nil { 2404 err = errors.New("DeleteMessageBatch Failed: " + "Message Entries Required (nil)") 2405 return nil, nil, err 2406 } 2407 2408 if len(messageEntries) <= 0 { 2409 err = errors.New("DeleteMessageBatch Failed: " + "Message Entries Required (count = 0)") 2410 return nil, nil, err 2411 } 2412 2413 if len(messageEntries) > 10 { 2414 err = errors.New("DeleteMessageBatch Failed: " + "Message Entries Per Batch Limited to 10") 2415 return nil, nil, err 2416 } 2417 2418 // create input object 2419 var entries []*awssqs.DeleteMessageBatchRequestEntry 2420 2421 for _, v := range messageEntries { 2422 if v != nil { 2423 if util.LenTrim(v.Id) > 0 && util.LenTrim(v.ReceiptHandle) > 0 { 2424 entries = append(entries, &awssqs.DeleteMessageBatchRequestEntry{ 2425 Id: aws.String(v.Id), 2426 ReceiptHandle: aws.String(v.ReceiptHandle), 2427 }) 2428 } 2429 } 2430 } 2431 2432 if len(entries) <= 0 { 2433 err = errors.New("DeleteMessagseBatch Failed: " + "Message Entries Elements Must Not Be Zero") 2434 return nil, nil, err 2435 } 2436 2437 input := &awssqs.DeleteMessageBatchInput{ 2438 QueueUrl: aws.String(queueUrl), 2439 Entries: entries, 2440 } 2441 2442 // perform action 2443 var output *awssqs.DeleteMessageBatchOutput 2444 2445 if len(timeOutDuration) > 0 { 2446 ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0]) 2447 defer cancel() 2448 2449 output, err = s.sqsClient.DeleteMessageBatchWithContext(ctx, input) 2450 } else { 2451 if segCtxSet { 2452 output, err = s.sqsClient.DeleteMessageBatchWithContext(segCtx, input) 2453 } else { 2454 output, err = s.sqsClient.DeleteMessageBatch(input) 2455 } 2456 } 2457 2458 // evaluate result 2459 if err != nil { 2460 err = errors.New("DeleteMessageBatch Failed: (Delete Action) " + err.Error()) 2461 return nil, nil, err 2462 } else { 2463 if len(output.Successful) > 0 { 2464 for _, v := range output.Successful { 2465 if v != nil { 2466 successIDsList = append(successIDsList, aws.StringValue(v.Id)) 2467 } 2468 } 2469 } 2470 2471 if len(output.Failed) > 0 { 2472 for _, v := range output.Failed { 2473 if v != nil { 2474 failedList = append(failedList, &SQSFailResult{ 2475 Id: aws.StringValue(v.Id), 2476 Code: aws.StringValue(v.Code), 2477 Message: aws.StringValue(v.Message), 2478 SenderFault: aws.BoolValue(v.SenderFault), 2479 }) 2480 } 2481 } 2482 } 2483 2484 return successIDsList, failedList, nil 2485 } 2486 }