@@ -56,13 +56,102 @@ Here is a propagator that carries a custom key-value pair from the Client to Wor
5656
5757
5858<!--SNIPSTART samples-go-ctx-propagation-propagator-- >
59+ [ ctxpropagation/propagator.go] ( https://github.com/temporalio/samples-go/blob/main/ctxpropagation/propagator.go )
60+ ``` go
61+ type (
62+ // contextKey is an unexported type used as key for items stored in the
63+ // Context object
64+ contextKey struct {}
65+
66+ // propagator implements the custom context propagator
67+ propagator struct {}
68+
69+ // Values is a struct holding values
70+ Values struct {
71+ Key string ` json:"key"`
72+ Value string ` json:"value"`
73+ }
74+ )
75+
76+ // PropagateKey is the key used to store the value in the Context object
77+ var PropagateKey = contextKey{}
78+
79+ // HeaderKey is the key used by the propagator to pass values through the
80+ // Temporal server headers
81+ const HeaderKey = " custom-header"
82+
83+ // NewContextPropagator returns a context propagator that propagates a set of
84+ // string key-value pairs across a workflow
85+ func NewContextPropagator () workflow .ContextPropagator {
86+ return &propagator{}
87+ }
88+
89+ // Inject injects values from context into headers for propagation
90+ func (s *propagator ) Inject (ctx context .Context , writer workflow .HeaderWriter ) error {
91+ value := ctx.Value (PropagateKey)
92+ payload , err := converter.GetDefaultDataConverter ().ToPayload (value)
93+ if err != nil {
94+ return err
95+ }
96+ writer.Set (HeaderKey, payload)
97+ return nil
98+ }
99+
100+ // InjectFromWorkflow injects values from context into headers for propagation
101+ func (s *propagator ) InjectFromWorkflow (ctx workflow .Context , writer workflow .HeaderWriter ) error {
102+ value := ctx.Value (PropagateKey)
103+ payload , err := converter.GetDefaultDataConverter ().ToPayload (value)
104+ if err != nil {
105+ return err
106+ }
107+ writer.Set (HeaderKey, payload)
108+ return nil
109+ }
110+
111+ // Extract extracts values from headers and puts them into context
112+ func (s *propagator ) Extract (ctx context .Context , reader workflow .HeaderReader ) (context .Context , error ) {
113+ if value , ok := reader.Get (HeaderKey); ok {
114+ var values Values
115+ if err := converter.GetDefaultDataConverter ().FromPayload (value, &values); err != nil {
116+ return ctx, nil
117+ }
118+ ctx = context.WithValue (ctx, PropagateKey, values)
119+ }
120+
121+ return ctx, nil
122+ }
123+ ```
59124<!--SNIPEND-->
60125
61126## Register the propagator and set context values
62127
63128Register the propagator on the Client. Then set context values before starting a Workflow:
64129
65130<!--SNIPSTART samples-go-ctx-propagation-starter-- >
131+ [ ctxpropagation/starter/main.go] ( https://github.com/temporalio/samples-go/blob/main/ctxpropagation/starter/main.go )
132+ ``` go
133+ // The client is a heavyweight object that should be created once per process.
134+ c , err := client.Dial (client.Options {
135+ HostPort : client.DefaultHostPort ,
136+ Interceptors : []interceptor.ClientInterceptor {tracingInterceptor},
137+ ContextPropagators : []workflow.ContextPropagator {ctxpropagation.NewContextPropagator ()},
138+ })
139+ if err != nil {
140+ log.Fatalln (" Unable to create client" , err)
141+ }
142+ defer c.Close ()
143+
144+ workflowID := " ctx-propagation_" + uuid.New ()
145+ workflowOptions := client.StartWorkflowOptions {
146+ ID : workflowID,
147+ TaskQueue : " ctx-propagation" ,
148+ }
149+
150+ ctx := context.Background ()
151+ ctx = context.WithValue (ctx, ctxpropagation.PropagateKey , &ctxpropagation.Values {Key: " test" , Value : " tested" })
152+
153+ we , err := c.ExecuteWorkflow (ctx, workflowOptions, ctxpropagation.CtxPropWorkflow )
154+ ```
66155<!--SNIPEND-->
67156
68157You can also register context propagators through a [Plugin](/develop/plugins-guide) if you are building a reusable library.
@@ -72,9 +161,43 @@ You can also register context propagators through a [Plugin](/develop/plugins-gu
72161In your Workflow, the propagated values are available on the `workflow.Context`. When the Workflow starts an Activity, the SDK automatically propagates the same values:
73162
74163<!--SNIPSTART samples-go-ctx-propagation-workflow-- >
164+ [ ctxpropagation/workflow.go] ( https://github.com/temporalio/samples-go/blob/main/ctxpropagation/workflow.go )
165+ ``` go
166+ // CtxPropWorkflow workflow definition
167+ func CtxPropWorkflow (ctx workflow .Context ) (err error ) {
168+ ao := workflow.ActivityOptions {
169+ StartToCloseTimeout: 2 * time.Second , // such a short timeout to make sample fail over very fast
170+ }
171+ ctx = workflow.WithActivityOptions (ctx, ao)
172+
173+ if val := ctx.Value (PropagateKey); val != nil {
174+ vals := val.(Values)
175+ workflow.GetLogger (ctx).Info (" custom context propagated to workflow" , vals.Key , vals.Value )
176+ }
177+
178+ var values Values
179+ if err = workflow.ExecuteActivity (ctx, SampleActivity).Get (ctx, &values); err != nil {
180+ workflow.GetLogger (ctx).Error (" Workflow failed." , " Error" , err)
181+ return err
182+ }
183+ workflow.GetLogger (ctx).Info (" context propagated to activity" , values.Key , values.Value )
184+ workflow.GetLogger (ctx).Info (" Workflow completed." )
185+ return nil
186+ }
187+ ```
75188<!--SNIPEND-->
76189
77190<!--SNIPSTART samples-go-ctx-propagation-activity-- >
191+ [ ctxpropagation/activities.go] ( https://github.com/temporalio/samples-go/blob/main/ctxpropagation/activities.go )
192+ ``` go
193+ func SampleActivity (ctx context .Context ) (*Values , error ) {
194+ if val := ctx.Value (PropagateKey); val != nil {
195+ vals := val.(Values)
196+ return &vals, nil
197+ }
198+ return nil , nil
199+ }
200+ ```
78201<!--SNIPEND-->
79202
80203You can configure multiple context propagators on a single Client, each responsible for its own set of keys.
0 commit comments