Skip to content

Commit 7231e06

Browse files
committed
Add drain states to PipelineResult
1 parent 55e1ecb commit 7231e06

12 files changed

Lines changed: 96 additions & 20 deletions

File tree

runners/flink/src/main/java/org/apache/beam/runners/flink/FlinkDetachedRunnerResult.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,11 @@ public synchronized State drain() throws IOException {
120120

121121
private State getDrainState(CompletableFuture<String> drainFuture) throws IOException {
122122
if (!drainFuture.isDone()) {
123-
return State.RUNNING;
123+
return State.DRAINING;
124124
}
125125
try {
126126
drainFuture.get();
127-
return State.DONE;
127+
return State.DRAINED;
128128
} catch (InterruptedException e) {
129129
Thread.currentThread().interrupt();
130130
throw new IOException("Failed to drain Flink job", e);

runners/flink/src/test/java/org/apache/beam/runners/flink/FlinkRunnerResultTest.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,18 @@ public void testDrainDoneResultDoesNotThrowAnException() throws Exception {
6666
}
6767

6868
@Test
69-
public void testDetachedDrainReturnsRunningThenDone() throws Exception {
69+
public void testDetachedDrainReturnsDrainingThenDrained() throws Exception {
7070
JobClient jobClient = mock(JobClient.class);
7171
CompletableFuture<String> drainFuture = new CompletableFuture<>();
7272
when(jobClient.stopWithSavepoint(true, null, SavepointFormatType.DEFAULT))
7373
.thenReturn(drainFuture);
7474
FlinkDetachedRunnerResult result = new FlinkDetachedRunnerResult(jobClient, 1);
7575

76-
assertThat(result.drain(), is(PipelineResult.State.RUNNING));
77-
assertThat(result.getState(), is(PipelineResult.State.RUNNING));
76+
assertThat(result.drain(), is(PipelineResult.State.DRAINING));
77+
assertThat(result.getState(), is(PipelineResult.State.DRAINING));
7878

7979
drainFuture.complete("savepoint");
80-
assertThat(result.getState(), is(PipelineResult.State.DONE));
80+
assertThat(result.getState(), is(PipelineResult.State.DRAINED));
8181
verify(jobClient).stopWithSavepoint(true, null, SavepointFormatType.DEFAULT);
8282
}
8383

@@ -132,11 +132,11 @@ public void testDetachedDrainRetriesAfterFailure() throws Exception {
132132
result.drain();
133133
fail("Expected IOException");
134134
} catch (IOException expected) {
135-
assertThat(result.drain(), is(PipelineResult.State.RUNNING));
135+
assertThat(result.drain(), is(PipelineResult.State.DRAINING));
136136
}
137137

138138
retryDrainFuture.complete("savepoint");
139-
assertThat(result.getState(), is(PipelineResult.State.DONE));
139+
assertThat(result.getState(), is(PipelineResult.State.DRAINED));
140140
verify(jobClient, times(2)).stopWithSavepoint(true, null, SavepointFormatType.DEFAULT);
141141
}
142142
}

runners/google-cloud-dataflow-java/src/main/java/org/apache/beam/runners/dataflow/DataflowPipelineJob.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ private void logTerminalState(State state) {
365365
switch (state) {
366366
case DONE:
367367
case CANCELLED:
368+
case DRAINED:
368369
LOG.info("Job {} finished with status {}.", getJobId(), state);
369370
break;
370371
case UPDATED:

runners/google-cloud-dataflow-java/src/main/java/org/apache/beam/runners/dataflow/util/MonitoringUtil.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,17 +221,19 @@ public static State toState(@Nullable String stateName) {
221221
return State.CANCELLED;
222222
case "JOB_STATE_UPDATED":
223223
return State.UPDATED;
224+
case "JOB_STATE_DRAINING":
225+
return State.DRAINING;
226+
case "JOB_STATE_DRAINED":
227+
return State.DRAINED;
224228

225229
case "JOB_STATE_RUNNING":
226230
case "JOB_STATE_PENDING": // Job has not yet started; closest mapping is RUNNING
227-
case "JOB_STATE_DRAINING": // Job is still active; the closest mapping is RUNNING
228231
case "JOB_STATE_CANCELLING": // Job is still active; the closest mapping is RUNNING
229232
case "JOB_STATE_PAUSING": // Job is still active; the closest mapping is RUNNING
230233
case "JOB_STATE_RESOURCE_CLEANING_UP": // Job is still active; the closest mapping is RUNNING
231234
return State.RUNNING;
232235

233236
case "JOB_STATE_DONE":
234-
case "JOB_STATE_DRAINED": // Job has successfully terminated; closest mapping is DONE
235237
return State.DONE;
236238
default:
237239
LOG.warn(

runners/google-cloud-dataflow-java/src/test/java/org/apache/beam/runners/dataflow/DataflowPipelineJobTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ public void testDrainUnterminatedJobThatSucceeds() throws IOException {
417417
DataflowPipelineJob job =
418418
new DataflowPipelineJob(DataflowClient.create(options), JOB_ID, options, null);
419419

420-
assertEquals(State.RUNNING, job.drain());
420+
assertEquals(State.DRAINING, job.drain());
421421
Job content = new Job();
422422
content.setProjectId(PROJECT_ID);
423423
content.setId(JOB_ID);

runners/google-cloud-dataflow-java/src/test/java/org/apache/beam/runners/dataflow/util/MonitoringUtilTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,9 @@ public void testToStateNormal() {
100100

101101
// Non-trivially mapped cases
102102
assertEquals(State.STOPPED, MonitoringUtil.toState("JOB_STATE_PAUSED"));
103-
assertEquals(State.RUNNING, MonitoringUtil.toState("JOB_STATE_DRAINING"));
103+
assertEquals(State.DRAINING, MonitoringUtil.toState("JOB_STATE_DRAINING"));
104104
assertEquals(State.RUNNING, MonitoringUtil.toState("JOB_STATE_PAUSING"));
105-
assertEquals(State.DONE, MonitoringUtil.toState("JOB_STATE_DRAINED"));
105+
assertEquals(State.DRAINED, MonitoringUtil.toState("JOB_STATE_DRAINED"));
106106
}
107107

108108
@Test

runners/java-job-service/src/main/java/org/apache/beam/runners/jobsubmission/JobInvocation.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,12 @@ public void onSuccess(PortablePipelineResult pipelineResult) {
116116
case RUNNING:
117117
setState(JobState.Enum.RUNNING);
118118
break;
119+
case DRAINING:
120+
setState(JobState.Enum.DRAINING);
121+
break;
122+
case DRAINED:
123+
setState(JobState.Enum.DRAINED);
124+
break;
119125
case CANCELLED:
120126
setState(JobState.Enum.CANCELLED);
121127
break;
@@ -169,9 +175,12 @@ public synchronized void cancel() {
169175
new FutureCallback<PortablePipelineResult>() {
170176
@Override
171177
public void onSuccess(PortablePipelineResult pipelineResult) {
172-
// Do not cancel when we are already done.
173-
if (pipelineResult != null
174-
&& pipelineResult.getState() != PipelineResult.State.DONE) {
178+
// Do not cancel when the runner has already successfully finished.
179+
if (pipelineResult != null) {
180+
PipelineResult.State state = pipelineResult.getState();
181+
if (state == PipelineResult.State.DONE || state == PipelineResult.State.DRAINED) {
182+
return;
183+
}
175184
try {
176185
pipelineResult.cancel();
177186
setState(JobState.Enum.CANCELLED);

runners/java-job-service/src/test/java/org/apache/beam/runners/jobsubmission/JobInvocationTest.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,28 @@ public void testStateAfterCompletion() throws Exception {
8080
awaitJobState(jobInvocation, JobApi.JobState.Enum.DONE);
8181
}
8282

83+
@Test(timeout = 10_000)
84+
public void testStateAfterDrainCompleted() throws Exception {
85+
jobInvocation.start();
86+
assertThat(jobInvocation.getState(), is(JobApi.JobState.Enum.RUNNING));
87+
88+
TestPipelineResult pipelineResult = new TestPipelineResult(PipelineResult.State.DRAINED);
89+
runner.setResult(pipelineResult);
90+
91+
awaitJobState(jobInvocation, JobApi.JobState.Enum.DRAINED);
92+
}
93+
94+
@Test(timeout = 10_000)
95+
public void testStateAfterDrainStarted() throws Exception {
96+
jobInvocation.start();
97+
assertThat(jobInvocation.getState(), is(JobApi.JobState.Enum.RUNNING));
98+
99+
TestPipelineResult pipelineResult = new TestPipelineResult(PipelineResult.State.DRAINING);
100+
runner.setResult(pipelineResult);
101+
102+
awaitJobState(jobInvocation, JobApi.JobState.Enum.DRAINING);
103+
}
104+
83105
@Test(timeout = 10_000)
84106
public void testStateAfterCompletionWithoutResult() throws Exception {
85107
jobInvocation.start();
@@ -128,6 +150,20 @@ public void testNoCancellationWhenDone() throws Exception {
128150
assertThat(pipelineResult.cancelLatch.getCount(), is(1L));
129151
}
130152

153+
@Test(timeout = 10_000)
154+
public void testNoCancellationWhenDrained() throws Exception {
155+
jobInvocation.start();
156+
assertThat(jobInvocation.getState(), is(JobApi.JobState.Enum.RUNNING));
157+
158+
TestPipelineResult pipelineResult = new TestPipelineResult(PipelineResult.State.DRAINED);
159+
runner.setResult(pipelineResult);
160+
awaitJobState(jobInvocation, JobApi.JobState.Enum.DRAINED);
161+
162+
jobInvocation.cancel();
163+
assertThat(jobInvocation.getState(), is(JobApi.JobState.Enum.DRAINED));
164+
assertThat(pipelineResult.cancelLatch.getCount(), is(1L));
165+
}
166+
131167
@Test(timeout = 10_000)
132168
public void testReturnsMetricsFromJobInvocationAfterSuccess() throws Exception {
133169
JobApi.MetricResults expectedMonitoringInfos = JobApi.MetricResults.newBuilder().build();

runners/portability/java/src/main/java/org/apache/beam/runners/portability/JobServicePipelineResult.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ private void waitForTerminalState() {
160160
}
161161

162162
private void propagateErrors() {
163-
if (terminalState != State.DONE) {
163+
if (terminalState != State.DONE && terminalState != State.DRAINED) {
164164
JobMessagesRequest messageStreamRequest =
165165
JobMessagesRequest.newBuilder().setJobIdBytes(jobId).build();
166166
Iterator<JobMessagesResponse> messageStreamIterator =
@@ -196,10 +196,9 @@ private static State getJavaState(JobApi.JobState.Enum protoState) {
196196
case UPDATED:
197197
return State.UPDATED;
198198
case DRAINING:
199-
// TODO: Determine the correct mappings for the states below.
200-
return State.UNKNOWN;
199+
return State.DRAINING;
201200
case DRAINED:
202-
return State.UNKNOWN;
201+
return State.DRAINED;
203202
case STARTING:
204203
return State.RUNNING;
205204
case CANCELLING:

runners/portability/java/src/test/java/org/apache/beam/runners/portability/PortableRunnerTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,27 @@ public void stagesAndRunsJob() throws Exception {
109109
assertThat(state, is(State.DONE));
110110
}
111111

112+
@Test
113+
public void mapsDrainingJobState() throws Exception {
114+
createJobServer(JobState.Enum.DRAINING, JobApi.MetricResults.getDefaultInstance());
115+
PortableRunner runner = PortableRunner.create(options, ManagedChannelFactory.createInProcess());
116+
PipelineResult result = runner.run(p);
117+
118+
try {
119+
assertThat(result.getState(), is(State.DRAINING));
120+
} finally {
121+
((AutoCloseable) result).close();
122+
}
123+
}
124+
125+
@Test
126+
public void mapsDrainedJobState() throws Exception {
127+
createJobServer(JobState.Enum.DRAINED, JobApi.MetricResults.getDefaultInstance());
128+
PortableRunner runner = PortableRunner.create(options, ManagedChannelFactory.createInProcess());
129+
State state = runner.run(p).waitUntilFinish();
130+
assertThat(state, is(State.DRAINED));
131+
}
132+
112133
@Test
113134
public void extractsMetrics() throws Exception {
114135
JobApi.MetricResults metricResults = generateMetricResults();

0 commit comments

Comments
 (0)