# Amazon Pinpoint & SES message sending queuing
#
# **DO NOT DELETE**
#
# author: pavlosik@
---
AWSTemplateFormatVersion: 2010-09-09
Description: SES - Pinpoint messages queuing

Parameters:

  SQSBatchSize:
    Type: Number
    Description: Provide the SQS batch-size
  ReservedLambdaConcurrency:
    Type: Number
    Description: Set the AWS Lambda poller function reserved concurrency
  Emailthroughput:
    Type: Number
    Description: Your email throughput e.g. 100 emails per second
  DashboardName:
    Type: String
    Description: Name for the CloudWatch dashboard
  EmailFrom:
    Type: String
    Description: The email address you will send from for testing purposes
  NoOfMessagesSQS:
    Type: String
    Description: How many messages will you write to SQS (for demo purposes)
  LambdaCodeS3BucketName:
    Type: String
    Description: Type the S3 bucket name with the Lambda code

Resources:

  ##### SQS Queues
  #######################################
  MessagesQueue:
    Type: AWS::SQS::Queue
    Properties:
      VisibilityTimeout: 500
      KmsMasterKeyId: alias/aws/sqs
      RedrivePolicy:
        deadLetterTargetArn: !GetAtt MessagesDeadLetterQueue.Arn
        maxReceiveCount: 3

  MessagesDeadLetterQueue:
    Type: AWS::SQS::Queue
    Properties:
      KmsMasterKeyId: alias/aws/sqs

  ##### Lambda Functions
  #######################################
  PublisherLambda:
    Type: AWS::Lambda::Function
    Properties:
      Role: !GetAtt PublisherLambdaRole.Arn
      Timeout: 60
      Environment:
        Variables:
          SQS_QUEUE_URL: !Ref MessagesQueue
          NO_OF_MESSAGES: !Ref NoOfMessagesSQS
          EMAIL_FROM: !Ref EmailFrom
      Handler: lambda_function.lambda_handler
      Runtime: python3.9
      Code:
        S3Bucket: !Ref LambdaCodeS3BucketName
        S3Key: "sqs_message_publisher.zip"

  PublisherLambdaRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - "sts:AssumeRole"
      Path: "/"
      Policies:
        -
          PolicyName: "root"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              -
                Effect: Allow
                Action: sqs:SendMessage
                Resource: !GetAtt MessagesQueue.Arn
              -
                Effect: "Allow"
                Action:
                  - "logs:CreateLogGroup"
                  - "logs:CreateLogStream"
                  - "logs:PutLogEvents"
                Resource: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:*"

  CloudWatchInvokeLambda:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !GetAtt PublisherLambda.Arn
      Principal: events.amazonaws.com
      SourceArn: !GetAtt EventBridgeRulePublishSQS.Arn

  PollerLambda:
    Type: AWS::Lambda::Function
    Properties:
      Role: !GetAtt PollerLambdaRole.Arn
      Timeout: 300
      Environment:
        Variables:
          SQS_QUEUE_URL: !Ref MessagesQueue
          SQS_DLQ_QUEUE_URL: !Ref MessagesDeadLetterQueue
      Handler: lambda_function.lambda_handler
      Runtime: python3.9
      ReservedConcurrentExecutions: !Ref ReservedLambdaConcurrency
      Code:
        S3Bucket: !Ref LambdaCodeS3BucketName
        S3Key: "sqs_message_poller.zip"

  PollerLambdaEventMapping:
    Type: AWS::Lambda::EventSourceMapping
    Properties:
      BatchSize: !Ref SQSBatchSize
      MaximumBatchingWindowInSeconds: 1
      Enabled: True
      EventSourceArn: !GetAtt MessagesQueue.Arn
      FunctionName: !Ref PollerLambda

  PollerLambdaRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - "sts:AssumeRole"
      Path: "/"
      Policies:
        -
          PolicyName: "root"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              -
                Effect: Allow
                Action:
                  - "mobiletargeting:SendMessages"
                Resource: !Sub arn:aws:mobiletargeting:${AWS::Region}:${AWS::AccountId}:*
              -
                Effect: Allow
                Action:
                  - "ses:SendEmail"
                  - "ses:SendBulkEmail"
                Resource: !Sub arn:aws:ses:${AWS::Region}:${AWS::AccountId}:*
              -
                Effect: Allow
                Action:
                  - "sqs:SendMessage"
                  - "sqs:ReceiveMessage"
                  - "sqs:DeleteMessage"
                  - "sqs:GetQueueAttributes"
                Resource: !GetAtt MessagesQueue.Arn
              -
                Effect: Allow
                Action:
                  - "sqs:SendMessage"
                Resource: !GetAtt MessagesDeadLetterQueue.Arn
              -
                Effect: "Allow"
                Action:
                  - "logs:CreateLogGroup"
                  - "logs:CreateLogStream"
                  - "logs:PutLogEvents"
                Resource: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:*"
              -
                Effect: "Allow"
                Action:
                  - "cloudwatch:PutMetricData"
                Resource: "*"


  ##### CloudWatch dashboard
  #######################################

  SESCloudwatchDashboard:
    Type: AWS::CloudWatch::Dashboard
    Properties: 
      DashboardName: !Ref DashboardName
      DashboardBody:
        !Sub |
          {
              "widgets": [
                  {
                      "height": 9,
                      "width": 24,
                      "y": 0,
                      "x": 0,
                      "type": "metric",
                      "properties": {
                          "metrics": [
                              [ "AWS/SES", "Send" ],
                              [ ".", "Delivery" ],
                              [ "AWS/Lambda", "Invocations", "FunctionName", "${PollerLambda}", { "label": "Lambda Invocations", "yAxis": "right" } ],
                              [ "ses_custom_metrics", "no_SQSmessages_processed", { "label": "Lambda No SQS messages processed" } ],
                              [ ".", "ses_throttling", { "yAxis": "left", "label": "SES_throttling" } ],
                              [ "AWS/SQS", "NumberOfMessagesSent", "QueueName", "${MessagesQueue.QueueName}", { "label": "SQS number of messages sent" } ]
                          ],
                          "view": "timeSeries",
                          "stacked": false,
                          "region": "${AWS::Region}",
                          "stat": "Sum",
                          "period": 1,
                          "title": "Email Queuing Monitoring",
                          "yAxis": {
                              "right": {
                                  "max": 20
                              }
                          }
                      }
                  },
                  {
                      "height": 6,
                      "width": 6,
                      "y": 9,
                      "x": 0,
                      "type": "metric",
                      "properties": {
                          "metrics": [
                              [ "AWS/SES", "Delivery"]
                          ],
                          "view": "gauge",
                          "region": "${AWS::Region}",
                          "stat": "Average",
                          "period": 10,
                          "yAxis": {
                              "left": {
                                  "min": 0,
                                  "max": ${Emailthroughput}
                              }
                          },
                          "title": "Email-Throughput"
                      }
                  },
                  {
                      "height": 6,
                      "width": 6,
                      "y": 9,
                      "x": 6,
                      "type": "metric",
                      "properties": {
                          "view": "timeSeries",
                          "stacked": true,
                          "metrics": [
                              [ "AWS/SQS", "ApproximateNumberOfMessagesVisible", "QueueName", "${MessagesQueue.QueueName}" ]
                          ],
                          "region": "${AWS::Region}",
                          "period": 10,
                          "title": "SQS-NumberOfMessagesVisible"
                      }
                  },
                  {
                      "height": 6,
                      "width": 6,
                      "y": 9,
                      "x": 12,
                      "type": "metric",
                      "properties": {
                          "metrics": [
                              [ "ses_custom_metrics", "message_sent_ms" ],
                              [ "AWS/Lambda", "Duration", "FunctionName", "${PollerLambda}", { "yAxis": "right", "label": "Lambda poller duration" } ]
                          ],
                          "view": "timeSeries",
                          "stacked": false,
                          "region": "${AWS::Region}",
                          "stat": "Average",
                          "period": 10,
                          "title": "Lambda duration & SES API duration"
                      }
                  },
                  {
                      "height": 6,
                      "width": 6,
                      "y": 9,
                      "x": 18,
                      "type": "metric",
                      "properties": {
                          "view": "timeSeries",
                          "stacked": false,
                          "metrics": [
                              [ "AWS/Lambda", "ConcurrentExecutions", "FunctionName", "${PollerLambda}" ],
                              [ ".", "Errors", ".", ".", { "stat": "Sum", "yAxis": "right" } ]
                          ],
                          "region": "${AWS::Region}",
                          "period": 10,
                          "title": "Lambda - Poller metrics"
                      }
                  }
              ]
          }

#### EVENT BRIDGE RULE FOR PUBLISHER LAMBDA
##################################

  EventBridgeRulePublishSQS:
    Type: AWS::Events::Rule
    Properties:
      Name: "TriggerSQSPublishMessagesLambda"
      Description: "Invokes publisher AWS Lambda function, which writes dummy test messages to SQS"
      State: "DISABLED"
      ScheduleExpression: "rate(1 minute)"
      Targets:
        - 
          Arn: !GetAtt PublisherLambda.Arn
          Id: EventBridgeRulePublishSQS