-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtemplate.yml
More file actions
522 lines (490 loc) · 14.9 KB
/
Copy pathtemplate.yml
File metadata and controls
522 lines (490 loc) · 14.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Asynchronous Chromium PDF generation with API Gateway, SQS, DynamoDB, and S3
Parameters:
AppBucketName:
Type: String
Description: "REQUIRED: Unique S3 bucket name to use for PDF inputs and outputs."
WorkerMemorySize:
Type: Number
Default: 3072
AllowedValues: [ 2048, 3072, 4096 ]
Description: Memory allocated to the PDF worker for tuning benchmarks.
WorkerReservedConcurrency:
Type: Number
Default: 2
MinValue: 2
Description: Maximum number of image-heavy PDFs rendered concurrently.
Resources:
ApiGateway:
Type: AWS::Serverless::Api
Properties:
Name: ChromiumPDFApi
StageName: prod
Auth:
ApiKeyRequired: true
ApiKey:
Type: AWS::ApiGateway::ApiKey
Properties:
Enabled: true
Name: MyApiKey
StageKeys:
- RestApiId: !Ref ApiGateway
StageName: prod
UsagePlan:
Type: AWS::ApiGateway::UsagePlan
Properties:
UsagePlanName: MyUsagePlan
ApiStages:
- ApiId: !Ref ApiGateway
Stage: prod
Throttle:
BurstLimit: 100
RateLimit: 50
Quota:
Limit: 10000
Period: MONTH
UsagePlanKey:
Type: AWS::ApiGateway::UsagePlanKey
Properties:
KeyId: !Ref ApiKey
KeyType: API_KEY
UsagePlanId: !Ref UsagePlan
ChromiumLayer:
Type: AWS::Serverless::LayerVersion
Properties:
Description: Chromium 149 for Node.js 24 Lambda functions
ContentUri: layers/chromium
CompatibleRuntimes:
- &nodejsRuntime nodejs24.x
CompatibleArchitectures:
- &chromiumArch x86_64
RetentionPolicy: Delete
Metadata:
BuildMethod: *nodejsRuntime
BuildArchitecture: *chromiumArch
AppBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref AppBucketName
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
LifecycleConfiguration:
Rules:
- Id: DeleteAfter24Hours
Status: Enabled
ExpirationInDays: 1
PdfJobsTable:
Type: AWS::DynamoDB::Table
Properties:
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: jobId
AttributeType: S
KeySchema:
- AttributeName: jobId
KeyType: HASH
SSESpecification:
SSEEnabled: true
TimeToLiveSpecification:
AttributeName: ttl
Enabled: true
PdfDeadLetterQueue:
Type: AWS::SQS::Queue
Properties:
MessageRetentionPeriod: 1209600
VisibilityTimeout: 1800
SqsManagedSseEnabled: true
PdfQueue:
Type: AWS::SQS::Queue
Properties:
ReceiveMessageWaitTimeSeconds: 20
VisibilityTimeout: 1800
SqsManagedSseEnabled: true
RedrivePolicy:
deadLetterTargetArn: !GetAtt PdfDeadLetterQueue.Arn
maxReceiveCount: 3
SynchronousFunctionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument: &lambdaTrustPolicy
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: SynchronousPdfStorage
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: [ s3:PutObject, s3:GetObject ]
Resource: !Sub "arn:aws:s3:::${AppBucketName}/*"
SubmitFunctionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument: *lambdaTrustPolicy
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: SubmitPdfJob
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: [ s3:PutObject, s3:DeleteObject ]
Resource: !Sub "arn:aws:s3:::${AppBucketName}/jobs/*"
- Effect: Allow
Action:
- dynamodb:PutItem
- dynamodb:GetItem
- dynamodb:DeleteItem
- dynamodb:TransactWriteItems
Resource: !GetAtt PdfJobsTable.Arn
- Effect: Allow
Action: sqs:SendMessage
Resource: !GetAtt PdfQueue.Arn
StatusFunctionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument: *lambdaTrustPolicy
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: ReadPdfJob
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: dynamodb:GetItem
Resource: !GetAtt PdfJobsTable.Arn
- Effect: Allow
Action: s3:GetObject
Resource: !Sub "arn:aws:s3:::${AppBucketName}/jobs/*"
WorkerFunctionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument: *lambdaTrustPolicy
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: ProcessPdfJob
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: [ s3:GetObject, s3:PutObject ]
Resource: !Sub "arn:aws:s3:::${AppBucketName}/jobs/*"
- Effect: Allow
Action: [ dynamodb:GetItem, dynamodb:UpdateItem ]
Resource: !GetAtt PdfJobsTable.Arn
- Effect: Allow
Action:
- sqs:ReceiveMessage
- sqs:DeleteMessage
- sqs:GetQueueAttributes
- sqs:ChangeMessageVisibility
Resource: !GetAtt PdfQueue.Arn
DlqFunctionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument: *lambdaTrustPolicy
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: FinalizeFailedPdfJob
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: dynamodb:UpdateItem
Resource: !GetAtt PdfJobsTable.Arn
- Effect: Allow
Action:
- sqs:ReceiveMessage
- sqs:DeleteMessage
- sqs:GetQueueAttributes
Resource: !GetAtt PdfDeadLetterQueue.Arn
GeneratePdfFromHtml:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
CodeUri: functions/html
Description: Deprecated synchronous HTML-to-PDF endpoint
Runtime: *nodejsRuntime
Architectures: [ *chromiumArch ]
Layers: [ !Ref ChromiumLayer ]
Timeout: 28
MemorySize: 2048
Role: !GetAtt SynchronousFunctionRole.Arn
Events:
Api:
Type: Api
Properties:
RestApiId: !Ref ApiGateway
Path: /pdf/html
Method: POST
Environment:
Variables:
BUCKET_NAME: !Ref AppBucketName
REGION: !Ref AWS::Region
Metadata:
BuildMethod: nodejs24.x
SubmitPdfJob:
Type: AWS::Serverless::Function
Properties:
Handler: submit.handler
CodeUri: functions/html
Description: Validate and queue asynchronous PDF jobs
Runtime: *nodejsRuntime
Architectures: [ *chromiumArch ]
Timeout: 10
MemorySize: 512
Role: !GetAtt SubmitFunctionRole.Arn
Events:
Api:
Type: Api
Properties:
RestApiId: !Ref ApiGateway
Path: /pdf/jobs
Method: POST
Environment:
Variables:
BUCKET_NAME: !Ref AppBucketName
JOBS_TABLE: !Ref PdfJobsTable
QUEUE_URL: !Ref PdfQueue
REGION: !Ref AWS::Region
Metadata:
BuildMethod: nodejs24.x
GetPdfJob:
Type: AWS::Serverless::Function
Properties:
Handler: status.handler
CodeUri: functions/html
Description: Return asynchronous PDF job status and download URL
Runtime: *nodejsRuntime
Architectures: [ *chromiumArch ]
Timeout: 10
MemorySize: 512
Role: !GetAtt StatusFunctionRole.Arn
Events:
Api:
Type: Api
Properties:
RestApiId: !Ref ApiGateway
Path: /pdf/jobs/{jobId}
Method: GET
Environment:
Variables:
BUCKET_NAME: !Ref AppBucketName
JOBS_TABLE: !Ref PdfJobsTable
REGION: !Ref AWS::Region
Metadata:
BuildMethod: nodejs24.x
PdfWorker:
Type: AWS::Serverless::Function
Properties:
Handler: worker.handler
CodeUri: functions/html
Description: Render queued PDFs with Chromium
Runtime: *nodejsRuntime
Architectures: [ *chromiumArch ]
Layers: [ !Ref ChromiumLayer ]
Timeout: 300
MemorySize: !Ref WorkerMemorySize
EphemeralStorage:
Size: 1024
ReservedConcurrentExecutions: !Ref WorkerReservedConcurrency
Role: !GetAtt WorkerFunctionRole.Arn
Events:
Queue:
Type: SQS
Properties:
Queue: !GetAtt PdfQueue.Arn
BatchSize: 1
FunctionResponseTypes: [ ReportBatchItemFailures ]
ScalingConfig:
MaximumConcurrency: !Ref WorkerReservedConcurrency
Environment:
Variables:
BUCKET_NAME: !Ref AppBucketName
JOBS_TABLE: !Ref PdfJobsTable
QUEUE_URL: !Ref PdfQueue
REGION: !Ref AWS::Region
Metadata:
BuildMethod: nodejs24.x
PdfDlqHandler:
Type: AWS::Serverless::Function
Properties:
Handler: dlq.handler
CodeUri: functions/html
Description: Mark exhausted PDF jobs as permanently failed
Runtime: *nodejsRuntime
Architectures: [ *chromiumArch ]
Timeout: 10
MemorySize: 512
Role: !GetAtt DlqFunctionRole.Arn
Events:
Queue:
Type: SQS
Properties:
Queue: !GetAtt PdfDeadLetterQueue.Arn
BatchSize: 1
FunctionResponseTypes: [ ReportBatchItemFailures ]
Environment:
Variables:
JOBS_TABLE: !Ref PdfJobsTable
REGION: !Ref AWS::Region
Metadata:
BuildMethod: nodejs24.x
GeneratePdfFromHtmlLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/lambda/${GeneratePdfFromHtml}
RetentionInDays: 7
SubmitPdfJobLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/lambda/${SubmitPdfJob}
RetentionInDays: 7
GetPdfJobLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/lambda/${GetPdfJob}
RetentionInDays: 7
PdfWorkerLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/lambda/${PdfWorker}
RetentionInDays: 7
PdfDlqHandlerLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/lambda/${PdfDlqHandler}
RetentionInDays: 7
QueueAgeAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmDescription: Oldest queued PDF job has waited more than five minutes
Namespace: AWS/SQS
MetricName: ApproximateAgeOfOldestMessage
Dimensions:
- Name: QueueName
Value: !GetAtt PdfQueue.QueueName
Statistic: Maximum
Period: 60
EvaluationPeriods: 1
Threshold: 300
ComparisonOperator: GreaterThanThreshold
TreatMissingData: notBreaching
WorkerErrorAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmDescription: PDF worker returned an invocation error
Namespace: AWS/Lambda
MetricName: Errors
Dimensions:
- Name: FunctionName
Value: !Ref PdfWorker
Statistic: Sum
Period: 60
EvaluationPeriods: 1
Threshold: 0
ComparisonOperator: GreaterThanThreshold
TreatMissingData: notBreaching
WorkerAttemptFailureAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmDescription: A PDF worker attempt failed and was returned to SQS
Namespace: ChromiumPdf
MetricName: JobsRetried
Dimensions:
- Name: Service
Value: PdfWorker
Statistic: Sum
Period: 60
EvaluationPeriods: 1
Threshold: 0
ComparisonOperator: GreaterThanThreshold
TreatMissingData: notBreaching
WorkerThrottleAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmDescription: PDF worker was throttled
Namespace: AWS/Lambda
MetricName: Throttles
Dimensions:
- Name: FunctionName
Value: !Ref PdfWorker
Statistic: Sum
Period: 60
EvaluationPeriods: 1
Threshold: 0
ComparisonOperator: GreaterThanThreshold
TreatMissingData: notBreaching
WorkerDurationAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmDescription: PDF worker p95 duration exceeded four minutes
Namespace: AWS/Lambda
MetricName: Duration
Dimensions:
- Name: FunctionName
Value: !Ref PdfWorker
ExtendedStatistic: p95
Period: 300
EvaluationPeriods: 1
Threshold: 240000
ComparisonOperator: GreaterThanThreshold
TreatMissingData: notBreaching
PermanentFailureAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmDescription: A PDF job exhausted all retry attempts
Namespace: ChromiumPdf
MetricName: PermanentFailures
Dimensions:
- Name: Service
Value: PdfDlq
Statistic: Sum
Period: 60
EvaluationPeriods: 1
Threshold: 0
ComparisonOperator: GreaterThanThreshold
TreatMissingData: notBreaching
Outputs:
ApiUrl:
Description: Base URL for the API
Value: !Sub "https://${ApiGateway}.execute-api.${AWS::Region}.amazonaws.com/prod"
SubmitJobUrl:
Description: Asynchronous PDF submission endpoint
Value: !Sub "https://${ApiGateway}.execute-api.${AWS::Region}.amazonaws.com/prod/pdf/jobs"
BucketName:
Description: PDF input and output bucket
Value: !Ref AppBucketName
JobsTableName:
Description: DynamoDB PDF jobs table
Value: !Ref PdfJobsTable
QueueUrl:
Description: SQS PDF work queue URL
Value: !Ref PdfQueue
DeadLetterQueueUrl:
Description: SQS dead-letter queue URL
Value: !Ref PdfDeadLetterQueue
SynchronousFunctionName:
Description: Deprecated synchronous Lambda function
Value: !Ref GeneratePdfFromHtml
WorkerFunctionName:
Description: Asynchronous PDF worker Lambda function
Value: !Ref PdfWorker