Skip to content

Commit d981c5f

Browse files
committed
feat(schedule): support creating schedule in paused state
Add ScheduleInitialState input type and a five-arg createSchedule() overload that accepts it. Passing ScheduleInitialState with paused=true creates the schedule already paused, removing the need for a subsequent PauseSchedule call. pausedAt is server-populated and intentionally excluded from this type. Also updates the src/main/idls submodule to d6d4d81 (adds state field to CreateScheduleRequest in shared.thrift) and adds the corresponding state field to the generated CreateScheduleRequest Java class. Signed-off-by: abhishek.jha <abhishek.jha@uber.com>
1 parent 3509da1 commit d981c5f

5 files changed

Lines changed: 189 additions & 0 deletions

File tree

src/gen/java/com/uber/cadence/CreateScheduleRequest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ public class CreateScheduleRequest {
1414
private SchedulePolicies policies;
1515
private Memo memo;
1616
private SearchAttributes searchAttributes;
17+
private ScheduleState state;
1718
}

src/main/java/com/uber/cadence/client/ScheduleClient.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import com.uber.cadence.client.schedule.ScheduleAction;
3030
import com.uber.cadence.client.schedule.ScheduleCatchUpPolicy;
3131
import com.uber.cadence.client.schedule.ScheduleDescription;
32+
import com.uber.cadence.client.schedule.ScheduleInitialState;
3233
import com.uber.cadence.client.schedule.SchedulePolicies;
3334
import com.uber.cadence.client.schedule.ScheduleSpec;
3435
import java.util.List;
@@ -74,6 +75,25 @@ CompletableFuture<CreateScheduleResponse> createSchedule(
7475
CompletableFuture<CreateScheduleResponse> createSchedule(
7576
String scheduleId, ScheduleSpec spec, ScheduleAction action, SchedulePolicies policies);
7677

78+
/**
79+
* Creates a new schedule in a specific initial state using clean client types. Pass a {@link
80+
* ScheduleInitialState} with {@code paused = true} to start the schedule already paused, avoiding
81+
* a subsequent {@link #pauseSchedule} call.
82+
*
83+
* @param scheduleId unique identifier for the schedule within the domain
84+
* @param spec when and how often the schedule fires
85+
* @param action what to do on each firing (start a workflow)
86+
* @param policies overlap, catch-up, and failure-handling policies
87+
* @param initialState optional initial pause state; {@code null} behaves like the four-arg
88+
* overload
89+
*/
90+
CompletableFuture<CreateScheduleResponse> createSchedule(
91+
String scheduleId,
92+
ScheduleSpec spec,
93+
ScheduleAction action,
94+
SchedulePolicies policies,
95+
ScheduleInitialState initialState);
96+
7797
/**
7898
* Returns the current configuration and runtime state of a schedule.
7999
*
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/**
2+
* Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* <p>Modifications copyright (C) 2017 Uber Technologies, Inc.
5+
*
6+
* <p>Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file
7+
* except in compliance with the License. A copy of the License is located at
8+
*
9+
* <p>http://aws.amazon.com/apache2.0
10+
*
11+
* <p>or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
13+
* specific language governing permissions and limitations under the License.
14+
*/
15+
package com.uber.cadence.client.schedule;
16+
17+
import java.util.Objects;
18+
19+
/**
20+
* Initial pause state supplied on {@link
21+
* com.uber.cadence.client.ScheduleClient#createSchedule(String, ScheduleSpec, ScheduleAction,
22+
* SchedulePolicies, ScheduleInitialState)} to create a schedule already paused. {@code pausedAt} is
23+
* server-populated and therefore not accepted as input.
24+
*/
25+
public final class ScheduleInitialState {
26+
27+
private final boolean paused;
28+
private final String pauseReason;
29+
private final String pausedBy;
30+
31+
public ScheduleInitialState(boolean paused, String pauseReason, String pausedBy) {
32+
this.paused = paused;
33+
this.pauseReason = pauseReason;
34+
this.pausedBy = pausedBy;
35+
}
36+
37+
/** Whether to create the schedule in the paused state. */
38+
public boolean isPaused() {
39+
return paused;
40+
}
41+
42+
/**
43+
* Human-readable reason for the initial pause. May be {@code null} when {@link #isPaused()} is
44+
* {@code false}.
45+
*/
46+
public String getPauseReason() {
47+
return pauseReason;
48+
}
49+
50+
/**
51+
* Identity of the actor initiating the pause. May be {@code null} when {@link #isPaused()} is
52+
* {@code false}.
53+
*/
54+
public String getPausedBy() {
55+
return pausedBy;
56+
}
57+
58+
@Override
59+
public boolean equals(Object o) {
60+
if (this == o) return true;
61+
if (!(o instanceof ScheduleInitialState)) return false;
62+
ScheduleInitialState that = (ScheduleInitialState) o;
63+
return paused == that.paused
64+
&& Objects.equals(pauseReason, that.pauseReason)
65+
&& Objects.equals(pausedBy, that.pausedBy);
66+
}
67+
68+
@Override
69+
public int hashCode() {
70+
return Objects.hash(paused, pauseReason, pausedBy);
71+
}
72+
73+
@Override
74+
public String toString() {
75+
return "ScheduleInitialState{"
76+
+ "paused="
77+
+ paused
78+
+ ", pauseReason='"
79+
+ pauseReason
80+
+ "', pausedBy='"
81+
+ pausedBy
82+
+ "'}";
83+
}
84+
}

src/main/java/com/uber/cadence/internal/sync/ScheduleClientImpl.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import com.uber.cadence.client.schedule.ScheduleCatchUpPolicy;
4646
import com.uber.cadence.client.schedule.ScheduleDescription;
4747
import com.uber.cadence.client.schedule.ScheduleInfo;
48+
import com.uber.cadence.client.schedule.ScheduleInitialState;
4849
import com.uber.cadence.client.schedule.ScheduleOverlapPolicy;
4950
import com.uber.cadence.client.schedule.SchedulePolicies;
5051
import com.uber.cadence.client.schedule.ScheduleSpec;
@@ -80,12 +81,25 @@ public CompletableFuture<CreateScheduleResponse> createSchedule(
8081
@Override
8182
public CompletableFuture<CreateScheduleResponse> createSchedule(
8283
String scheduleId, ScheduleSpec spec, ScheduleAction action, SchedulePolicies policies) {
84+
return createSchedule(scheduleId, spec, action, policies, null);
85+
}
86+
87+
@Override
88+
public CompletableFuture<CreateScheduleResponse> createSchedule(
89+
String scheduleId,
90+
ScheduleSpec spec,
91+
ScheduleAction action,
92+
SchedulePolicies policies,
93+
ScheduleInitialState initialState) {
8394
try {
8495
CreateScheduleRequest request =
8596
new CreateScheduleRequest()
8697
.setSpec(toThriftSpec(spec))
8798
.setAction(toThriftAction(action))
8899
.setPolicies(toThriftPolicies(policies));
100+
if (initialState != null) {
101+
request.setState(toThriftInitialState(initialState));
102+
}
89103
return createSchedule(scheduleId, request);
90104
} catch (Exception e) {
91105
CompletableFuture<CreateScheduleResponse> f = new CompletableFuture<>();
@@ -297,6 +311,17 @@ private static com.uber.cadence.SchedulePolicies toThriftPolicies(SchedulePolici
297311
return t;
298312
}
299313

314+
private static com.uber.cadence.ScheduleState toThriftInitialState(ScheduleInitialState s) {
315+
com.uber.cadence.ScheduleState t = new com.uber.cadence.ScheduleState().setPaused(s.isPaused());
316+
if (s.isPaused() && (s.getPauseReason() != null || s.getPausedBy() != null)) {
317+
com.uber.cadence.SchedulePauseInfo pi = new com.uber.cadence.SchedulePauseInfo();
318+
if (s.getPauseReason() != null) pi.setReason(s.getPauseReason());
319+
if (s.getPausedBy() != null) pi.setPausedBy(s.getPausedBy());
320+
t.setPauseInfo(pi);
321+
}
322+
return t;
323+
}
324+
300325
private static com.uber.cadence.ScheduleCatchUpPolicy toThriftCatchUpPolicy(
301326
ScheduleCatchUpPolicy p) {
302327
switch (p) {

src/test/java/com/uber/cadence/internal/sync/ScheduleClientImplTest.java

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import com.uber.cadence.UpdateScheduleResponse;
3030
import com.uber.cadence.client.schedule.ScheduleAction;
3131
import com.uber.cadence.client.schedule.ScheduleCatchUpPolicy;
32+
import com.uber.cadence.client.schedule.ScheduleInitialState;
3233
import com.uber.cadence.client.schedule.ScheduleOverlapPolicy;
3334
import com.uber.cadence.client.schedule.SchedulePolicies;
3435
import com.uber.cadence.client.schedule.ScheduleSpec;
@@ -343,6 +344,64 @@ public void updateSchedule_cleanTypeOverload_setsFields() throws Exception {
343344
com.uber.cadence.ScheduleOverlapPolicy.CONCURRENT, req.getPolicies().getOverlapPolicy());
344345
}
345346

347+
// --- initialState ---
348+
349+
@Test
350+
public void createSchedule_initialState_pausedWithReasonAndPausedBy() throws Exception {
351+
ArgumentCaptor<CreateScheduleRequest> captor = forClass(CreateScheduleRequest.class);
352+
when(service.CreateSchedule(captor.capture()))
353+
.thenReturn(CompletableFuture.completedFuture(new CreateScheduleResponse()));
354+
355+
ScheduleInitialState initialState = new ScheduleInitialState(true, "deploying", "ci-bot");
356+
client.createSchedule(SCHEDULE_ID, null, minimalAction(), null, initialState).join();
357+
358+
CreateScheduleRequest req = captor.getValue();
359+
assertNotNull(req.getState());
360+
assertEquals(true, req.getState().isPaused());
361+
assertNotNull(req.getState().getPauseInfo());
362+
assertEquals("deploying", req.getState().getPauseInfo().getReason());
363+
assertEquals("ci-bot", req.getState().getPauseInfo().getPausedBy());
364+
}
365+
366+
@Test
367+
public void createSchedule_initialState_pausedNoPauseInfo() throws Exception {
368+
ArgumentCaptor<CreateScheduleRequest> captor = forClass(CreateScheduleRequest.class);
369+
when(service.CreateSchedule(captor.capture()))
370+
.thenReturn(CompletableFuture.completedFuture(new CreateScheduleResponse()));
371+
372+
client
373+
.createSchedule(
374+
SCHEDULE_ID, null, minimalAction(), null, new ScheduleInitialState(true, null, null))
375+
.join();
376+
377+
CreateScheduleRequest req = captor.getValue();
378+
assertNotNull(req.getState());
379+
assertEquals(true, req.getState().isPaused());
380+
assertNull(req.getState().getPauseInfo());
381+
}
382+
383+
@Test
384+
public void createSchedule_initialState_null_sendsNoState() throws Exception {
385+
ArgumentCaptor<CreateScheduleRequest> captor = forClass(CreateScheduleRequest.class);
386+
when(service.CreateSchedule(captor.capture()))
387+
.thenReturn(CompletableFuture.completedFuture(new CreateScheduleResponse()));
388+
389+
client.createSchedule(SCHEDULE_ID, null, minimalAction(), null, null).join();
390+
391+
assertNull(captor.getValue().getState());
392+
}
393+
394+
@Test
395+
public void createSchedule_fourArg_sendsNoState() throws Exception {
396+
ArgumentCaptor<CreateScheduleRequest> captor = forClass(CreateScheduleRequest.class);
397+
when(service.CreateSchedule(captor.capture()))
398+
.thenReturn(CompletableFuture.completedFuture(new CreateScheduleResponse()));
399+
400+
client.createSchedule(SCHEDULE_ID, null, minimalAction(), null).join();
401+
402+
assertNull(captor.getValue().getState());
403+
}
404+
346405
// --- null handling ---
347406

348407
@Test

0 commit comments

Comments
 (0)