27
27
import io .temporal .common .interceptors .WorkflowOutboundCallsInterceptor ;
28
28
import io .temporal .common .interceptors .WorkflowOutboundCallsInterceptorBase ;
29
29
import io .temporal .opentracing .OpenTracingOptions ;
30
+ import io .temporal .workflow .Functions ;
31
+ import io .temporal .workflow .Promise ;
30
32
import io .temporal .workflow .Workflow ;
31
33
import io .temporal .workflow .WorkflowInfo ;
32
34
import io .temporal .workflow .unsafe .WorkflowUnsafe ;
35
+ import java .util .concurrent .Executor ;
36
+ import java .util .concurrent .TimeUnit ;
37
+ import java .util .concurrent .TimeoutException ;
33
38
34
39
public class OpenTracingWorkflowOutboundCallsInterceptor
35
40
extends WorkflowOutboundCallsInterceptorBase {
36
41
private final SpanFactory spanFactory ;
37
42
private final Tracer tracer ;
38
43
private final ContextAccessor contextAccessor ;
39
44
45
+ private class SpanTransferringExecutor implements Executor {
46
+ private final Executor passthrough ;
47
+ private final Span capturedSpan ;
48
+
49
+ public SpanTransferringExecutor (Executor passthrough ) {
50
+ this .passthrough = passthrough ;
51
+ capturedSpan = tracer .scopeManager ().activeSpan ();
52
+ }
53
+
54
+ public void execute (Runnable r ) {
55
+ Span activeSpan = tracer .scopeManager ().activeSpan ();
56
+
57
+ if (activeSpan == null && capturedSpan != null ) {
58
+ // if there is no activeSpan AND we captured a span during construction,
59
+ // we should transfer it to the calling context as the new active span
60
+ try (Scope ignored = tracer .scopeManager ().activate (capturedSpan )) {
61
+ passthrough .execute (r );
62
+ }
63
+ } else {
64
+ passthrough .execute (r );
65
+ }
66
+ }
67
+ }
68
+
69
+ private class PromiseWrapper <R > implements Promise <R > {
70
+ private final Span capturedSpan ;
71
+ private final Promise <R > delegate ;
72
+
73
+ PromiseWrapper (Span capturedSpan , Promise <R > delegate ) {
74
+ this .capturedSpan = capturedSpan ;
75
+ this .delegate = delegate ;
76
+ }
77
+
78
+ @ Override
79
+ public boolean isCompleted () {
80
+ return delegate .isCompleted ();
81
+ }
82
+
83
+ @ Override
84
+ public R get () {
85
+ return delegate .get ();
86
+ }
87
+
88
+ @ Override
89
+ public R cancellableGet () {
90
+ return delegate .cancellableGet ();
91
+ }
92
+
93
+ @ Override
94
+ public R get (long timeout , TimeUnit unit ) throws TimeoutException {
95
+ return delegate .get (timeout , unit );
96
+ }
97
+
98
+ @ Override
99
+ public R cancellableGet (long timeout , TimeUnit unit ) throws TimeoutException {
100
+ return delegate .cancellableGet (timeout , unit );
101
+ }
102
+
103
+ @ Override
104
+ public RuntimeException getFailure () {
105
+ return delegate .getFailure ();
106
+ }
107
+
108
+ @ Override
109
+ public <U > Promise <U > thenApply (Functions .Func1 <? super R , ? extends U > fn ) {
110
+ return delegate .thenApply (
111
+ (r ) -> {
112
+ if (capturedSpan != null ) {
113
+ try (Scope ignored = tracer .scopeManager ().activate (capturedSpan )) {
114
+ return fn .apply (r );
115
+ }
116
+ } else {
117
+ return fn .apply (r );
118
+ }
119
+ });
120
+ }
121
+
122
+ @ Override
123
+ public <U > Promise <U > handle (Functions .Func2 <? super R , RuntimeException , ? extends U > fn ) {
124
+ return delegate .handle (
125
+ (r , e ) -> {
126
+ if (capturedSpan != null ) {
127
+ try (Scope ignored = tracer .scopeManager ().activate (capturedSpan )) {
128
+ return fn .apply (r , e );
129
+ }
130
+ } else {
131
+ return fn .apply (r , e );
132
+ }
133
+ });
134
+ }
135
+
136
+ @ Override
137
+ public <U > Promise <U > thenCompose (Functions .Func1 <? super R , ? extends Promise <U >> fn ) {
138
+ return delegate .thenCompose (
139
+ (R r ) -> {
140
+ if (capturedSpan != null ) {
141
+ try (Scope ignored = tracer .scopeManager ().activate (capturedSpan )) {
142
+ return fn .apply (r );
143
+ }
144
+ } else {
145
+ return fn .apply (r );
146
+ }
147
+ });
148
+ }
149
+
150
+ @ Override
151
+ public Promise <R > exceptionally (Functions .Func1 <Throwable , ? extends R > fn ) {
152
+ return delegate .exceptionally (
153
+ (Throwable t ) -> {
154
+ if (capturedSpan != null ) {
155
+ try (Scope ignored = tracer .scopeManager ().activate (capturedSpan )) {
156
+ return fn .apply (t );
157
+ }
158
+ } else {
159
+ return fn .apply (t );
160
+ }
161
+ });
162
+ }
163
+ }
164
+
40
165
public OpenTracingWorkflowOutboundCallsInterceptor (
41
166
WorkflowOutboundCallsInterceptor next ,
42
167
OpenTracingOptions options ,
@@ -51,13 +176,16 @@ public OpenTracingWorkflowOutboundCallsInterceptor(
51
176
@ Override
52
177
public <R > ActivityOutput <R > executeActivity (ActivityInput <R > input ) {
53
178
if (!WorkflowUnsafe .isReplaying ()) {
179
+ Span capturedSpan = tracer .scopeManager ().activeSpan ();
54
180
Span activityStartSpan =
55
181
contextAccessor .writeSpanContextToHeader (
56
182
() -> createActivityStartSpanBuilder (input .getActivityName ()).start (),
57
183
input .getHeader (),
58
184
tracer );
59
185
try (Scope ignored = tracer .scopeManager ().activate (activityStartSpan )) {
60
- return super .executeActivity (input );
186
+ ActivityOutput <R > output = super .executeActivity (input );
187
+ return new ActivityOutput <>(
188
+ output .getActivityId (), new PromiseWrapper <>(capturedSpan , output .getResult ()));
61
189
} finally {
62
190
activityStartSpan .finish ();
63
191
}
@@ -69,13 +197,15 @@ public <R> ActivityOutput<R> executeActivity(ActivityInput<R> input) {
69
197
@ Override
70
198
public <R > LocalActivityOutput <R > executeLocalActivity (LocalActivityInput <R > input ) {
71
199
if (!WorkflowUnsafe .isReplaying ()) {
200
+ Span capturedSpan = tracer .scopeManager ().activeSpan ();
72
201
Span activityStartSpan =
73
202
contextAccessor .writeSpanContextToHeader (
74
203
() -> createActivityStartSpanBuilder (input .getActivityName ()).start (),
75
204
input .getHeader (),
76
205
tracer );
77
206
try (Scope ignored = tracer .scopeManager ().activate (activityStartSpan )) {
78
- return super .executeLocalActivity (input );
207
+ LocalActivityOutput <R > output = super .executeLocalActivity (input );
208
+ return new LocalActivityOutput <>(new PromiseWrapper <>(capturedSpan , output .getResult ()));
79
209
} finally {
80
210
activityStartSpan .finish ();
81
211
}
@@ -87,11 +217,14 @@ public <R> LocalActivityOutput<R> executeLocalActivity(LocalActivityInput<R> inp
87
217
@ Override
88
218
public <R > ChildWorkflowOutput <R > executeChildWorkflow (ChildWorkflowInput <R > input ) {
89
219
if (!WorkflowUnsafe .isReplaying ()) {
220
+ Span capturedSpan = tracer .scopeManager ().activeSpan ();
90
221
Span childWorkflowStartSpan =
91
222
contextAccessor .writeSpanContextToHeader (
92
223
() -> createChildWorkflowStartSpanBuilder (input ).start (), input .getHeader (), tracer );
93
224
try (Scope ignored = tracer .scopeManager ().activate (childWorkflowStartSpan )) {
94
- return super .executeChildWorkflow (input );
225
+ ChildWorkflowOutput <R > output = super .executeChildWorkflow (input );
226
+ return new ChildWorkflowOutput <>(
227
+ new PromiseWrapper <>(capturedSpan , output .getResult ()), output .getWorkflowExecution ());
95
228
} finally {
96
229
childWorkflowStartSpan .finish ();
97
230
}
@@ -104,13 +237,16 @@ public <R> ChildWorkflowOutput<R> executeChildWorkflow(ChildWorkflowInput<R> inp
104
237
public <R > ExecuteNexusOperationOutput <R > executeNexusOperation (
105
238
ExecuteNexusOperationInput <R > input ) {
106
239
if (!WorkflowUnsafe .isReplaying ()) {
240
+ Span capturedSpan = tracer .scopeManager ().activeSpan ();
107
241
Span nexusOperationExecuteSpan =
108
242
contextAccessor .writeSpanContextToHeader (
109
243
() -> createStartNexusOperationSpanBuilder (input ).start (),
110
244
input .getHeaders (),
111
245
tracer );
112
246
try (Scope ignored = tracer .scopeManager ().activate (nexusOperationExecuteSpan )) {
113
- return super .executeNexusOperation (input );
247
+ ExecuteNexusOperationOutput <R > output = super .executeNexusOperation (input );
248
+ return new ExecuteNexusOperationOutput <>(
249
+ new PromiseWrapper <>(capturedSpan , output .getResult ()), output .getOperationExecution ());
114
250
} finally {
115
251
nexusOperationExecuteSpan .finish ();
116
252
}
@@ -122,6 +258,7 @@ public <R> ExecuteNexusOperationOutput<R> executeNexusOperation(
122
258
@ Override
123
259
public SignalExternalOutput signalExternalWorkflow (SignalExternalInput input ) {
124
260
if (!WorkflowUnsafe .isReplaying ()) {
261
+ Span capturedSpan = tracer .scopeManager ().activeSpan ();
125
262
WorkflowInfo workflowInfo = Workflow .getInfo ();
126
263
Span childWorkflowStartSpan =
127
264
contextAccessor .writeSpanContextToHeader (
@@ -136,7 +273,8 @@ public SignalExternalOutput signalExternalWorkflow(SignalExternalInput input) {
136
273
input .getHeader (),
137
274
tracer );
138
275
try (Scope ignored = tracer .scopeManager ().activate (childWorkflowStartSpan )) {
139
- return super .signalExternalWorkflow (input );
276
+ SignalExternalOutput output = super .signalExternalWorkflow (input );
277
+ return new SignalExternalOutput (new PromiseWrapper <>(capturedSpan , output .getResult ()));
140
278
} finally {
141
279
childWorkflowStartSpan .finish ();
142
280
}
@@ -178,6 +316,12 @@ public Object newChildThread(Runnable runnable, boolean detached, String name) {
178
316
return super .newChildThread (wrappedRunnable , detached , name );
179
317
}
180
318
319
+ @ Override
320
+ public Executor newCallbackExecutor () {
321
+ Executor passthrough = super .newCallbackExecutor ();
322
+ return new SpanTransferringExecutor (passthrough );
323
+ }
324
+
181
325
private Tracer .SpanBuilder createActivityStartSpanBuilder (String activityName ) {
182
326
WorkflowInfo workflowInfo = Workflow .getInfo ();
183
327
return spanFactory .createActivityStartSpan (
0 commit comments