go.temporal.io/server/common/contextutil/metadata.go
190 LOC · 102 covered · 88 uncovered · 36 ranges · 1100 concepts · 33 introducers · 460 tests
File neighbourhood
The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.
Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file
In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.
Graph controls are ready.
Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.
package contextutil
import (
"context"
"maps"
"strconv"
"strings"
"sync"
)
type (
metadataContextKey struct{}
// metadataContext is used to store workflow and activity metadata
metadataContext struct {
sync.Mutex
Metadata map[string]any
MarkedActivityIDs map[string]struct{}
}
)
var metadataCtxKey = metadataContextKey{}
const (
// MetadataKeyWorkflowType is the context metadata key for workflow type.
// These keys are serialized into a protobuf message (ContextMetadata) and sent
// in the "contextmetadata-bin" gRPC trailer. The "-bin" suffix causes gRPC to
// base64-encode the value on the wire, so metadata values may contain arbitrary
// bytes including HTTP/2-unsafe control characters.
MetadataKeyWorkflowType = "workflow-type"
// MetadataKeyWorkflowTaskQueue is the context metadata key for workflow task queue
MetadataKeyWorkflowTaskQueue = "workflow-task-queue"
// MetadataKeyStandaloneActivityType is the context metadata key for standalone activity type.
MetadataKeyStandaloneActivityType = "standalone-activity-type"
// MetadataKeyStandaloneActivityTaskQueue is the context metadata key for standalone activity task queue.
MetadataKeyStandaloneActivityTaskQueue = "standalone-activity-task-queue"
activityTypePrefix = "activity-type-"
activityTaskQueuePrefix = "activity-task-queue-"
)
// ActivityTypeKey returns the metadata key for an activity's type, keyed by scheduled event ID.
return activityTypePrefix + strconv.FormatInt(scheduledEventID, 10)
}
// ActivityTaskQueueKey returns the metadata key for an activity's task queue, keyed by scheduled event ID.
return activityTaskQueuePrefix + strconv.FormatInt(scheduledEventID, 10)
}
// ContextMetadataGetActivityTypeAndTaskQueue scans the context metadata for a single
// activity's type and task queue. Returns false if no activity metadata is found
// or if multiple activities are present.
func ContextMetadataGetActivityTypeAndTaskQueue(ctx context.Context) (activityType string, taskQueue string, ok bool) {
metadata.go ×1
metadataCtx := getMetadataContext(ctx)
if metadataCtx == nil {
}
defer metadataCtx.Unlock()
var foundType, foundTaskQueue bool
for key, value := range metadataCtx.Metadata {
}
if foundTaskQueue {
return "", "", false
}
}
}
}
// ContextMetadataMarkActivityID marks an activity ID on the context for metadata resolution.
// The handler knows which activity (from the task token) but not its type or task queue.
// Mutable state knows the activity details but not which activity the request targets.
// This bridges the two: the handler marks the ID, and SetContextMetadata (during
// closeTransaction) resolves it to type and task queue from mutable state.
// Cannot be used for transactions that remove the activity from mutable state
// (e.g., activity completion), since it won't be available for resolution.
func ContextMetadataMarkActivityID(ctx context.Context, activityID string) bool {
metadata.go ×1
metadataCtx := getMetadataContext(ctx)
if metadataCtx == nil {
}
defer metadataCtx.Unlock()
metadataCtx.MarkedActivityIDs[activityID] = struct{}{}
return true
}
// ContextMetadataGetMarkedActivityIDs returns the marked activity IDs from the context.
metadataCtx := getMetadataContext(ctx)
if metadataCtx == nil {
}
defer metadataCtx.Unlock()
if len(metadataCtx.MarkedActivityIDs) == 0 {
}
for id := range metadataCtx.MarkedActivityIDs {
ids = append(ids, id)
}
return ids
}
// getMetadataContext extracts metadata context from golang context.
metadataCtx := ctx.Value(metadataCtxKey)
if metadataCtx == nil {
}
if !ok {
}
}
// WithMetadataContext adds a metadata context to the given context.
metadataCtx := &metadataContext{
Metadata: make(map[string]any),
MarkedActivityIDs: make(map[string]struct{}),
}
return context.WithValue(ctx, metadataCtxKey, metadataCtx)
}
// ContextHasMetadata returns true if the context has metadata support.
// This can be used to debug whether a context has been properly initialized with metadata.
return getMetadataContext(ctx) != nil
}
// ContextMetadataSet sets a metadata key-value pair in the context, overwriting any existing value.
metadataCtx := getMetadataContext(ctx)
if metadataCtx == nil {
}
defer metadataCtx.Unlock()
metadataCtx.Metadata[key] = value
return true
}
// ContextMetadataGet retrieves a metadata value from the context.
metadataCtx := getMetadataContext(ctx)
if metadataCtx == nil {
}
defer metadataCtx.Unlock()
value, ok := metadataCtx.Metadata[key]
return value, ok
}
// ContextMetadataGetAll retrieves all metadata from the context as a map copy.
metadataCtx := getMetadataContext(ctx)
if metadataCtx == nil {
}
defer metadataCtx.Unlock()
// Return a copy to prevent external modifications
result := make(map[string]any, len(metadataCtx.Metadata))
maps.Copy(result, metadataCtx.Metadata)
return result
}