Skip to content

Commit 03f7182

Browse files
Add support for user meta data (#2218)
Add support for user metadata on certain events
1 parent 2163b8f commit 03f7182

29 files changed

+621
-41
lines changed

temporal-sdk/src/main/java/io/temporal/client/WorkflowOptions.java

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,7 @@
2323
import com.google.common.base.Objects;
2424
import io.temporal.api.enums.v1.WorkflowIdConflictPolicy;
2525
import io.temporal.api.enums.v1.WorkflowIdReusePolicy;
26-
import io.temporal.common.CronSchedule;
27-
import io.temporal.common.MethodRetry;
28-
import io.temporal.common.RetryOptions;
29-
import io.temporal.common.SearchAttributes;
26+
import io.temporal.common.*;
3027
import io.temporal.common.context.ContextPropagator;
3128
import io.temporal.internal.common.OptionsUtils;
3229
import io.temporal.worker.WorkerFactory;
@@ -79,6 +76,8 @@ public static WorkflowOptions merge(
7976
.setDisableEagerExecution(o.isDisableEagerExecution())
8077
.setStartDelay(o.getStartDelay())
8178
.setWorkflowIdConflictPolicy(o.getWorkflowIdConflictPolicy())
79+
.setStaticSummary(o.getStaticSummary())
80+
.setStaticDetails(o.getStaticDetails())
8281
.validateBuildWithDefaults();
8382
}
8483

@@ -114,6 +113,10 @@ public static final class Builder {
114113

115114
private WorkflowIdConflictPolicy workflowIdConflictpolicy;
116115

116+
private String staticSummary;
117+
118+
private String staticDetails;
119+
117120
private Builder() {}
118121

119122
private Builder(WorkflowOptions options) {
@@ -135,6 +138,8 @@ private Builder(WorkflowOptions options) {
135138
this.disableEagerExecution = options.disableEagerExecution;
136139
this.startDelay = options.startDelay;
137140
this.workflowIdConflictpolicy = options.workflowIdConflictpolicy;
141+
this.staticSummary = options.staticSummary;
142+
this.staticDetails = options.staticDetails;
138143
}
139144

140145
/**
@@ -382,6 +387,31 @@ public Builder setStartDelay(Duration startDelay) {
382387
return this;
383388
}
384389

390+
/**
391+
* Single-line fixed summary for this workflow execution that will appear in UI/CLI. This can be
392+
* in single-line Temporal Markdown format.
393+
*
394+
* <p>Default is none/empty.
395+
*/
396+
@Experimental
397+
public Builder setStaticSummary(String staticSummary) {
398+
this.staticSummary = staticSummary;
399+
return this;
400+
}
401+
402+
/**
403+
* General fixed details for this workflow execution that will appear in UI/CLI. This can be in
404+
* Temporal Markdown format and can span multiple lines. This is a fixed value on the workflow
405+
* that cannot be updated.
406+
*
407+
* <p>Default is none/empty.
408+
*/
409+
@Experimental
410+
public Builder setStaticDetails(String staticDetails) {
411+
this.staticDetails = staticDetails;
412+
return this;
413+
}
414+
385415
public WorkflowOptions build() {
386416
return new WorkflowOptions(
387417
workflowId,
@@ -398,7 +428,9 @@ public WorkflowOptions build() {
398428
contextPropagators,
399429
disableEagerExecution,
400430
startDelay,
401-
workflowIdConflictpolicy);
431+
workflowIdConflictpolicy,
432+
staticSummary,
433+
staticDetails);
402434
}
403435

404436
/**
@@ -420,7 +452,9 @@ public WorkflowOptions validateBuildWithDefaults() {
420452
contextPropagators,
421453
disableEagerExecution,
422454
startDelay,
423-
workflowIdConflictpolicy);
455+
workflowIdConflictpolicy,
456+
staticSummary,
457+
staticDetails);
424458
}
425459
}
426460

@@ -454,6 +488,10 @@ public WorkflowOptions validateBuildWithDefaults() {
454488

455489
private final WorkflowIdConflictPolicy workflowIdConflictpolicy;
456490

491+
private final String staticSummary;
492+
493+
private final String staticDetails;
494+
457495
private WorkflowOptions(
458496
String workflowId,
459497
WorkflowIdReusePolicy workflowIdReusePolicy,
@@ -469,7 +507,9 @@ private WorkflowOptions(
469507
List<ContextPropagator> contextPropagators,
470508
boolean disableEagerExecution,
471509
Duration startDelay,
472-
WorkflowIdConflictPolicy workflowIdConflictpolicy) {
510+
WorkflowIdConflictPolicy workflowIdConflictpolicy,
511+
String staticSummary,
512+
String staticDetails) {
473513
this.workflowId = workflowId;
474514
this.workflowIdReusePolicy = workflowIdReusePolicy;
475515
this.workflowRunTimeout = workflowRunTimeout;
@@ -485,6 +525,8 @@ private WorkflowOptions(
485525
this.disableEagerExecution = disableEagerExecution;
486526
this.startDelay = startDelay;
487527
this.workflowIdConflictpolicy = workflowIdConflictpolicy;
528+
this.staticSummary = staticSummary;
529+
this.staticDetails = staticDetails;
488530
}
489531

490532
public String getWorkflowId() {
@@ -556,6 +598,14 @@ public WorkflowIdConflictPolicy getWorkflowIdConflictPolicy() {
556598
return workflowIdConflictpolicy;
557599
}
558600

601+
public String getStaticSummary() {
602+
return staticSummary;
603+
}
604+
605+
public String getStaticDetails() {
606+
return staticDetails;
607+
}
608+
559609
public Builder toBuilder() {
560610
return new Builder(this);
561611
}
@@ -579,7 +629,9 @@ public boolean equals(Object o) {
579629
&& Objects.equal(contextPropagators, that.contextPropagators)
580630
&& Objects.equal(disableEagerExecution, that.disableEagerExecution)
581631
&& Objects.equal(startDelay, that.startDelay)
582-
&& Objects.equal(workflowIdConflictpolicy, that.workflowIdConflictpolicy);
632+
&& Objects.equal(workflowIdConflictpolicy, that.workflowIdConflictpolicy)
633+
&& Objects.equal(staticSummary, that.staticSummary)
634+
&& Objects.equal(staticDetails, that.staticDetails);
583635
}
584636

585637
@Override
@@ -599,7 +651,9 @@ public int hashCode() {
599651
contextPropagators,
600652
disableEagerExecution,
601653
startDelay,
602-
workflowIdConflictpolicy);
654+
workflowIdConflictpolicy,
655+
staticSummary,
656+
staticDetails);
603657
}
604658

605659
@Override
@@ -638,6 +692,10 @@ public String toString() {
638692
+ startDelay
639693
+ ", workflowIdConflictpolicy="
640694
+ workflowIdConflictpolicy
695+
+ ", staticSummary="
696+
+ staticSummary
697+
+ ", staticDetails="
698+
+ staticDetails
641699
+ '}';
642700
}
643701
}

temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptor.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,8 @@ public DynamicUpdateHandler getHandler() {
588588

589589
Promise<Void> newTimer(Duration duration);
590590

591+
Promise<Void> newTimer(Duration duration, TimerOptions options);
592+
591593
<R> R sideEffect(Class<R> resultClass, Type resultType, Func<R> func);
592594

593595
<R> R mutableSideEffect(

temporal-sdk/src/main/java/io/temporal/common/interceptors/WorkflowOutboundCallsInterceptorBase.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import io.temporal.common.SearchAttributeUpdate;
2424
import io.temporal.workflow.Functions.Func;
2525
import io.temporal.workflow.Promise;
26+
import io.temporal.workflow.TimerOptions;
2627
import java.lang.reflect.Type;
2728
import java.time.Duration;
2829
import java.util.Map;
@@ -90,6 +91,11 @@ public Promise<Void> newTimer(Duration duration) {
9091
return next.newTimer(duration);
9192
}
9293

94+
@Override
95+
public Promise<Void> newTimer(Duration duration, TimerOptions options) {
96+
return next.newTimer(duration, options);
97+
}
98+
9399
@Override
94100
public <R> R sideEffect(Class<R> resultClass, Type resultType, Func<R> func) {
95101
return next.sideEffect(resultClass, resultType, func);

temporal-sdk/src/main/java/io/temporal/internal/client/RootWorkflowClientInvoker.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
package io.temporal.internal.client;
2222

2323
import static io.temporal.internal.common.HeaderUtils.intoPayloadMap;
24+
import static io.temporal.internal.common.WorkflowExecutionUtils.makeUserMetaData;
2425

2526
import io.grpc.Deadline;
2627
import io.grpc.Status;
@@ -29,6 +30,7 @@
2930
import io.temporal.api.enums.v1.UpdateWorkflowExecutionLifecycleStage;
3031
import io.temporal.api.enums.v1.WorkflowExecutionStatus;
3132
import io.temporal.api.query.v1.WorkflowQuery;
33+
import io.temporal.api.sdk.v1.UserMetadata;
3234
import io.temporal.api.update.v1.*;
3335
import io.temporal.api.workflowservice.v1.*;
3436
import io.temporal.client.*;
@@ -86,14 +88,22 @@ public WorkflowStartOutput start(WorkflowStartInput input) {
8688
.build()
8789
: null;
8890

91+
@Nullable
92+
UserMetadata userMetadata =
93+
makeUserMetaData(
94+
input.getOptions().getStaticSummary(),
95+
input.getOptions().getStaticDetails(),
96+
dataConverterWithWorkflowContext);
97+
8998
StartWorkflowExecutionRequest.Builder request =
9099
requestsHelper.newStartWorkflowExecutionRequest(
91100
input.getWorkflowId(),
92101
input.getWorkflowType(),
93102
input.getHeader(),
94103
input.getOptions(),
95104
inputArgs.orElse(null),
96-
memo);
105+
memo,
106+
userMetadata);
97107
try (@Nullable WorkflowTaskDispatchHandle eagerDispatchHandle = obtainDispatchHandle(input)) {
98108
boolean requestEagerExecution = eagerDispatchHandle != null;
99109
request.setRequestEagerExecution(requestEagerExecution);
@@ -173,14 +183,22 @@ public WorkflowSignalWithStartOutput signalWithStart(WorkflowSignalWithStartInpu
173183
.build()
174184
: null;
175185

186+
@Nullable
187+
UserMetadata userMetadata =
188+
makeUserMetaData(
189+
workflowStartInput.getOptions().getStaticSummary(),
190+
workflowStartInput.getOptions().getStaticDetails(),
191+
dataConverterWithWorkflowContext);
192+
176193
StartWorkflowExecutionRequestOrBuilder startRequest =
177194
requestsHelper.newStartWorkflowExecutionRequest(
178195
workflowStartInput.getWorkflowId(),
179196
workflowStartInput.getWorkflowType(),
180197
workflowStartInput.getHeader(),
181198
workflowStartInput.getOptions(),
182199
workflowInput.orElse(null),
183-
memo);
200+
memo,
201+
userMetadata);
184202

185203
Optional<Payloads> signalInput =
186204
dataConverterWithWorkflowContext.toPayloads(input.getSignalArguments());

temporal-sdk/src/main/java/io/temporal/internal/client/ScheduleProtoUtil.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
import static io.temporal.internal.common.HeaderUtils.toHeaderGrpc;
2424
import static io.temporal.internal.common.RetryOptionsUtils.toRetryPolicy;
25+
import static io.temporal.internal.common.WorkflowExecutionUtils.makeUserMetaData;
2526

2627
import com.google.common.base.MoreObjects;
2728
import com.google.common.base.Preconditions;
@@ -33,6 +34,7 @@
3334
import io.temporal.api.schedule.v1.ScheduleInfo;
3435
import io.temporal.api.schedule.v1.ScheduleSpec;
3536
import io.temporal.api.schedule.v1.ScheduleState;
37+
import io.temporal.api.sdk.v1.UserMetadata;
3638
import io.temporal.api.taskqueue.v1.TaskQueue;
3739
import io.temporal.api.workflow.v1.NewWorkflowExecutionInfo;
3840
import io.temporal.client.WorkflowOptions;
@@ -160,6 +162,16 @@ public ScheduleAction actionToProto(io.temporal.client.schedules.ScheduleAction
160162
SearchAttributesUtil.encodeTyped(wfOptions.getTypedSearchAttributes()));
161163
}
162164

165+
@Nullable
166+
UserMetadata userMetadata =
167+
makeUserMetaData(
168+
wfOptions.getStaticSummary(),
169+
wfOptions.getStaticDetails(),
170+
dataConverterWithWorkflowContext);
171+
if (userMetadata != null) {
172+
workflowRequest.setUserMetadata(userMetadata);
173+
}
174+
163175
Header grpcHeader =
164176
toHeaderGrpc(
165177
startWorkflowAction.getHeader(),
@@ -460,6 +472,15 @@ public io.temporal.client.schedules.ScheduleAction protoToAction(@Nonnull Schedu
460472
SearchAttributesUtil.decodeTyped(startWfAction.getSearchAttributes()));
461473
}
462474

475+
if (startWfAction.hasUserMetadata()) {
476+
wfOptionsBuilder.setStaticSummary(
477+
dataConverterWithWorkflowContext.fromPayload(
478+
startWfAction.getUserMetadata().getSummary(), String.class, String.class));
479+
wfOptionsBuilder.setStaticDetails(
480+
dataConverterWithWorkflowContext.fromPayload(
481+
startWfAction.getUserMetadata().getDetails(), String.class, String.class));
482+
}
483+
463484
builder.setOptions(wfOptionsBuilder.build());
464485
return builder.build();
465486
}

temporal-sdk/src/main/java/io/temporal/internal/client/WorkflowClientRequestFactory.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import com.google.protobuf.ByteString;
2929
import io.temporal.api.common.v1.*;
3030
import io.temporal.api.enums.v1.HistoryEventFilterType;
31+
import io.temporal.api.sdk.v1.UserMetadata;
3132
import io.temporal.api.taskqueue.v1.TaskQueue;
3233
import io.temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryRequest;
3334
import io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest;
@@ -59,7 +60,8 @@ StartWorkflowExecutionRequest.Builder newStartWorkflowExecutionRequest(
5960
@Nonnull io.temporal.common.interceptors.Header header,
6061
@Nonnull WorkflowOptions options,
6162
@Nullable Payloads inputArgs,
62-
@Nullable Memo memo) {
63+
@Nullable Memo memo,
64+
@Nullable UserMetadata userMetadata) {
6365
StartWorkflowExecutionRequest.Builder request =
6466
StartWorkflowExecutionRequest.newBuilder()
6567
.setNamespace(clientOptions.getNamespace())
@@ -108,6 +110,10 @@ StartWorkflowExecutionRequest.Builder newStartWorkflowExecutionRequest(
108110
request.setWorkflowStartDelay(ProtobufTimeUtils.toProtoDuration(options.getStartDelay()));
109111
}
110112

113+
if (userMetadata != null) {
114+
request.setUserMetadata(userMetadata);
115+
}
116+
111117
if (options.getSearchAttributes() != null && !options.getSearchAttributes().isEmpty()) {
112118
if (options.getTypedSearchAttributes() != null) {
113119
throw new IllegalArgumentException(
@@ -183,6 +189,10 @@ SignalWithStartWorkflowExecutionRequest.Builder newSignalWithStartWorkflowExecut
183189
request.setWorkflowStartDelay(startParameters.getWorkflowStartDelay());
184190
}
185191

192+
if (startParameters.hasUserMetadata()) {
193+
request.setUserMetadata(startParameters.getUserMetadata());
194+
}
195+
186196
return request;
187197
}
188198

temporal-sdk/src/main/java/io/temporal/internal/common/WorkflowExecutionUtils.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import io.temporal.api.enums.v1.TimeoutType;
3434
import io.temporal.api.enums.v1.WorkflowExecutionStatus;
3535
import io.temporal.api.history.v1.*;
36+
import io.temporal.api.sdk.v1.UserMetadata;
3637
import io.temporal.api.workflowservice.v1.PollWorkflowTaskQueueResponseOrBuilder;
3738
import io.temporal.client.WorkflowFailedException;
3839
import io.temporal.common.converter.DataConverter;
@@ -240,6 +241,21 @@ public static WorkflowExecutionStatus getCloseStatus(HistoryEvent event) {
240241
}
241242
}
242243

244+
public static UserMetadata makeUserMetaData(String summary, String details, DataConverter dc) {
245+
if (summary == null && details == null) {
246+
return null;
247+
}
248+
249+
UserMetadata.Builder builder = UserMetadata.newBuilder();
250+
if (summary != null) {
251+
builder.setSummary(dc.toPayload(summary).get());
252+
}
253+
if (details != null) {
254+
builder.setDetails(dc.toPayload(details).get());
255+
}
256+
return builder.build();
257+
}
258+
243259
public static String prettyPrintCommands(Iterable<Command> commands) {
244260
StringBuilder result = new StringBuilder();
245261
for (Command command : commands) {

0 commit comments

Comments
 (0)