Skip to content

Commit b76d122

Browse files
authored
feat: invalidate cloudfront caches when lambda configuration changes (#63)
*Issue #, if available:* *Description of changes:* When next.js contains a static page, changes to the page will not be reflected due to cloudfront cache. This PR adds invalidation of old cache when Lambda configuration changes By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
1 parent f832eb8 commit b76d122

3 files changed

Lines changed: 237 additions & 2 deletions

File tree

cdk/lib/constructs/cf-lambda-furl-service/service.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Construct } from 'constructs';
22
import { Duration } from 'aws-cdk-lib';
3-
import { FunctionUrlAuthType, IFunction, InvokeMode } from 'aws-cdk-lib/aws-lambda';
3+
import { FunctionUrlAuthType, Function, InvokeMode } from 'aws-cdk-lib/aws-lambda';
44
import {
55
AllowedMethods,
66
CacheCookieBehavior,
@@ -19,13 +19,14 @@ import { CloudFrontTarget } from 'aws-cdk-lib/aws-route53-targets';
1919
import { ICertificate } from 'aws-cdk-lib/aws-certificatemanager';
2020
import { Bucket } from 'aws-cdk-lib/aws-s3';
2121
import { EdgeFunction } from './edge-function';
22+
import { AwsCustomResource, PhysicalResourceId, AwsCustomResourcePolicy } from 'aws-cdk-lib/custom-resources';
2223

2324
export interface CloudFrontLambdaFunctionUrlServiceProps {
2425
/**
2526
* @default use root domain
2627
*/
2728
subDomain?: string;
28-
handler: IFunction;
29+
handler: Function;
2930

3031
/**
3132
* This should be unique across the app
@@ -117,6 +118,28 @@ export class CloudFrontLambdaFunctionUrlService extends Construct {
117118
domainName = distribution.domainName;
118119
}
119120

121+
// Invalidate CloudFront when Lambda function version changes
122+
new AwsCustomResource(this, 'CloudFrontInvalidation', {
123+
onUpdate: {
124+
service: 'cloudfront',
125+
action: 'createInvalidation',
126+
parameters: {
127+
DistributionId: distribution.distributionId,
128+
InvalidationBatch: {
129+
CallerReference: `${handler.currentVersion.version}`,
130+
Paths: {
131+
Quantity: 1,
132+
Items: ['/*'],
133+
},
134+
},
135+
},
136+
physicalResourceId: PhysicalResourceId.of('invalidation'),
137+
},
138+
policy: AwsCustomResourcePolicy.fromSdkCalls({
139+
resources: [distribution.distributionArn],
140+
}),
141+
});
142+
120143
this.url = `https://${domainName}`;
121144
this.domainName = domainName;
122145
}

cdk/test/__snapshots__/serverless-fullstack-webapp-starter-kit-without-domain.test.ts.snap

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3193,6 +3193,96 @@ sudo service iptables save",
31933193
"Type": "AWS::ECR::Repository",
31943194
"UpdateReplacePolicy": "Delete",
31953195
},
3196+
"WebappCloudFrontInvalidation588CF152": Object {
3197+
"DeletionPolicy": "Delete",
3198+
"DependsOn": Array [
3199+
"WebappCloudFrontInvalidationCustomResourcePolicy18C215D6",
3200+
],
3201+
"Properties": Object {
3202+
"Create": Object {
3203+
"Fn::Join": Array [
3204+
"",
3205+
Array [
3206+
"{"service":"cloudfront","action":"createInvalidation","parameters":{"DistributionId":"",
3207+
Object {
3208+
"Ref": "Webapp107041BD",
3209+
},
3210+
"","InvalidationBatch":{"CallerReference":"",
3211+
Object {
3212+
"Fn::GetAtt": Array [
3213+
"WebappHandlerCurrentVersionREDACTED",
3214+
"Version",
3215+
],
3216+
},
3217+
"","Paths":{"Quantity":1,"Items":["/*"]}}},"physicalResourceId":{"id":"invalidation"}}",
3218+
],
3219+
],
3220+
},
3221+
"InstallLatestAwsSdk": true,
3222+
"ServiceToken": Object {
3223+
"Fn::GetAtt": Array [
3224+
"AWS679f53fac002430cb0da5b7982bd22872D164C4C",
3225+
"Arn",
3226+
],
3227+
},
3228+
"Update": Object {
3229+
"Fn::Join": Array [
3230+
"",
3231+
Array [
3232+
"{"service":"cloudfront","action":"createInvalidation","parameters":{"DistributionId":"",
3233+
Object {
3234+
"Ref": "Webapp107041BD",
3235+
},
3236+
"","InvalidationBatch":{"CallerReference":"",
3237+
Object {
3238+
"Fn::GetAtt": Array [
3239+
"WebappHandlerCurrentVersionREDACTED",
3240+
"Version",
3241+
],
3242+
},
3243+
"","Paths":{"Quantity":1,"Items":["/*"]}}},"physicalResourceId":{"id":"invalidation"}}",
3244+
],
3245+
],
3246+
},
3247+
},
3248+
"Type": "Custom::AWS",
3249+
"UpdateReplacePolicy": "Delete",
3250+
},
3251+
"WebappCloudFrontInvalidationCustomResourcePolicy18C215D6": Object {
3252+
"Properties": Object {
3253+
"PolicyDocument": Object {
3254+
"Statement": Array [
3255+
Object {
3256+
"Action": "cloudfront:CreateInvalidation",
3257+
"Effect": "Allow",
3258+
"Resource": Object {
3259+
"Fn::Join": Array [
3260+
"",
3261+
Array [
3262+
"arn:",
3263+
Object {
3264+
"Ref": "AWS::Partition",
3265+
},
3266+
":cloudfront::123456789012:distribution/",
3267+
Object {
3268+
"Ref": "Webapp107041BD",
3269+
},
3270+
],
3271+
],
3272+
},
3273+
},
3274+
],
3275+
"Version": "2012-10-17",
3276+
},
3277+
"PolicyName": "WebappCloudFrontInvalidationCustomResourcePolicy18C215D6",
3278+
"Roles": Array [
3279+
Object {
3280+
"Ref": "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2",
3281+
},
3282+
],
3283+
},
3284+
"Type": "AWS::IAM::Policy",
3285+
},
31963286
"WebappHandler8DD158A3": Object {
31973287
"DependsOn": Array [
31983288
"VpcPrivateSubnet1DefaultRouteBE02A9ED",
@@ -3415,6 +3505,22 @@ sudo service iptables save",
34153505
},
34163506
"Type": "AWS::Lambda::Function",
34173507
},
3508+
"WebappHandlerCurrentVersionREDACTED": Object {
3509+
"DependsOn": Array [
3510+
"VpcPrivateSubnet1DefaultRouteBE02A9ED",
3511+
"VpcPrivateSubnet1RouteTableAssociation70C59FA6",
3512+
"VpcPrivateSubnet2DefaultRoute060D2087",
3513+
"VpcPrivateSubnet2RouteTableAssociationA89CAD56",
3514+
"VpcPrivateSubnet3DefaultRoute94B74F0D",
3515+
"VpcPrivateSubnet3RouteTableAssociation16BDDC43",
3516+
],
3517+
"Properties": Object {
3518+
"FunctionName": Object {
3519+
"Ref": "WebappHandler8DD158A3",
3520+
},
3521+
},
3522+
"Type": "AWS::Lambda::Version",
3523+
},
34183524
"WebappHandlerFunctionUrl7AEF8DEE": Object {
34193525
"DependsOn": Array [
34203526
"VpcPrivateSubnet1DefaultRouteBE02A9ED",

cdk/test/__snapshots__/serverless-fullstack-webapp-starter-kit.test.ts.snap

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3038,6 +3038,96 @@ sudo service iptables save",
30383038
"Type": "AWS::ECR::Repository",
30393039
"UpdateReplacePolicy": "Delete",
30403040
},
3041+
"WebappCloudFrontInvalidation588CF152": Object {
3042+
"DeletionPolicy": "Delete",
3043+
"DependsOn": Array [
3044+
"WebappCloudFrontInvalidationCustomResourcePolicy18C215D6",
3045+
],
3046+
"Properties": Object {
3047+
"Create": Object {
3048+
"Fn::Join": Array [
3049+
"",
3050+
Array [
3051+
"{"service":"cloudfront","action":"createInvalidation","parameters":{"DistributionId":"",
3052+
Object {
3053+
"Ref": "Webapp107041BD",
3054+
},
3055+
"","InvalidationBatch":{"CallerReference":"",
3056+
Object {
3057+
"Fn::GetAtt": Array [
3058+
"WebappHandlerCurrentVersionREDACTED",
3059+
"Version",
3060+
],
3061+
},
3062+
"","Paths":{"Quantity":1,"Items":["/*"]}}},"physicalResourceId":{"id":"invalidation"}}",
3063+
],
3064+
],
3065+
},
3066+
"InstallLatestAwsSdk": true,
3067+
"ServiceToken": Object {
3068+
"Fn::GetAtt": Array [
3069+
"AWS679f53fac002430cb0da5b7982bd22872D164C4C",
3070+
"Arn",
3071+
],
3072+
},
3073+
"Update": Object {
3074+
"Fn::Join": Array [
3075+
"",
3076+
Array [
3077+
"{"service":"cloudfront","action":"createInvalidation","parameters":{"DistributionId":"",
3078+
Object {
3079+
"Ref": "Webapp107041BD",
3080+
},
3081+
"","InvalidationBatch":{"CallerReference":"",
3082+
Object {
3083+
"Fn::GetAtt": Array [
3084+
"WebappHandlerCurrentVersionREDACTED",
3085+
"Version",
3086+
],
3087+
},
3088+
"","Paths":{"Quantity":1,"Items":["/*"]}}},"physicalResourceId":{"id":"invalidation"}}",
3089+
],
3090+
],
3091+
},
3092+
},
3093+
"Type": "Custom::AWS",
3094+
"UpdateReplacePolicy": "Delete",
3095+
},
3096+
"WebappCloudFrontInvalidationCustomResourcePolicy18C215D6": Object {
3097+
"Properties": Object {
3098+
"PolicyDocument": Object {
3099+
"Statement": Array [
3100+
Object {
3101+
"Action": "cloudfront:CreateInvalidation",
3102+
"Effect": "Allow",
3103+
"Resource": Object {
3104+
"Fn::Join": Array [
3105+
"",
3106+
Array [
3107+
"arn:",
3108+
Object {
3109+
"Ref": "AWS::Partition",
3110+
},
3111+
":cloudfront::123456789012:distribution/",
3112+
Object {
3113+
"Ref": "Webapp107041BD",
3114+
},
3115+
],
3116+
],
3117+
},
3118+
},
3119+
],
3120+
"Version": "2012-10-17",
3121+
},
3122+
"PolicyName": "WebappCloudFrontInvalidationCustomResourcePolicy18C215D6",
3123+
"Roles": Array [
3124+
Object {
3125+
"Ref": "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2",
3126+
},
3127+
],
3128+
},
3129+
"Type": "AWS::IAM::Policy",
3130+
},
30413131
"WebappHandler8DD158A3": Object {
30423132
"DependsOn": Array [
30433133
"VpcPrivateSubnet1DefaultRouteBE02A9ED",
@@ -3245,6 +3335,22 @@ sudo service iptables save",
32453335
},
32463336
"Type": "AWS::Lambda::Function",
32473337
},
3338+
"WebappHandlerCurrentVersionREDACTED": Object {
3339+
"DependsOn": Array [
3340+
"VpcPrivateSubnet1DefaultRouteBE02A9ED",
3341+
"VpcPrivateSubnet1RouteTableAssociation70C59FA6",
3342+
"VpcPrivateSubnet2DefaultRoute060D2087",
3343+
"VpcPrivateSubnet2RouteTableAssociationA89CAD56",
3344+
"VpcPrivateSubnet3DefaultRoute94B74F0D",
3345+
"VpcPrivateSubnet3RouteTableAssociation16BDDC43",
3346+
],
3347+
"Properties": Object {
3348+
"FunctionName": Object {
3349+
"Ref": "WebappHandler8DD158A3",
3350+
},
3351+
},
3352+
"Type": "AWS::Lambda::Version",
3353+
},
32483354
"WebappHandlerFunctionUrl7AEF8DEE": Object {
32493355
"DependsOn": Array [
32503356
"VpcPrivateSubnet1DefaultRouteBE02A9ED",

0 commit comments

Comments
 (0)