GoWindGoWind
Home
Framework
GoWind Toolkit
  • Open Source

    • GoWind Admin (Admin Platform)
    • GoWind CMS (Content Management)
    • GoWind UBA (Behavior Analytics)
    • GoWind Shop (E-commerce)
    • GoWind Kanban (Kanban Boards)
    • GoWind Ledger (Personal Finance)
    • GoWind ShortPlay (Short Drama)
    • GoWind Ops (Operations Platform)
    • RushWind (Rust Ecosystem)
  • Open Core (Community + Enterprise)

    • GoWind OA (Office Collaboration)
    • GoWind ERP (Procure-to-Pay)
    • GoWind WMS (Warehousing)
  • Commercial

    • GoWind IM (Instant Messaging)
    • GoWind IoT (IoT Platform)
    • GoWind Edu (AI Education)
    • GoWind MES (Manufacturing Execution)
    • GoWind CDC (Data Pipeline)
    • GoWind SDP (Zero-Trust Gateway)
    • GoWind Quant (Quant Research)
    • GoWind Trade Radar (Export Sourcing)
    • GoWind Game Radar (Game Greenlight)
  • 简体中文
  • English
GitHub
Home
Framework
GoWind Toolkit
  • Open Source

    • GoWind Admin (Admin Platform)
    • GoWind CMS (Content Management)
    • GoWind UBA (Behavior Analytics)
    • GoWind Shop (E-commerce)
    • GoWind Kanban (Kanban Boards)
    • GoWind Ledger (Personal Finance)
    • GoWind ShortPlay (Short Drama)
    • GoWind Ops (Operations Platform)
    • RushWind (Rust Ecosystem)
  • Open Core (Community + Enterprise)

    • GoWind OA (Office Collaboration)
    • GoWind ERP (Procure-to-Pay)
    • GoWind WMS (Warehousing)
  • Commercial

    • GoWind IM (Instant Messaging)
    • GoWind IoT (IoT Platform)
    • GoWind Edu (AI Education)
    • GoWind MES (Manufacturing Execution)
    • GoWind CDC (Data Pipeline)
    • GoWind SDP (Zero-Trust Gateway)
    • GoWind Quant (Quant Research)
    • GoWind Trade Radar (Export Sourcing)
    • GoWind Game Radar (Game Greenlight)
  • 简体中文
  • English
GitHub
  • Introduction

    • GoWind Framework
    • Framework Architecture
  • go-wind Core

    • go-wind Core Framework
    • App Lifecycle Management
    • Context Propagation
    • Transport Abstraction
    • Log Facade Interface
  • go-wind-plugins

    • go-wind-plugins Plugin Overview
    • Plugin Configuration System
    • Plugin Registration Mechanism (SPI)
    • Logging Adapter Plugins
    • Transport Protocol Plugins
    • Message Middleware Plugins
    • Encoding Plugins
    • Security and Authentication Plugins
    • Distributed Tracing Plugins
    • Cache Plugins
    • Object Storage Plugins (OSS)
    • Rate Limiting Plugins
    • Metrics Plugins
    • AI Plugins
    • Workflow Plugins
    • Database and Cache Plugins
    • Bootstrap Integration and Gateway Plugins
    • Compression and Serialization Plugins
    • Template Rendering and Validation Plugins
  • go-wind-bootstrap

    • go-wind-bootstrap: The Declarative Bootstrap
    • The Bootstrap Configuration System
    • The Bootstrap SPI Mechanism
    • Declarative Middleware Orchestration
    • Bootstrap Command-Line Integration
    • Bootstrap Practical Examples
  • go-wind-flow Workflow Engine

    • GoWind Flow Process Engine
  • Tutorials

    • Quick Start Tutorial
    • Custom Plugin Development Tutorial
    • Multi-Protocol Listening Tutorial
    • Framework Migration Guide

Context Propagation

The Context module of go-wind provides request-scoped metadata propagation, including TraceID, UserID, and ColorTag (canary release tag), protected against data races through deep copies.

1. Context Design

All request-scoped metadata is stored in a single Metadata map, attached to the context via an unexported context key to avoid conflicts with other context values:

// context.go
type metadataKey struct{}        // Unexported key, preventing key collisions

// Metadata is a string key-value map carrying request-scoped attributes
type Metadata map[string]string

// Standard propagation headers (used across service boundaries)
const (
    HeaderTraceID  = "x-wind-trace-id"
    HeaderUserID   = "x-wind-user-id"
    HeaderColorTag = "x-wind-color-tag"
)

Two groups of APIs are provided:

CategoryFunctions
MetadataNewMetadataContext / MetadataFromContext / GetMetadata
MutationWithMetadata / WithMetadatas / WithoutMetadata (always operate on a private copy)
Convenience wrappersWithTraceID / GetTraceID, WithUserID / GetUserID, WithColorTag / GetColorTag

2. Propagated Metadata

Standard Header KeySet/GetDescription
x-wind-trace-idWithTraceID / GetTraceIDDistributed tracing ID, spanning the entire request chain
x-wind-user-idWithUserID / GetUserIDCurrent user ID
x-wind-color-tagWithColorTag / GetColorTagCanary release/coloring tag used for traffic routing
Any custom keyWithMetadata / GetMetadataCustom metadata

Beyond the standard headers, Metadata can carry arbitrary custom key-value pairs.

3. Usage

3.1 Setting and Getting

// Set at the request entry point
ctx := wind.WithTraceID(ctx, generateTraceID())
ctx = wind.WithUserID(ctx, "user_123")
ctx = wind.WithColorTag(ctx, "gray")

// Get in business logic
traceID := wind.GetTraceID(ctx)   // "abc-123"
userID := wind.GetUserID(ctx)     // "user_123"

// Custom metadata
ctx = wind.WithMetadata(ctx, "tenant", "acme")
tenant := wind.GetMetadata(ctx, "tenant")

3.2 Middleware Injection

func TraceMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // Extract or generate the TraceID from request headers
        traceID := r.Header.Get("X-Trace-ID")
        if traceID == "" {
            traceID = uuid.New().String()
        }

        // Inject it into the Context
        ctx := wind.WithTraceID(r.Context(), traceID)
        next.ServeHTTP(w, r.WithContext(ctx))
    })
}

3.3 Cross-Service Propagation

// gRPC client: inject the TraceID into outgoing metadata
func injectTraceID(ctx context.Context) context.Context {
    traceID := wind.GetTraceID(ctx)
    return metadata.AppendToOutgoingContext(ctx, wind.HeaderTraceID, traceID)
}

// gRPC server: extract the TraceID from incoming metadata
func extractTraceID(ctx context.Context) context.Context {
    md, _ := metadata.FromIncomingContext(ctx)
    if vals := md.Get(wind.HeaderTraceID); len(vals) > 0 {
        return wind.WithTraceID(ctx, vals[0])
    }
    return ctx
}

4. Deep Copy and Concurrency Safety

The Metadata stored in a context is always a deep copy: WithMetadata / WithMetadatas / WithoutMetadata clone the entire map before mutating it, preventing data races caused by concurrent modification:

// WithMetadata mutates a private copy (cloneMetadata performs a deep copy)
func WithMetadata(ctx context.Context, key, value string) context.Context {
    existing, _ := MetadataFromContext(ctx)
    copied := cloneMetadata(existing) // deep copy
    copied[key] = value
    return context.WithValue(ctx, metadataKey{}, copied)
}

Note: the map returned by MetadataFromContext is shared with the context and must be treated as read-only; to modify it, use the WithMetadata family of functions, which always operate on private copies.

Related Documentation

  • Core Framework Introduction
  • App Lifecycle Management
  • Transport Abstraction
  • Tracing Plugin
Edit this page
Last Updated:: 11/3/26, 2:14 PM
Contributors: Bobo
Prev
App Lifecycle Management
Next
Transport Abstraction