Skip to content

Commit 0b4ab1d

Browse files
authored
feat(scheduler): start and end time for schedule construct (#28306)
This PR added support for start and end time of the schedule. ## Description Currently, users cannot set a start time and an end time for the schedule. A schedule without a start date will begin as soon as it is created and available, and without an end date, it will continue to invoke its target indefinitely. With this feature, users can set the start and end dates of a schedule, allowing for more flexible schedule configurations. https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-scheduler-schedule.html#cfn-scheduler-schedule-startdate https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-scheduler-schedule.html#cfn-scheduler-schedule-enddate In CloudFormation, users can use this feature as follows: ```yaml TestSchedule: Type: AWS::Scheduler::Schedule Properties: StartDate: "2024-12-01T13:09:00.000Z" EndDate: "2025-12-01T00:00:00.001Z" ScheduleExpression: "at(2023-01-01T00:00:00)" State: "ENABLED" Target: # target ``` ## Major changes ### add property to ScheduleProps interface Added startDate and endDate properties, and typed these values as string based on the following PR comments. #26819 (comment) It is not necessary to specify both startDate and endDate, they can be set independently. Validation is performed on the following points. - Error if not following ISO 8601 format. - Must include milliseconds (yyyy-MM-ddTHH:mm:ss.SSSZ) - Error if startDate is later than endDate If a time before the current time is specified, the following error occurs in CFn, but no validation is performed because the timing of validation in CDK and the timing of actual deployment are different. `The StartDate you specify cannot be earlier than 5 minutes ago.` ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent db22b85 commit 0b4ab1d

11 files changed

+189
-20
lines changed

packages/@aws-cdk/aws-scheduler-alpha/README.md

+14
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,20 @@ new Schedule(this, 'Schedule', {
138138
});
139139
```
140140

141+
### Configuring a start and end time of the Schedule
142+
143+
If you choose a recurring schedule, you can set the start and end time of the Schedule by specifying the `start` and `end`.
144+
145+
```ts
146+
declare const target: targets.LambdaInvoke;
147+
148+
new Schedule(this, 'Schedule', {
149+
schedule: ScheduleExpression.rate(cdk.Duration.hours(12)),
150+
target: target,
151+
start: new Date('2023-01-01T00:00:00.000Z'),
152+
end: new Date('2023-02-01T00:00:00.000Z'),
153+
});
154+
```
141155

142156
## Scheduler Targets
143157

packages/@aws-cdk/aws-scheduler-alpha/lib/schedule.ts

+27-1
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,22 @@ export interface ScheduleProps {
114114
* @default - All events in Scheduler are encrypted with a key that AWS owns and manages.
115115
*/
116116
readonly key?: kms.IKey;
117+
118+
/**
119+
* The date, in UTC, after which the schedule can begin invoking its target.
120+
* EventBridge Scheduler ignores start for one-time schedules.
121+
*
122+
* @default - no value
123+
*/
124+
readonly start?: Date;
125+
126+
/**
127+
* The date, in UTC, before which the schedule can invoke its target.
128+
* EventBridge Scheduler ignores end for one-time schedules.
129+
*
130+
* @default - no value
131+
*/
132+
readonly end?: Date;
117133
}
118134

119135
/**
@@ -254,6 +270,8 @@ export class Schedule extends Resource implements ISchedule {
254270

255271
this.retryPolicy = targetConfig.retryPolicy;
256272

273+
this.validateTimeFrame(props.start, props.end);
274+
257275
const resource = new CfnSchedule(this, 'Resource', {
258276
name: this.physicalName,
259277
flexibleTimeWindow: { mode: 'OFF' },
@@ -276,6 +294,8 @@ export class Schedule extends Resource implements ISchedule {
276294
sageMakerPipelineParameters: targetConfig.sageMakerPipelineParameters,
277295
sqsParameters: targetConfig.sqsParameters,
278296
},
297+
startDate: props.start?.toISOString(),
298+
endDate: props.end?.toISOString(),
279299
});
280300

281301
this.scheduleName = this.getResourceNameAttribute(resource.ref);
@@ -306,4 +326,10 @@ export class Schedule extends Resource implements ISchedule {
306326
const isEmptyPolicy = Object.values(policy).every(value => value === undefined);
307327
return !isEmptyPolicy ? policy : undefined;
308328
}
309-
}
329+
330+
private validateTimeFrame(start?: Date, end?: Date) {
331+
if (start && end && start >= end) {
332+
throw new Error(`start must precede end, got start: ${start.toISOString()}, end: ${end.toISOString()}`);
333+
}
334+
}
335+
}

packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/aws-cdk-scheduler-schedule.assets.json

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/aws-cdk-scheduler-schedule.template.json

+32
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,38 @@
348348
}
349349
}
350350
}
351+
},
352+
"ScheduleWithTimeFrameC1C8BDCC": {
353+
"Type": "AWS::Scheduler::Schedule",
354+
"Properties": {
355+
"EndDate": "2025-10-01T00:00:00.000Z",
356+
"FlexibleTimeWindow": {
357+
"Mode": "OFF"
358+
},
359+
"ScheduleExpression": "rate(12 hours)",
360+
"ScheduleExpressionTimezone": "Etc/UTC",
361+
"StartDate": "2024-04-15T06:30:00.000Z",
362+
"State": "ENABLED",
363+
"Target": {
364+
"Arn": {
365+
"Fn::GetAtt": [
366+
"Function76856677",
367+
"Arn"
368+
]
369+
},
370+
"Input": "\"Input Text\"",
371+
"RetryPolicy": {
372+
"MaximumEventAgeInSeconds": 180,
373+
"MaximumRetryAttempts": 3
374+
},
375+
"RoleArn": {
376+
"Fn::GetAtt": [
377+
"Role1ABCC5F0",
378+
"Arn"
379+
]
380+
}
381+
}
382+
}
351383
}
352384
},
353385
"Parameters": {

packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/cdk.out

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/integ.json

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/integtestscheduleDefaultTestDeployAssert24CB3896.assets.json

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/manifest.json

+8-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.js.snapshot/tree.json

+60-10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk/aws-scheduler-alpha/test/integ.schedule.ts

+8
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,14 @@ new scheduler.Schedule(stack, 'CustomerKmsSchedule', {
9090
key,
9191
});
9292

93+
const currentYear = new Date().getFullYear();
94+
new scheduler.Schedule(stack, 'ScheduleWithTimeFrame', {
95+
schedule: expression,
96+
target: target,
97+
start: new Date(`${currentYear + 1}-04-15T06:30:00.000Z`),
98+
end: new Date(`${currentYear + 2}-10-01T00:00:00.000Z`),
99+
});
100+
93101
new IntegTest(app, 'integtest-schedule', {
94102
testCases: [stack],
95103
});

packages/@aws-cdk/aws-scheduler-alpha/test/schedule.test.ts

+34-1
Original file line numberDiff line numberDiff line change
@@ -128,4 +128,37 @@ describe('Schedule', () => {
128128
},
129129
});
130130
});
131-
});
131+
132+
describe('schedule timeFrame', () => {
133+
test.each([
134+
{ StartDate: '2023-04-15T06:20:00.000Z', EndDate: '2023-10-01T00:00:00.000Z' },
135+
{ StartDate: '2023-04-15T06:25:00.000Z' },
136+
{ EndDate: '2023-10-01T00:00:00.000Z' },
137+
])('schedule can set start and end', (timeFrame) => {
138+
new Schedule(stack, 'TestSchedule', {
139+
schedule: expr,
140+
target: new SomeLambdaTarget(func, role),
141+
start: timeFrame.StartDate ? new Date(timeFrame.StartDate) : undefined,
142+
end: timeFrame.EndDate ? new Date(timeFrame.EndDate) : undefined,
143+
});
144+
145+
Template.fromStack(stack).hasResourceProperties('AWS::Scheduler::Schedule', {
146+
...timeFrame,
147+
});
148+
});
149+
150+
test.each([
151+
{ start: '2023-10-01T00:00:00.000Z', end: '2023-10-01T00:00:00.000Z' },
152+
{ start: '2023-10-01T00:00:00.000Z', end: '2023-09-01T00:00:00.000Z' },
153+
])('throw error when start does not come before end', ({ start, end }) => {
154+
expect(() => {
155+
new Schedule(stack, 'TestSchedule', {
156+
schedule: expr,
157+
target: new SomeLambdaTarget(func, role),
158+
start: new Date(start),
159+
end: new Date(end),
160+
});
161+
}).toThrow(`start must precede end, got start: ${start}, end: ${end}`);
162+
});
163+
});
164+
});

0 commit comments

Comments
 (0)