Skip to content

Commit

Permalink
feat: Add service timeout to custom resources
Browse files Browse the repository at this point in the history
  • Loading branch information
prazian committed Jun 15, 2024
1 parent 4e9ef15 commit 68ff606
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 1 deletion.
31 changes: 31 additions & 0 deletions packages/aws-cdk-lib/core/lib/custom-resource.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Construct } from 'constructs';
import { CfnResource } from './cfn-resource';
import { RemovalPolicy } from './removal-policy';
import { Duration } from './duration';
import { Resource } from './resource';
import { Token } from './token';

Expand Down Expand Up @@ -91,6 +92,16 @@ export interface CustomResourceProps {
*/
readonly removalPolicy?: RemovalPolicy;

/**
* The ServiceTimeout property from Cloudformation
*
* The value must be a duration between 1 and 3600 seconds.
* The default value is 3600 seconds (1 hour).
*
* @default Duration.minutes(60)
*/
readonly serviceTimeout?: Duration;

/**
* Convert all property keys to pascal case.
*
Expand Down Expand Up @@ -131,6 +142,7 @@ export class CustomResource extends Resource {
const type = renderResourceType(props.resourceType);
const pascalCaseProperties = props.pascalCaseProperties ?? false;
const properties = pascalCaseProperties ? uppercaseProperties(props.properties || {}) : (props.properties || {});
const serviceTimeout = renderServiceTimeout(props.serviceTimeout);

this.resource = new CfnResource(this, 'Default', {
type,
Expand All @@ -143,6 +155,10 @@ export class CustomResource extends Resource {
this.resource.applyRemovalPolicy(props.removalPolicy, {
default: RemovalPolicy.DESTROY,
});

if (serviceTimeout) {
this.resource.addPropertyOverride('ServiceTimeout', serviceTimeout);
}
}

/**
Expand Down Expand Up @@ -214,3 +230,18 @@ function renderResourceType(resourceType?: string) {

return resourceType;
}

function renderServiceTimeout(serviceTimeout?: Duration): number|undefined {

if (!serviceTimeout) {
return undefined;
}

let timeoutSeconds = serviceTimeout.toSeconds();

if (timeoutSeconds < 1 || timeoutSeconds > 3600) {
throw new Error('ServiceTimeout must be an integer from 1 to 3600');
}

return timeoutSeconds;
}
26 changes: 25 additions & 1 deletion packages/aws-cdk-lib/core/test/custom-resource.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { toCloudFormation } from './util';
import { CustomResource, RemovalPolicy, Stack } from '../lib';
import {CustomResource, Duration, RemovalPolicy, Stack} from '../lib';

describe('custom resource', () => {
test('simple case provider identified by service token', () => {
Expand Down Expand Up @@ -82,6 +82,30 @@ describe('custom resource', () => {
});
});

test('custom timeout', () => {
// GIVEN
const stack = new Stack();

// WHEN
new CustomResource(stack, 'MyCustomResource', {
serviceToken: 'MyServiceToken',
serviceTimeout: Duration.minutes(5),
});

// THEN
expect(toCloudFormation(stack)).toEqual({
Resources: {
MyCustomResource: {
Type: 'AWS::CloudFormation::CustomResource',
Properties: {
ServiceToken: 'MyServiceToken',
},
ServiceTimeout: 300,
},
},
});
});

test('resource type must begin with "Custom::"', () => {
// GIVEN
const stack = new Stack();
Expand Down

0 comments on commit 68ff606

Please sign in to comment.