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

temporalio / sdk-java / #181

pending completion
#181

push

github-actions

web-flow
Properly wrap exceptions from schedule client (#1827)

Wrap schedule exception

37 of 37 new or added lines in 1 file covered. (100.0%)

18557 of 23894 relevant lines covered (77.66%)

0.78 hits per line

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

3.92
/temporal-sdk/src/main/java/io/temporal/internal/client/RootScheduleClientInvoker.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.internal.client;
22

23
import static io.temporal.internal.common.HeaderUtils.intoPayloadMap;
24

25
import com.google.common.collect.Iterators;
26
import io.grpc.Status;
27
import io.grpc.StatusRuntimeException;
28
import io.temporal.api.common.v1.Memo;
29
import io.temporal.api.schedule.v1.*;
30
import io.temporal.api.workflowservice.v1.*;
31
import io.temporal.client.ListScheduleListDescriptionIterator;
32
import io.temporal.client.schedules.*;
33
import io.temporal.common.interceptors.ScheduleClientCallsInterceptor;
34
import io.temporal.internal.client.external.GenericWorkflowClient;
35
import io.temporal.internal.common.ProtobufTimeUtils;
36
import io.temporal.internal.common.SearchAttributesUtil;
37
import java.util.*;
38
import java.util.stream.StreamSupport;
39
import org.slf4j.Logger;
40
import org.slf4j.LoggerFactory;
41

42
public class RootScheduleClientInvoker implements ScheduleClientCallsInterceptor {
43
  private static final Logger log = LoggerFactory.getLogger(RootScheduleClientInvoker.class);
1✔
44

45
  private final GenericWorkflowClient genericClient;
46

47
  private final ScheduleClientOptions clientOptions;
48

49
  private final ScheduleProtoUtil scheduleRequestHeader;
50

51
  public RootScheduleClientInvoker(
52
      GenericWorkflowClient genericClient, ScheduleClientOptions clientOptions) {
1✔
53
    this.genericClient = genericClient;
1✔
54
    this.clientOptions = clientOptions;
1✔
55
    this.scheduleRequestHeader = new ScheduleProtoUtil(genericClient, clientOptions);
1✔
56
  }
1✔
57

58
  @Override
59
  public void createSchedule(CreateScheduleInput input) {
60

61
    CreateScheduleRequest.Builder request =
62
        CreateScheduleRequest.newBuilder()
×
63
            .setIdentity(clientOptions.getIdentity())
×
64
            .setNamespace(clientOptions.getNamespace())
×
65
            .setRequestId(UUID.randomUUID().toString())
×
66
            .setScheduleId(input.getId())
×
67
            .setSchedule(scheduleRequestHeader.scheduleToProto(input.getSchedule()));
×
68

69
    if (input.getOptions().getMemo() != null) {
×
70
      request.setMemo(
×
71
          Memo.newBuilder()
×
72
              .putAllFields(
×
73
                  intoPayloadMap(clientOptions.getDataConverter(), input.getOptions().getMemo())));
×
74
    }
75

76
    if (input.getOptions().getSearchAttributes() != null
×
77
        && !input.getOptions().getSearchAttributes().isEmpty()) {
×
78
      request.setSearchAttributes(
×
79
          SearchAttributesUtil.encode(input.getOptions().getSearchAttributes()));
×
80
    }
81

82
    if (input.getOptions().isTriggerImmediately()
×
83
        || (input.getOptions().getBackfills() != null
×
84
            && input.getOptions().getBackfills().size() > 0)) {
×
85
      SchedulePatch.Builder patchBuilder = SchedulePatch.newBuilder();
×
86

87
      if (input.getOptions().getBackfills() != null) {
×
88
        input.getOptions().getBackfills().stream()
×
89
            .forEach(b -> patchBuilder.addBackfillRequest(backfillToProto(b)));
×
90
      }
91

92
      if (input.getOptions().isTriggerImmediately()) {
×
93
        patchBuilder.setTriggerImmediately(
×
94
            TriggerImmediatelyRequest.newBuilder()
×
95
                .setOverlapPolicy(input.getSchedule().getPolicy().getOverlap())
×
96
                .build());
×
97
      }
98

99
      request.setInitialPatch(patchBuilder.build());
×
100
    }
101

102
    try {
103
      genericClient.createSchedule(request.build());
×
104
    } catch (StatusRuntimeException e) {
×
105
      if (Status.Code.ALREADY_EXISTS.equals(e.getStatus().getCode())) {
×
106
        throw new ScheduleAlreadyRunningException(e);
×
107
      } else {
108
        throw new ScheduleException(e);
×
109
      }
110
    } catch (Exception e) {
×
111
      throw new ScheduleException(e);
×
112
    }
×
113
  }
×
114

115
  @Override
116
  public ListScheduleOutput listSchedules(ListSchedulesInput input) {
117
    ListScheduleListDescriptionIterator iterator =
×
118
        new ListScheduleListDescriptionIterator(
119
            clientOptions.getNamespace(), input.getPageSize(), genericClient);
×
120
    iterator.init();
×
121
    Iterator<ScheduleListDescription> wrappedIterator =
×
122
        Iterators.transform(
×
123
            iterator, entry -> scheduleRequestHeader.protoToScheduleListDescription(entry));
×
124

125
    final int CHARACTERISTICS =
×
126
        Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.NONNULL | Spliterator.IMMUTABLE;
127
    return new ListScheduleOutput(
×
128
        StreamSupport.stream(
×
129
            Spliterators.spliteratorUnknownSize(wrappedIterator, CHARACTERISTICS), false));
×
130
  }
131

132
  public BackfillRequest backfillToProto(ScheduleBackfill backfill) {
133
    return BackfillRequest.newBuilder()
×
134
        .setStartTime(ProtobufTimeUtils.toProtoTimestamp(backfill.getStartAt()))
×
135
        .setEndTime(ProtobufTimeUtils.toProtoTimestamp(backfill.getEndAt()))
×
136
        .setOverlapPolicy(backfill.getOverlapPolicy())
×
137
        .build();
×
138
  }
139

140
  @Override
141
  public void backfillSchedule(BackfillScheduleInput input) {
142
    ArrayList<BackfillRequest> backfillRequests =
×
143
        new ArrayList<BackfillRequest>(input.getBackfills().size());
×
144
    for (ScheduleBackfill backfill : input.getBackfills()) {
×
145
      backfillRequests.add(backfillToProto(backfill));
×
146
    }
×
147

148
    SchedulePatch patch =
149
        SchedulePatch.newBuilder().addAllBackfillRequest(backfillRequests).build();
×
150

151
    PatchScheduleRequest request =
152
        PatchScheduleRequest.newBuilder()
×
153
            .setIdentity(clientOptions.getIdentity())
×
154
            .setNamespace(clientOptions.getNamespace())
×
155
            .setScheduleId(input.getScheduleId())
×
156
            .setPatch(patch)
×
157
            .build();
×
158
    try {
159
      genericClient.patchSchedule(request);
×
160
    } catch (Exception e) {
×
161
      throw new ScheduleException(e);
×
162
    }
×
163
  }
×
164

165
  @Override
166
  public void deleteSchedule(DeleteScheduleInput input) {
167
    DeleteScheduleRequest request =
168
        DeleteScheduleRequest.newBuilder()
×
169
            .setIdentity(clientOptions.getIdentity())
×
170
            .setNamespace(clientOptions.getNamespace())
×
171
            .setScheduleId(input.getScheduleId())
×
172
            .build();
×
173
    try {
174
      genericClient.deleteSchedule(request);
×
175
    } catch (Exception e) {
×
176
      throw new ScheduleException(e);
×
177
    }
×
178
  }
×
179

180
  @Override
181
  public DescribeScheduleOutput describeSchedule(DescribeScheduleInput input) {
182
    DescribeScheduleRequest request =
183
        DescribeScheduleRequest.newBuilder()
×
184
            .setNamespace(clientOptions.getNamespace())
×
185
            .setScheduleId(input.getScheduleId())
×
186
            .build();
×
187

188
    try {
189
      DescribeScheduleResponse response = genericClient.describeSchedule(request);
×
190
      return new DescribeScheduleOutput(
×
191
          new ScheduleDescription(
192
              input.getScheduleId(),
×
193
              scheduleRequestHeader.protoToScheduleInfo(response.getInfo()),
×
194
              scheduleRequestHeader.protoToSchedule(response.getSchedule()),
×
195
              Collections.unmodifiableMap(
×
196
                  SearchAttributesUtil.decode(response.getSearchAttributes())),
×
197
              response.getMemo().getFieldsMap(),
×
198
              clientOptions.getDataConverter()));
×
199
    } catch (Exception e) {
×
200
      throw new ScheduleException(e);
×
201
    }
202
  }
203

204
  @Override
205
  public void pauseSchedule(PauseScheduleInput input) {
206
    SchedulePatch patch = SchedulePatch.newBuilder().setPause(input.getNote()).build();
×
207

208
    PatchScheduleRequest request =
209
        PatchScheduleRequest.newBuilder()
×
210
            .setIdentity(clientOptions.getIdentity())
×
211
            .setNamespace(clientOptions.getNamespace())
×
212
            .setScheduleId(input.getScheduleId())
×
213
            .setPatch(patch)
×
214
            .build();
×
215
    try {
216
      genericClient.patchSchedule(request);
×
217
    } catch (Exception e) {
×
218
      throw new ScheduleException(e);
×
219
    }
×
220
  }
×
221

222
  @Override
223
  public void triggerSchedule(TriggerScheduleInput input) {
224
    TriggerImmediatelyRequest trigger =
225
        TriggerImmediatelyRequest.newBuilder().setOverlapPolicy(input.getOverlapPolicy()).build();
×
226

227
    SchedulePatch patch = SchedulePatch.newBuilder().setTriggerImmediately(trigger).build();
×
228

229
    PatchScheduleRequest request =
230
        PatchScheduleRequest.newBuilder()
×
231
            .setIdentity(clientOptions.getIdentity())
×
232
            .setNamespace(clientOptions.getNamespace())
×
233
            .setScheduleId(input.getScheduleId())
×
234
            .setPatch(patch)
×
235
            .build();
×
236
    try {
237
      genericClient.patchSchedule(request);
×
238
    } catch (Exception e) {
×
239
      throw new ScheduleException(e);
×
240
    }
×
241
  }
×
242

243
  @Override
244
  public void unpauseSchedule(UnpauseScheduleInput input) {
245
    SchedulePatch patch = SchedulePatch.newBuilder().setUnpause(input.getNote()).build();
×
246

247
    PatchScheduleRequest request =
248
        PatchScheduleRequest.newBuilder()
×
249
            .setIdentity(clientOptions.getIdentity())
×
250
            .setNamespace(clientOptions.getNamespace())
×
251
            .setScheduleId(input.getScheduleId())
×
252
            .setPatch(patch)
×
253
            .build();
×
254
    try {
255
      genericClient.patchSchedule(request);
×
256
    } catch (Exception e) {
×
257
      throw new ScheduleException(e);
×
258
    }
×
259
  }
×
260

261
  @Override
262
  public void updateSchedule(UpdateScheduleInput input) {
263
    ScheduleUpdate schedule =
×
264
        input.getUpdater().apply(new ScheduleUpdateInput(input.getDescription()));
×
265
    if (schedule == null) {
×
266
      return;
×
267
    }
268

269
    UpdateScheduleRequest request =
270
        UpdateScheduleRequest.newBuilder()
×
271
            .setNamespace(clientOptions.getNamespace())
×
272
            .setIdentity(clientOptions.getIdentity())
×
273
            .setScheduleId(input.getDescription().getId())
×
274
            .setRequestId(UUID.randomUUID().toString())
×
275
            .setSchedule(scheduleRequestHeader.scheduleToProto(schedule.getSchedule()))
×
276
            .build();
×
277
    try {
278
      genericClient.updateSchedule(request);
×
279
    } catch (Exception e) {
×
280
      throw new ScheduleException(e);
×
281
    }
×
282
  }
×
283
}
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

© 2025 Coveralls, Inc