Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ func (c *valueCtx) Value(key interface{}) interface{} {
return c.Context.Value(key)
}

func spanFromContext(ctx Context) opentracing.SpanContext {
func GetSpanContext(ctx Context) opentracing.SpanContext {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we also expose contextWithSpan or is there another way for users to add their existing context?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now I'm a bit concerned about the determinism if users start a new span inside the workflow.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we don't have a clear story around replay traces. It wouldn't cause non-determinism though. Just weird/duplicate traces potentially.
Are you suggesting to expose the span via GetSpanContext but don't let user set/override the span in the context?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. It's still deterministics. Replay is going to cause issues. We will see multiple child spans if we allow users to set them.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using Sideeffect would work. But is span serializable or recoverable?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure. We can try and see. It sounds like we need to start a new span even for replays but let's discuss that separately.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SpanContext is serializable and should be passed. With that said, we'll require users to start a short-lived new span just to modify spancontext. Please refer the examples in the comments

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added an integration test which works.

val := ctx.Value(activeSpanContextKey)
if sp, ok := val.(opentracing.SpanContext); ok {
return sp
Expand Down
2 changes: 1 addition & 1 deletion internal/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func (t *tracingContextPropagator) InjectFromWorkflow(
hw HeaderWriter,
) error {
// retrieve span from context object
spanContext := spanFromContext(ctx)
spanContext := GetSpanContext(ctx)
if spanContext == nil {
return nil
}
Expand Down
6 changes: 3 additions & 3 deletions internal/tracer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,9 @@ func TestTracingContextPropagatorWorkflowContext(t *testing.T) {
returnCtx2, err := ctxProp.ExtractToWorkflow(Background(), NewHeaderReader(header))
require.NoError(t, err)

newSpanContext := spanFromContext(returnCtx)
newSpanContext := GetSpanContext(returnCtx)
assert.NotNil(t, newSpanContext)
newSpanContext2 := spanFromContext(returnCtx2)
newSpanContext2 := GetSpanContext(returnCtx2)
assert.NotNil(t, newSpanContext2)
assert.Equal(t, newSpanContext2, newSpanContext)
}
Expand Down Expand Up @@ -140,7 +140,7 @@ func TestConsistentInjectionExtraction(t *testing.T) {
extractedCtx, err := ctxProp.ExtractToWorkflow(Background(), NewHeaderReader(header))
require.NoError(t, err)

extractedSpanContext := spanFromContext(extractedCtx)
extractedSpanContext := GetSpanContext(extractedCtx)
extractedSpanContext.ForeachBaggageItem(func(k, v string) bool {
if k == "request-tenancy" {
assert.Equal(t, v, baggageVal)
Expand Down
17 changes: 17 additions & 0 deletions workflow/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
package workflow

import (
"github.com/opentracing/opentracing-go"
"go.uber.org/cadence/internal"
)

Expand Down Expand Up @@ -76,3 +77,19 @@ func WithValue(parent Context, key interface{}, val interface{}) Context {
func NewDisconnectedContext(parent Context) (ctx Context, cancel CancelFunc) {
return internal.NewDisconnectedContext(parent)
}

// GetSpanContext returns the [opentracing.SpanContext] from [Context].
// Returns nil if tracer is not set in [go.uber.org/cadence/worker.Options].
//
// Note: If tracer is set, we already activate a span for each workflow.
// This SpanContext will be passed to the activities and child workflows to start new spans.
//
// Example Usage:
//
// span := GetSpanContext(ctx)
// if span != nil {
// span.SetTag("foo", "bar")
// }
func GetSpanContext(ctx Context) opentracing.SpanContext {
return internal.GetSpanContext(ctx)
}
Loading