Skip to content

Commit ddf07ab

Browse files
authored
Schedule API updates (#230)
1 parent aeaac41 commit ddf07ab

File tree

2 files changed

+111
-29
lines changed

2 files changed

+111
-29
lines changed

Diff for: temporal/api/schedule/v1/message.proto

+108-29
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2121
// THE SOFTWARE.
2222

23+
// (-- api-linter: core::0203::optional=disabled
24+
// aip.dev/not-precedent: field_behavior annotation not available in our gogo fork --)
25+
// (-- api-linter: core::0203::input-only=disabled
26+
// aip.dev/not-precedent: field_behavior annotation not available in our gogo fork --)
27+
2328
syntax = "proto3";
2429

2530
package temporal.api.schedule.v1;
@@ -41,21 +46,23 @@ import "temporal/api/enums/v1/schedule.proto";
4146
import "temporal/api/workflow/v1/message.proto";
4247

4348
// CalendarSpec describes an event specification relative to the calendar,
44-
// similar to a traditional cron specification. Each field can be one of:
49+
// similar to a traditional cron specification, but with labeled fields. Each
50+
// field can be one of:
4551
// *: matches always
4652
// x: matches when the field equals x
4753
// x/y : matches when the field equals x+n*y where n is an integer
4854
// x-z: matches when the field is between x and z inclusive
4955
// w,x,y,...: matches when the field is one of the listed values
5056
// Each x, y, z, ... is either a decimal integer, or a month or day of week name
5157
// or abbreviation (in the appropriate fields).
52-
// A second in time matches if all fields match.
58+
// A timestamp matches if all fields match.
59+
// Note that fields have different default values, for convenience.
5360
// Note that the special case that some cron implementations have for treating
5461
// day_of_month and day_of_week as "or" instead of "and" when both are set is
5562
// not implemented.
5663
// day_of_week can accept 0 or 7 as Sunday
57-
// TODO: add relative-to-end-of-month
58-
// TODO: add nth day-of-week in month
64+
// CalendarSpec gets compiled into StructuredCalendarSpec, which is what will be
65+
// returned if you describe the schedule.
5966
message CalendarSpec {
6067
// Expression to match seconds. Default: 0
6168
string second = 1;
@@ -73,6 +80,51 @@ message CalendarSpec {
7380
string year = 6;
7481
// Expression to match days of the week. Default: *
7582
string day_of_week = 7;
83+
// Free-form comment describing the intention of this spec.
84+
string comment = 8;
85+
}
86+
87+
// Range represents a set of integer values, used to match fields of a calendar
88+
// time in StructuredCalendarSpec. If end < start, then end is interpreted as
89+
// equal to start. This means you can use a Range with start set to a value, and
90+
// end and step unset (defaulting to 0) to represent a single value.
91+
message Range {
92+
// Start of range (inclusive).
93+
int32 start = 1;
94+
// End of range (inclusive).
95+
int32 end = 2;
96+
// Step (optional, default 1).
97+
int32 step = 3;
98+
}
99+
100+
// StructuredCalendarSpec describes an event specification relative to the
101+
// calendar, in a form that's easy to work with programmatically. Each field can
102+
// be one or more ranges.
103+
// A timestamp matches if at least one range of each field matches the
104+
// corresponding fields of the timestamp, except for year: if year is missing,
105+
// that means all years match. For all fields besides year, at least one Range
106+
// must be present to match anything.
107+
// TODO: add relative-to-end-of-month
108+
// TODO: add nth day-of-week in month
109+
message StructuredCalendarSpec {
110+
// Match seconds (0-59)
111+
repeated Range second = 1;
112+
// Match minutes (0-59)
113+
repeated Range minute = 2;
114+
// Match hours (0-23)
115+
repeated Range hour = 3;
116+
// Match days of the month (1-31)
117+
// (-- api-linter: core::0140::prepositions=disabled
118+
// aip.dev/not-precedent: standard name of field --)
119+
repeated Range day_of_month = 4;
120+
// Match months (1-12)
121+
repeated Range month = 5;
122+
// Match years.
123+
repeated Range year = 6;
124+
// Match days of the week (0-6; 0 is Sunday).
125+
repeated Range day_of_week = 7;
126+
// Free-form comment describing the intention of this spec.
127+
string comment = 8;
76128
}
77129

78130
// IntervalSpec matches times that can be expressed as:
@@ -97,24 +149,56 @@ message IntervalSpec {
97149
// definition of a time zone can change over time (most commonly, when daylight
98150
// saving time policy changes for an area). To create a totally self-contained
99151
// ScheduleSpec, use UTC or include timezone_data.
152+
//
153+
// For input, you can provide zero or more of: structured_calendar, calendar,
154+
// cron_string, interval, and exclude_structured_calendar, and all of them will
155+
// be used (the schedule will take action at the union of all of their times,
156+
// minus the ones that match exclude_structured_calendar).
157+
//
158+
// On input, calendar and cron_string fields will be compiled into
159+
// structured_calendar (and maybe interval and timezone_name), so if you
160+
// Describe a schedule, you'll see only structured_calendar, interval, etc.
100161
message ScheduleSpec {
162+
// Calendar-based specifications of times.
163+
repeated StructuredCalendarSpec structured_calendar = 7;
164+
// cron_string holds a traditional cron specification as a string. It
165+
// accepts 5, 6, or 7 fields, separated by spaces, and interprets them the
166+
// same way as CalendarSpec.
167+
// 5 fields: minute, hour, day_of_month, month, day_of_week
168+
// 6 fields: minute, hour, day_of_month, month, day_of_week, year
169+
// 7 fields: second, minute, hour, day_of_month, month, day_of_week, year
170+
// If year is not given, it defaults to *. If second is not given, it
171+
// defaults to 0.
172+
// Shorthands @yearly, @monthly, @weekly, @daily, and @hourly are also
173+
// accepted instead of the 5-7 time fields.
174+
// Optionally, the string can be preceded by CRON_TZ=<timezone name> or
175+
// TZ=<timezone name>, which will get copied to timezone_name. (There must
176+
// not also be a timezone_name present.)
177+
// Optionally "#" followed by a comment can appear at the end of the string.
178+
// Note that the special case that some cron implementations have for
179+
// treating day_of_month and day_of_week as "or" instead of "and" when both
180+
// are set is not implemented.
181+
// @every <interval>[/<phase>] is accepted and gets compiled into an
182+
// IntervalSpec instead. <interval> and <phase> should be a decimal integer
183+
// with a unit suffix s, m, h, or d.
184+
repeated string cron_string = 8;
101185
// Calendar-based specifications of times.
102186
repeated CalendarSpec calendar = 1;
103187
// Interval-based specifications of times.
104188
repeated IntervalSpec interval = 2;
105-
// Any timestamps matching any of the exclude_calendar specs will be
106-
// skipped.
107-
repeated CalendarSpec exclude_calendar = 3;
108-
// Any timestamps before start_time will be skipped. Together, start_time
109-
// and end_time make an inclusive interval.
189+
// Any timestamps matching any of exclude_* will be skipped.
190+
repeated CalendarSpec exclude_calendar = 3 [deprecated = true]; // use exclude_structured_calendar
191+
repeated StructuredCalendarSpec exclude_structured_calendar = 9;
192+
// If start_time is set, any timestamps before start_time will be skipped.
193+
// (Together, start_time and end_time make an inclusive interval.)
110194
google.protobuf.Timestamp start_time = 4 [(gogoproto.stdtime) = true];
111-
// Any timestamps after end_time will be skipped.
195+
// If end_time is set, any timestamps after end_time will be skipped.
112196
google.protobuf.Timestamp end_time = 5 [(gogoproto.stdtime) = true];
113197
// All timestamps will be incremented by a random value from 0 to this
114-
// amount of jitter. Default: 1 second
198+
// amount of jitter. Default: 0
115199
google.protobuf.Duration jitter = 6 [(gogoproto.stdduration) = true];
116200

117-
// Time zone to interpret all CalendarSpecs in.
201+
// Time zone to interpret all calendar-based specs in.
118202
//
119203
// If unset, defaults to UTC. We recommend using UTC for your application if
120204
// at all possible, to avoid various surprising properties of time zones.
@@ -134,21 +218,17 @@ message ScheduleSpec {
134218
// at 2:30am and specify a time zone that follows DST, that action will not
135219
// be triggered on the day that has no 2:30am. Similarly, an action that
136220
// fires at 1:30am will be triggered twice on the day that has two 1:30s.
221+
//
222+
// Also note that no actions are taken on leap-seconds (e.g. 23:59:60 UTC).
137223
string timezone_name = 10;
138224
bytes timezone_data = 11;
139225
}
140226

141227
message SchedulePolicies {
142228
// Policy for overlaps.
143-
// Note that this can be changed after a schedule has taken some actions, and we can't
144-
// provide 100% sensible semantics for all changes. The most confusing case would be
145-
// changes to/from ALLOW_ALL: with that policy multiple scheduled workflows can run
146-
// concurrently, but for all other policies only one can run at a time. Changing
147-
// between these two classes will leave all workflows with the other class alone.
148-
// E.g., if changing from ALLOW_ALL to CANCEL_OTHER, and there are workflows running,
149-
// those workflows will not be cancelled. If changing from ALLOW_ALL to SKIP with
150-
// workflows running, the running workflows will not cause the next action to be
151-
// skipped.
229+
// Note that this can be changed after a schedule has taken some actions,
230+
// and some changes might produce unintuitive results. In general, the later
231+
// policy overrides the earlier policy.
152232
temporal.api.enums.v1.ScheduleOverlapPolicy overlap_policy = 1;
153233

154234
// Policy for catchups:
@@ -195,10 +275,11 @@ message ScheduleState {
195275
// If true, do not take any actions based on the schedule spec.
196276
bool paused = 2;
197277

198-
// If limited_actions is true, decrement remaining_actions after each action, and do
199-
// not take any more scheduled actions if remaining_actions is zero. Actions may still
200-
// be taken by explicit request. Skipped actions (due to overlap policy) do not count
201-
// against remaining actions.
278+
// If limited_actions is true, decrement remaining_actions after each
279+
// action, and do not take any more scheduled actions if remaining_actions
280+
// is zero. Actions may still be taken by explicit request (i.e. trigger
281+
// immediately or backfill). Skipped actions (due to overlap policy) do not
282+
// count against remaining actions.
202283
bool limited_actions = 3;
203284
int64 remaining_actions = 4;
204285
}
@@ -258,8 +339,7 @@ message ScheduleInfo {
258339
google.protobuf.Timestamp create_time = 6 [(gogoproto.stdtime) = true];
259340
google.protobuf.Timestamp update_time = 7 [(gogoproto.stdtime) = true];
260341

261-
// Error for invalid schedule. If this is set, no actions will be taken.
262-
string invalid_schedule_error = 8;
342+
string invalid_schedule_error = 8 [deprecated = true];
263343
}
264344

265345
message Schedule {
@@ -273,8 +353,7 @@ message Schedule {
273353
// that's returned in ListSchedules.
274354
message ScheduleListInfo {
275355
// From spec:
276-
// Some fields are too large/unimportant for the purpose of listing, so we'll clear them
277-
// from this copy of spec: exclude_calendar, jitter, timezone_data.
356+
// Some fields are dropped from this copy of spec: timezone_data
278357
ScheduleSpec spec = 1;
279358

280359
// From action:

Diff for: temporal/api/workflowservice/v1/request_response.proto

+3
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,9 @@ message DescribeScheduleRequest {
900900
message DescribeScheduleResponse {
901901
// The complete current schedule details. This may not match the schedule as
902902
// created because:
903+
// - some types of schedule specs may get compiled into others (e.g.
904+
// CronString into StructuredCalendarSpec)
905+
// - some unspecified fields may be replaced by defaults
903906
// - some fields in the state are modified automatically
904907
// - the schedule may have been modified by UpdateSchedule or PatchSchedule
905908
temporal.api.schedule.v1.Schedule schedule = 1;

0 commit comments

Comments
 (0)