cfn.yaml (180 lines of code) (raw):
Transform: AWS::Serverless-2016-10-31
Description: Source code in https://github.com/guardian/payment-failure-comms
Parameters:
Stage:
Description: Stage name
Type: String
AllowedValues:
- PROD
- CODE
- DEV
Default: DEV
AppName:
Type: String
Default: payment-failure-comms
Conditions:
IsProd: !Equals [ !Ref Stage, PROD ]
Mappings:
StageMap:
PROD:
Schedule: 'rate(20 minutes)'
SalesforceStage: PROD
SalesforceUserName: pfCommsAPIUser
SalesforceAppName: PfComms
IdapiInstanceUrl: idapi.theguardian.com
IdapiStage: PROD
BrazeInstanceUrl: rest.fra-01.braze.eu
BrazeAppGroup: LIVE
CODE:
Schedule: 'rate(365 days)'
SalesforceStage: UAT
SalesforceUserName: pfCommsAPIUser
SalesforceAppName: AwsConnectorSandbox
IdapiInstanceUrl: idapi.code.dev-theguardian.com
IdapiStage: CODE
BrazeInstanceUrl: rest.fra-01.braze.eu
BrazeAppGroup: DEV
DEV:
Schedule: 'rate(365 days)'
SalesforceStage: DEV
SalesforceUserName: pfCommsAPIUser
SalesforceAppName: AwsConnectorSandbox
IdapiInstanceUrl: idapi.code.dev-theguardian.com
IdapiStage: CODE
BrazeInstanceUrl: rest.fra-01.braze.eu
BrazeAppGroup: DEV
Resources:
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/lambda/${AppName}-${Stage}
RetentionInDays: 90
PaymentFailureCommsLambda:
Type: AWS::Serverless::Function
DependsOn: LogGroup
Properties:
FunctionName: !Sub ${AppName}-${Stage}
Handler: payment_failure_comms.Handler::handleRequest
Runtime: java8.al2
CodeUri:
Bucket: membership-dist
Key: !Sub membership/${Stage}/${AppName}/${AppName}.jar
Timeout: 120
MemorySize: 256
Environment:
Variables:
stage: !Ref Stage
salesforceApiVersion: v46.0
salesforceInstanceUrl:
!Sub
- '{{resolve:secretsmanager:${SalesforceStage}/Salesforce/ConnectedApp/${SalesforceAppName}:SecretString:authUrl}}'
- SalesforceStage: !FindInMap [ StageMap, !Ref Stage, SalesforceStage ]
SalesforceAppName: !FindInMap [ StageMap, !Ref Stage, SalesforceAppName ]
salesforceClientId:
!Sub
- '{{resolve:secretsmanager:${SalesforceStage}/Salesforce/ConnectedApp/${SalesforceAppName}:SecretString:clientId}}'
- SalesforceStage: !FindInMap [ StageMap, !Ref Stage, SalesforceStage ]
SalesforceAppName: !FindInMap [ StageMap, !Ref Stage, SalesforceAppName ]
salesforceClientSecret:
!Sub
- '{{resolve:secretsmanager:${SalesforceStage}/Salesforce/ConnectedApp/${SalesforceAppName}:SecretString:clientSecret}}'
- SalesforceStage: !FindInMap [ StageMap, !Ref Stage, SalesforceStage ]
SalesforceAppName: !FindInMap [ StageMap, !Ref Stage, SalesforceAppName ]
salesforceUserName:
!Sub
- '{{resolve:secretsmanager:${SalesforceStage}/Salesforce/User/${SalesforceUserName}:SecretString:userName}}'
- SalesforceStage: !FindInMap [ StageMap, !Ref Stage, SalesforceStage ]
SalesforceUserName: !FindInMap [ StageMap, !Ref Stage, SalesforceUserName ]
salesforcePassword:
!Sub
- '{{resolve:secretsmanager:${SalesforceStage}/Salesforce/User/${SalesforceUserName}:SecretString:password}}'
- SalesforceStage: !FindInMap [ StageMap, !Ref Stage, SalesforceStage ]
SalesforceUserName: !FindInMap [ StageMap, !Ref Stage, SalesforceUserName ]
salesforceToken:
!Sub
- '{{resolve:secretsmanager:${SalesforceStage}/Salesforce/User/${SalesforceUserName}:SecretString:token}}'
- SalesforceStage: !FindInMap [ StageMap, !Ref Stage, SalesforceStage ]
SalesforceUserName: !FindInMap [ StageMap, !Ref Stage, SalesforceUserName ]
idapiInstanceUrl: !FindInMap [ StageMap, !Ref Stage, IdapiInstanceUrl ]
idapiBearerToken: !Sub
- '{{resolve:secretsmanager:${IdapiStage}/Identity/${AppName}:SecretString:bearerToken}}'
- IdapiStage: !FindInMap [ StageMap, !Ref Stage, IdapiStage ]
brazeInstanceUrl: !FindInMap [ StageMap, !Ref Stage, BrazeInstanceUrl ]
brazeApiKey:
!Sub
- '{{resolve:secretsmanager:${BrazeAppGroup}/Braze/${AppName}:SecretString:apiKey}}'
- BrazeAppGroup: !FindInMap [ StageMap, !Ref Stage, BrazeAppGroup ]
appIdForBraze:
!Sub
- '{{resolve:secretsmanager:${BrazeAppGroup}/Braze/${AppName}:SecretString:appId}}'
- BrazeAppGroup: !FindInMap [ StageMap, !Ref Stage, BrazeAppGroup ]
Events:
ScheduledRun:
Type: Schedule
Properties:
Description: Send payment failure communications
Schedule: !FindInMap [ StageMap, !Ref Stage, Schedule ]
RetryPolicy:
# As process runs every 20 mins anyway, there's no point in retrying on failure
MaximumRetryAttempts: 0
Enabled: True
Policies:
- Statement:
- Effect: Allow
Action: cloudwatch:PutMetricData
Resource: "*"
EventInvokeConfig:
MaximumRetryAttempts: 0
FailureAlarm:
Type: AWS::CloudWatch::Alarm
Condition: IsProd
DependsOn: PaymentFailureCommsLambda
Properties:
AlarmName: "payment-failure-comms record syncing job is consistently failing to complete"
AlarmDescription: >
IMPACT: Until the job is repaired, new payment-failure events will not be communicated to customers.
For resolution steps, see https://github.com/guardian/payment-failure-comms/blob/main/README.md#alarms.
AlarmActions:
- !Sub arn:aws:sns:${AWS::Region}:${AWS::AccountId}:alarms-handler-topic-PROD
Metrics:
- Id: errors
Expression: "FILL(m1,0)"
Label: ErrorsCount
- Id: m1
ReturnData: false
MetricStat:
Metric:
MetricName: Errors
Namespace: AWS/Lambda
Dimensions:
- Name: FunctionName
Value: !Ref PaymentFailureCommsLambda
Stat: Sum
Period: 60
Unit: Count
ComparisonOperator: GreaterThanOrEqualToThreshold
Threshold: 1
EvaluationPeriods: 90
DatapointsToAlarm: 5
TreatMissingData: ignore
FailureLimitReachedAlarm:
Type: AWS::CloudWatch::Alarm
Condition: IsProd
DependsOn: PaymentFailureCommsLambda
Properties:
AlarmName: "Action required - payment-failure-comms: failure limit reached for some records"
AlarmDescription: >
IMPACT: At least one payment-failure event will not be communicated to the customer.
For resolution steps, see https://github.com/guardian/payment-failure-comms/blob/main/README.md#alarms.
AlarmActions:
- !Sub arn:aws:sns:${AWS::Region}:${AWS::AccountId}:alarms-handler-topic-PROD
MetricName: failure-limit-reached
Namespace: payment-failure-comms
Dimensions:
- Name: Stage
Value: !Ref Stage
ComparisonOperator: GreaterThanOrEqualToThreshold
Threshold: 5
Statistic: Sum
Period: 3600
EvaluationPeriods: 1
TreatMissingData: notBreaching