• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

temporalio / sdk-java / #253

21 May 2024 07:13PM UTC coverage: 77.429% (-0.09%) from 77.517%
#253

push

github

web-flow
Don't return update handles until desired stage reached (#2066)

45 of 54 new or added lines in 7 files covered. (83.33%)

17 existing lines in 5 files now uncovered.

19169 of 24757 relevant lines covered (77.43%)

0.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.83
/temporal-sdk/src/main/java/io/temporal/client/WorkflowStubImpl.java
1
/*
2
 * Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved.
3
 *
4
 * Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5
 *
6
 * Modifications copyright (C) 2017 Uber Technologies, Inc.
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this material except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *   http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20

21
package io.temporal.client;
22

23
import com.google.common.base.Strings;
24
import io.grpc.Status;
25
import io.grpc.StatusRuntimeException;
26
import io.temporal.api.common.v1.WorkflowExecution;
27
import io.temporal.api.errordetails.v1.QueryFailedFailure;
28
import io.temporal.api.errordetails.v1.WorkflowExecutionAlreadyStartedFailure;
29
import io.temporal.api.errordetails.v1.WorkflowNotReadyFailure;
30
import io.temporal.api.update.v1.WaitPolicy;
31
import io.temporal.common.interceptors.Header;
32
import io.temporal.common.interceptors.WorkflowClientCallsInterceptor;
33
import io.temporal.failure.CanceledFailure;
34
import io.temporal.serviceclient.CheckedExceptionWrapper;
35
import io.temporal.serviceclient.StatusUtils;
36
import java.lang.reflect.Type;
37
import java.util.Optional;
38
import java.util.UUID;
39
import java.util.concurrent.*;
40
import java.util.concurrent.atomic.AtomicReference;
41
import javax.annotation.Nonnull;
42
import javax.annotation.Nullable;
43

44
class WorkflowStubImpl implements WorkflowStub {
45
  private final WorkflowClientOptions clientOptions;
46
  private final WorkflowClientCallsInterceptor workflowClientInvoker;
47
  private final Optional<String> workflowType;
48
  // Execution this stub is bound to
49
  private final AtomicReference<WorkflowExecution> execution = new AtomicReference<>();
1✔
50
  // Full WorkflowExecution that this stub is started if any.
51
  // After a start, WorkflowStub binds to (workflowId, null) to follow the chain of RunIds.
52
  // But this field keeps the full (workflowId, runId) execution info that was started by this stub.
53
  private final AtomicReference<WorkflowExecution> startedExecution = new AtomicReference<>();
1✔
54
  // if null, this stub is created to bound to an existing execution.
55
  // This stub is created to bound to an existing execution otherwise.
56
  private final @Nullable WorkflowOptions options;
57

58
  WorkflowStubImpl(
59
      WorkflowClientOptions clientOptions,
60
      WorkflowClientCallsInterceptor workflowClientInvoker,
61
      Optional<String> workflowType,
62
      WorkflowExecution execution) {
1✔
63
    this.clientOptions = clientOptions;
1✔
64
    this.workflowClientInvoker = workflowClientInvoker;
1✔
65
    this.workflowType = workflowType;
1✔
66
    if (execution == null || execution.getWorkflowId().isEmpty()) {
1✔
67
      throw new IllegalArgumentException("null or empty workflowId");
×
68
    }
69
    this.execution.set(execution);
1✔
70
    this.options = null;
1✔
71
  }
1✔
72

73
  WorkflowStubImpl(
74
      WorkflowClientOptions clientOptions,
75
      WorkflowClientCallsInterceptor workflowClientInvoker,
76
      String workflowType,
77
      @Nonnull WorkflowOptions options) {
1✔
78
    this.clientOptions = clientOptions;
1✔
79
    this.workflowClientInvoker = workflowClientInvoker;
1✔
80
    this.workflowType = Optional.of(workflowType);
1✔
81
    this.options = options;
1✔
82
  }
1✔
83

84
  @Override
85
  public void signal(String signalName, Object... args) {
86
    checkStarted();
1✔
87
    WorkflowExecution targetExecution = currentExecutionWithoutRunId();
1✔
88
    try {
89
      workflowClientInvoker.signal(
1✔
90
          new WorkflowClientCallsInterceptor.WorkflowSignalInput(
91
              targetExecution, signalName, Header.empty(), args));
1✔
92
    } catch (Exception e) {
1✔
93
      Throwable throwable = throwAsWorkflowFailureException(e, targetExecution);
×
94
      throw new WorkflowServiceException(targetExecution, workflowType.orElse(null), throwable);
×
95
    }
1✔
96
  }
1✔
97

98
  private WorkflowExecution startWithOptions(WorkflowOptions options, Object... args) {
99
    checkExecutionIsNotStarted();
1✔
100
    String workflowId = getWorkflowIdForStart(options);
1✔
101
    WorkflowExecution workflowExecution = null;
1✔
102
    try {
103
      WorkflowClientCallsInterceptor.WorkflowStartOutput workflowStartOutput =
1✔
104
          workflowClientInvoker.start(
1✔
105
              new WorkflowClientCallsInterceptor.WorkflowStartInput(
106
                  workflowId, workflowType.get(), Header.empty(), args, options));
1✔
107
      workflowExecution = workflowStartOutput.getWorkflowExecution();
1✔
108
      populateExecutionAfterStart(workflowExecution);
1✔
109
      return workflowExecution;
1✔
110
    } catch (StatusRuntimeException e) {
1✔
111
      throw wrapStartException(workflowId, workflowType.orElse(null), e);
1✔
112
    } catch (Exception e) {
1✔
113
      if (workflowExecution == null) {
1✔
114
        // if start failed with exception - there could be no valid workflow execution populated
115
        // from the server.
116
        // WorkflowServiceException requires not null workflowExecution, so we have to provide
117
        // an WorkflowExecution instance with just a workflowId
118
        workflowExecution = WorkflowExecution.newBuilder().setWorkflowId(workflowId).build();
1✔
119
      }
120
      throw new WorkflowServiceException(workflowExecution, workflowType.orElse(null), e);
1✔
121
    }
122
  }
123

124
  @Override
125
  public WorkflowExecution start(Object... args) {
126
    if (options == null) {
1✔
127
      throw new IllegalStateException("Required parameter WorkflowOptions is missing");
×
128
    }
129
    return startWithOptions(WorkflowOptions.merge(null, null, options), args);
1✔
130
  }
131

132
  private WorkflowExecution signalWithStartWithOptions(
133
      WorkflowOptions options, String signalName, Object[] signalArgs, Object[] startArgs) {
134
    checkExecutionIsNotStarted();
1✔
135
    String workflowId = getWorkflowIdForStart(options);
1✔
136
    WorkflowExecution workflowExecution = null;
1✔
137
    try {
138
      WorkflowClientCallsInterceptor.WorkflowSignalWithStartOutput workflowStartOutput =
1✔
139
          workflowClientInvoker.signalWithStart(
1✔
140
              new WorkflowClientCallsInterceptor.WorkflowSignalWithStartInput(
141
                  new WorkflowClientCallsInterceptor.WorkflowStartInput(
142
                      workflowId, workflowType.get(), Header.empty(), startArgs, options),
1✔
143
                  signalName,
144
                  signalArgs));
145
      workflowExecution = workflowStartOutput.getWorkflowStartOutput().getWorkflowExecution();
1✔
146
      populateExecutionAfterStart(workflowExecution);
1✔
147
      return workflowExecution;
1✔
148
    } catch (StatusRuntimeException e) {
1✔
149
      throw wrapStartException(workflowId, workflowType.orElse(null), e);
1✔
150
    } catch (Exception e) {
×
151
      if (workflowExecution == null) {
×
152
        // if start failed with exception - there could be no valid workflow execution populated
153
        // from the server.
154
        // WorkflowServiceException requires not null workflowExecution, so we have to provide
155
        // an WorkflowExecution instance with just a workflowId
156
        workflowExecution = WorkflowExecution.newBuilder().setWorkflowId(workflowId).build();
×
157
      }
158
      throw new WorkflowServiceException(workflowExecution, workflowType.orElse(null), e);
×
159
    }
160
  }
161

162
  private static String getWorkflowIdForStart(WorkflowOptions options) {
163
    String workflowId = options.getWorkflowId();
1✔
164
    if (workflowId == null) {
1✔
165
      workflowId = UUID.randomUUID().toString();
1✔
166
    }
167
    return workflowId;
1✔
168
  }
169

170
  @Override
171
  public WorkflowExecution signalWithStart(
172
      String signalName, Object[] signalArgs, Object[] startArgs) {
173
    if (options == null) {
1✔
174
      throw new IllegalStateException("Required parameter WorkflowOptions is missing");
×
175
    }
176
    return signalWithStartWithOptions(
1✔
177
        WorkflowOptions.merge(null, null, options), signalName, signalArgs, startArgs);
1✔
178
  }
179

180
  @Override
181
  public Optional<String> getWorkflowType() {
182
    return workflowType;
1✔
183
  }
184

185
  @Override
186
  public WorkflowExecution getExecution() {
187
    return options != null ? startedExecution.get() : execution.get();
1✔
188
  }
189

190
  @Override
191
  public <R> R getResult(Class<R> resultClass) {
192
    return getResult(resultClass, resultClass);
1✔
193
  }
194

195
  @Override
196
  public <R> R getResult(Class<R> resultClass, Type resultType) {
197
    try {
198
      // int max to not overflow long
199
      return getResult(Integer.MAX_VALUE, TimeUnit.MILLISECONDS, resultClass, resultType);
1✔
200
    } catch (TimeoutException e) {
×
201
      throw new WorkflowServiceException(execution.get(), workflowType.orElse(null), e);
×
202
    }
203
  }
204

205
  @Override
206
  public <R> R getResult(long timeout, TimeUnit unit, Class<R> resultClass)
207
      throws TimeoutException {
208
    return getResult(timeout, unit, resultClass, resultClass);
×
209
  }
210

211
  @Override
212
  public <R> R getResult(long timeout, TimeUnit unit, Class<R> resultClass, Type resultType)
213
      throws TimeoutException {
214
    checkStarted();
1✔
215
    WorkflowExecution targetExecution = execution.get();
1✔
216
    try {
217
      WorkflowClientCallsInterceptor.GetResultOutput<R> result =
1✔
218
          workflowClientInvoker.getResult(
1✔
219
              new WorkflowClientCallsInterceptor.GetResultInput<>(
220
                  targetExecution, workflowType, timeout, unit, resultClass, resultType));
221
      return result.getResult();
1✔
222
    } catch (Exception e) {
1✔
223
      return throwAsWorkflowFailureExceptionForResult(e, resultClass, targetExecution);
×
224
    }
225
  }
226

227
  @Override
228
  public <R> CompletableFuture<R> getResultAsync(Class<R> resultClass) {
229
    return getResultAsync(resultClass, resultClass);
1✔
230
  }
231

232
  @Override
233
  public <R> CompletableFuture<R> getResultAsync(Class<R> resultClass, Type resultType) {
234
    return getResultAsync(Long.MAX_VALUE, TimeUnit.MILLISECONDS, resultClass, resultType);
1✔
235
  }
236

237
  @Override
238
  public <R> CompletableFuture<R> getResultAsync(
239
      long timeout, TimeUnit unit, Class<R> resultClass) {
240
    return getResultAsync(timeout, unit, resultClass, resultClass);
1✔
241
  }
242

243
  @Override
244
  public <R> CompletableFuture<R> getResultAsync(
245
      long timeout, TimeUnit unit, Class<R> resultClass, Type resultType) {
246
    checkStarted();
1✔
247
    WorkflowExecution targetExecution = execution.get();
1✔
248
    WorkflowClientCallsInterceptor.GetResultAsyncOutput<R> result =
1✔
249
        workflowClientInvoker.getResultAsync(
1✔
250
            new WorkflowClientCallsInterceptor.GetResultInput<>(
251
                targetExecution, workflowType, timeout, unit, resultClass, resultType));
252
    return result
1✔
253
        .getResult()
1✔
254
        .exceptionally(
1✔
255
            e -> {
256
              try {
257
                return throwAsWorkflowFailureExceptionForResult(e, resultClass, targetExecution);
×
258
              } catch (TimeoutException ex) {
1✔
259
                throw new CompletionException(ex);
1✔
260
              }
261
            });
262
  }
263

264
  @Override
265
  public <R> R query(String queryType, Class<R> resultClass, Object... args) {
266
    return query(queryType, resultClass, resultClass, args);
1✔
267
  }
268

269
  @Override
270
  public <R> R query(String queryType, Class<R> resultClass, Type resultType, Object... args) {
271
    checkStarted();
1✔
272
    WorkflowClientCallsInterceptor.QueryOutput<R> result;
273
    WorkflowExecution targetExecution = execution.get();
1✔
274
    try {
275
      result =
1✔
276
          workflowClientInvoker.query(
1✔
277
              new WorkflowClientCallsInterceptor.QueryInput<>(
278
                  targetExecution, queryType, Header.empty(), args, resultClass, resultType));
1✔
279
    } catch (Exception e) {
1✔
280
      return throwAsWorkflowFailureExceptionForQuery(e, resultClass, targetExecution);
×
281
    }
1✔
282
    if (result.isQueryRejected()) {
1✔
283
      throw new WorkflowQueryConditionallyRejectedException(
1✔
284
          targetExecution,
285
          workflowType.orElse(null),
1✔
286
          clientOptions.getQueryRejectCondition(),
1✔
287
          result.getQueryRejectedStatus(),
1✔
288
          null);
289
    }
290
    return result.getResult();
1✔
291
  }
292

293
  @Override
294
  public <R> R update(String updateName, Class<R> resultClass, Object... args) {
295
    checkStarted();
1✔
296
    try {
297
      UpdateOptions<R> options =
298
          UpdateOptions.<R>newBuilder()
1✔
299
              .setUpdateName(updateName)
1✔
300
              .setWaitPolicy(WorkflowUpdateStage.COMPLETED)
1✔
301
              .setResultClass(resultClass)
1✔
302
              .build();
1✔
303
      return startUpdate(options, args).getResultAsync().get();
1✔
304
    } catch (InterruptedException e) {
×
305
      throw new RuntimeException(e);
×
306
    } catch (ExecutionException e) {
×
307
      Throwable cause = e.getCause();
×
308
      throw (cause instanceof RuntimeException
×
309
          ? (RuntimeException) cause
×
310
          : new RuntimeException(cause));
×
311
    }
312
  }
313

314
  @Override
315
  public <R> UpdateHandle<R> startUpdate(String updateName, Class<R> resultClass, Object... args) {
316
    UpdateOptions<R> options =
317
        UpdateOptions.<R>newBuilder()
1✔
318
            .setUpdateName(updateName)
1✔
319
            .setWaitPolicy(WorkflowUpdateStage.ACCEPTED)
1✔
320
            .setResultClass(resultClass)
1✔
321
            .setResultType(resultClass)
1✔
322
            .build();
1✔
323

324
    return startUpdate(options, args);
1✔
325
  }
326

327
  @Override
328
  public <R> UpdateHandle<R> startUpdate(UpdateOptions<R> options, Object... args) {
329
    checkStarted();
1✔
330
    options.validate();
1✔
331
    WorkflowExecution targetExecution = execution.get();
1✔
332
    try {
333
      WorkflowClientCallsInterceptor.StartUpdateOutput<R> result =
1✔
334
          workflowClientInvoker.startUpdate(
1✔
335
              new WorkflowClientCallsInterceptor.StartUpdateInput<>(
336
                  targetExecution,
337
                  options.getUpdateName(),
1✔
338
                  Header.empty(),
1✔
339
                  options.getUpdateId(),
1✔
340
                  args,
341
                  options.getResultClass(),
1✔
342
                  options.getResultType(),
1✔
343
                  options.getFirstExecutionRunId(),
1✔
344
                  WaitPolicy.newBuilder()
1✔
345
                      .setLifecycleStage(options.getWaitPolicy().getProto())
1✔
346
                      .build()));
1✔
347

348
      if (result.hasResult()) {
1✔
349
        return new CompletedUpdateHandleImpl<>(
1✔
350
            result.getReference().getUpdateId(),
1✔
351
            result.getReference().getWorkflowExecution(),
1✔
352
            result.getResult());
1✔
353
      } else {
354
        LazyUpdateHandleImpl<R> handle =
1✔
355
            new LazyUpdateHandleImpl<>(
356
                workflowClientInvoker,
357
                workflowType.orElse(null),
1✔
358
                options.getUpdateName(),
1✔
359
                result.getReference().getUpdateId(),
1✔
360
                result.getReference().getWorkflowExecution(),
1✔
361
                options.getResultClass(),
1✔
362
                options.getResultType());
1✔
363
        if (options.getWaitPolicy() == WorkflowUpdateStage.COMPLETED) {
1✔
364
          // Don't return the handle until completed, since that's what's been asked for
NEW
365
          handle.waitCompleted();
×
366
        }
367
        return handle;
1✔
368
      }
369
    } catch (Exception e) {
1✔
370
      Throwable throwable = throwAsWorkflowFailureException(e, targetExecution);
1✔
371
      throw new WorkflowServiceException(targetExecution, workflowType.orElse(null), throwable);
1✔
372
    }
373
  }
374

375
  @Override
376
  public <R> UpdateHandle<R> getUpdateHandle(String updateId, Class<R> resultClass) {
377
    return new LazyUpdateHandleImpl<>(
1✔
378
        workflowClientInvoker,
379
        workflowType.orElse(null),
1✔
380
        "",
381
        updateId,
382
        execution.get(),
1✔
383
        resultClass,
384
        resultClass);
385
  }
386

387
  @Override
388
  public <R> UpdateHandle<R> getUpdateHandle(
389
      String updateId, Class<R> resultClass, Type resultType) {
390
    return new LazyUpdateHandleImpl<>(
×
391
        workflowClientInvoker,
392
        workflowType.orElse(null),
×
393
        "",
394
        updateId,
395
        execution.get(),
×
396
        resultClass,
397
        resultType);
398
  }
399

400
  @Override
401
  public void cancel() {
402
    checkStarted();
1✔
403
    WorkflowExecution targetExecution = currentExecutionWithoutRunId();
1✔
404
    try {
405
      workflowClientInvoker.cancel(new WorkflowClientCallsInterceptor.CancelInput(targetExecution));
1✔
406
    } catch (Exception e) {
1✔
407
      Throwable failure = throwAsWorkflowFailureException(e, targetExecution);
×
408
      throw new WorkflowServiceException(targetExecution, workflowType.orElse(null), failure);
×
409
    }
1✔
410
  }
1✔
411

412
  @Override
413
  public void terminate(@Nullable String reason, Object... details) {
414
    checkStarted();
1✔
415
    WorkflowExecution targetExecution = currentExecutionWithoutRunId();
1✔
416
    try {
417
      workflowClientInvoker.terminate(
1✔
418
          new WorkflowClientCallsInterceptor.TerminateInput(targetExecution, reason, details));
419
    } catch (Exception e) {
1✔
420
      Throwable failure = throwAsWorkflowFailureException(e, targetExecution);
×
421
      throw new WorkflowServiceException(targetExecution, workflowType.orElse(null), failure);
×
422
    }
1✔
423
  }
1✔
424

425
  @Override
426
  public Optional<WorkflowOptions> getOptions() {
427
    return Optional.ofNullable(options);
1✔
428
  }
429

430
  private void checkStarted() {
431
    if (execution.get() == null || execution.get().getWorkflowId() == null) {
1✔
432
      throw new IllegalStateException("Null workflowId. Was workflow started?");
×
433
    }
434
  }
1✔
435

436
  private void checkExecutionIsNotStarted() {
437
    if (execution.get() != null) {
1✔
438
      throw new IllegalStateException(
1✔
439
          "Cannot reuse a stub instance to start more than one workflow execution. The stub "
440
              + "points to already started execution. If you are trying to wait for a workflow completion either "
441
              + "change WorkflowIdReusePolicy from AllowDuplicate or use WorkflowStub.getResult");
442
    }
443
  }
1✔
444

445
  /*
446
   * Exceptions handling and processing for all methods of the stub
447
   */
448
  private RuntimeException wrapStartException(
449
      String workflowId, String workflowType, StatusRuntimeException e) {
450
    WorkflowExecution.Builder executionBuilder =
451
        WorkflowExecution.newBuilder().setWorkflowId(workflowId);
1✔
452

453
    WorkflowExecutionAlreadyStartedFailure f =
1✔
454
        StatusUtils.getFailure(e, WorkflowExecutionAlreadyStartedFailure.class);
1✔
455
    if (f != null) {
1✔
456
      WorkflowExecution exe = executionBuilder.setRunId(f.getRunId()).build();
1✔
457
      populateExecutionAfterStart(exe);
1✔
458
      return new WorkflowExecutionAlreadyStarted(exe, workflowType, e);
1✔
459
    } else {
460
      WorkflowExecution exe = executionBuilder.build();
1✔
461
      return new WorkflowServiceException(exe, workflowType, e);
1✔
462
    }
463
  }
464

465
  /**
466
   * RunId can change e.g. workflow does ContinueAsNew. Emptying runId in workflowExecution allows
467
   * Temporal server figure out the current run id dynamically.
468
   */
469
  private WorkflowExecution currentExecutionWithoutRunId() {
470
    WorkflowExecution workflowExecution = execution.get();
1✔
471
    if (Strings.isNullOrEmpty(workflowExecution.getRunId())) {
1✔
472
      return workflowExecution;
1✔
473
    } else {
474
      return WorkflowExecution.newBuilder(workflowExecution).setRunId("").build();
1✔
475
    }
476
  }
477

478
  private <R> R throwAsWorkflowFailureExceptionForQuery(
479
      Throwable failure,
480
      @SuppressWarnings("unused") Class<R> returnType,
481
      WorkflowExecution targetExecution) {
482
    failure = throwAsWorkflowFailureException(failure, targetExecution);
1✔
483
    if (failure instanceof StatusRuntimeException) {
1✔
484
      StatusRuntimeException sre = (StatusRuntimeException) failure;
1✔
485
      if (StatusUtils.hasFailure(sre, QueryFailedFailure.class)) {
1✔
486
        throw new WorkflowQueryException(execution.get(), workflowType.orElse(null), failure);
1✔
487
      } else if (Status.Code.FAILED_PRECONDITION.equals(sre.getStatus().getCode())
×
488
          && StatusUtils.hasFailure(sre, WorkflowNotReadyFailure.class)) {
×
489
        // Processes the edge case introduced by https://github.com/temporalio/temporal/pull/2826
490
        throw new WorkflowQueryRejectedException(
×
491
            targetExecution, workflowType.orElse(null), failure);
×
492
      }
493
    }
494
    throw new WorkflowServiceException(targetExecution, workflowType.orElse(null), failure);
×
495
  }
496

497
  // This function never returns anything, it only throws
498
  private <R> R throwAsWorkflowFailureExceptionForResult(
499
      Throwable failure,
500
      @SuppressWarnings("unused") Class<R> returnType,
501
      WorkflowExecution targetExecution)
502
      throws TimeoutException {
503
    failure = throwAsWorkflowFailureException(failure, targetExecution);
1✔
504
    if (failure instanceof TimeoutException) {
1✔
505
      throw (TimeoutException) failure;
1✔
506
    } else if (failure instanceof CanceledFailure) {
1✔
507
      throw (CanceledFailure) failure;
×
508
    }
509
    throw new WorkflowServiceException(targetExecution, workflowType.orElse(null), failure);
1✔
510
  }
511

512
  private Throwable throwAsWorkflowFailureException(
513
      Throwable failure, WorkflowExecution targetExecution) {
514
    if (failure instanceof CompletionException) {
1✔
515
      // if we work with CompletableFuture, the exception may be wrapped into CompletionException
516
      failure = failure.getCause();
1✔
517
    }
518
    failure = CheckedExceptionWrapper.unwrap(failure);
1✔
519
    if (failure instanceof Error) {
1✔
520
      throw (Error) failure;
×
521
    }
522
    if (failure instanceof StatusRuntimeException) {
1✔
523
      StatusRuntimeException sre = (StatusRuntimeException) failure;
1✔
524
      if (Status.Code.NOT_FOUND.equals(sre.getStatus().getCode())) {
1✔
525
        throw new WorkflowNotFoundException(targetExecution, workflowType.orElse(null), sre);
1✔
526
      }
527
    } else if (failure instanceof WorkflowException) {
1✔
528
      throw (WorkflowException) failure;
1✔
529
    }
530
    return failure;
1✔
531
  }
532

533
  private void populateExecutionAfterStart(WorkflowExecution startedExecution) {
534
    this.startedExecution.set(startedExecution);
1✔
535
    // bind to an execution without a runId, so queries follow runId chains by default
536
    this.execution.set(WorkflowExecution.newBuilder(startedExecution).setRunId("").build());
1✔
537
  }
1✔
538
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc