VOOZH about

URL: https://deepwiki.com/friendsofhyperf/components/2.6-coroutine-context-management-and-sentrycontext

⇱ Coroutine Context Management and SentryContext | friendsofhyperf/components | DeepWiki


Loading...
Last indexed: 14 February 2026 (15d5ca)
Menu

Coroutine Context Management and SentryContext

This document explains the SentryContext utility class and how the Sentry integration manages coroutine-safe context storage in Hyperf's asynchronous environment. SentryContext provides a centralized API for storing and retrieving Sentry-related data that must be isolated per coroutine, such as trace carriers, server connection details, and tracing control flags.

For information about how tracing spans are created and structured, see Distributed Tracing Architecture. For details on AOP-based instrumentation, see AOP-Based Instrumentation. For event-based trace capture, see Event Lifecycle and EventHandleListener.

The Coroutine Context Challenge

In Hyperf's coroutine-based architecture, multiple concurrent operations execute within the same process but must maintain isolated context. When the Sentry integration captures database queries, Redis commands, or HTTP requests, it needs to temporarily store metadata (such as server addresses and ports) until the operation completes and a span is created. This storage must be coroutine-safe to prevent data leakage between concurrent requests.

Additionally, when distributed tracing is enabled, trace context must propagate across asynchronous boundaries—from parent coroutines to child coroutines, and from producers to consumers in message queues. The SentryContext class solves these challenges by wrapping Hyperf's Context system with a type-safe API specific to Sentry's needs.

Sources: src/sentry/src/SentryContext.php1-161

SentryContext Class Architecture

The SentryContext class is a static utility that provides namespaced access to Hyperf's coroutine context storage. It defines constant keys prefixed with CTX_ and exposes getter/setter methods for each data type.


Context Storage Keys

The class defines constant keys for each data type stored in the context:

Constant KeyPurposeData Type
CTX_CARRIERTrace propagation carrierCarrier
CTX_DISABLE_COROUTINE_TRACINGTracing enable/disable flagbool
CTX_CRON_CHECKIN_IDCron monitor check-in IDstring
CTX_DB_SERVER_ADDRESSDatabase server hoststring
CTX_DB_SERVER_PORTDatabase server portint
CTX_REDIS_SERVER_ADDRESSRedis server hoststring
CTX_REDIS_SERVER_PORTRedis server portint
CTX_RPC_SERVER_ADDRESSRPC server hoststring
CTX_RPC_SERVER_PORTRPC server portint
CTX_RPC_SPAN_CONTEXTRPC span contextSpanContext
CTX_ELASTICSEARCH_SPAN_DATAElasticsearch span dataarray

Sources: src/sentry/src/SentryContext.php18-161

Context Storage Categories

The SentryContext API organizes storage into four functional categories:

Trace Carrier Storage

The Carrier object encapsulates trace context (sentry-trace header, baggage, and metadata) for propagation across async boundaries. The carrier is stored when consuming messages from AMQP or Kafka queues, or when creating child coroutines for AsyncQueue jobs.


The getCarrier() method accepts an optional $coroutineId parameter, allowing child coroutines to retrieve the carrier from their parent's context:


Sources: src/sentry/src/SentryContext.php67-75 src/sentry/src/Tracing/Listener/EventHandleListener.php554-605 src/sentry/src/Tracing/Listener/EventHandleListener.php624-669 src/sentry/src/Tracing/Listener/EventHandleListener.php685-716

Server Address Storage

When aspects intercept connection operations, they capture server addresses and ports before the actual query/command executes. This metadata is retrieved later when creating spans in event listeners.


Example: Database Connection

src/sentry/src/Tracing/Aspect/DbConnectionAspect.php38-67 intercepts PDO connection creation and extracts host/port from the DSN:


Then src/sentry/src/Tracing/Listener/EventHandleListener.php170-216 retrieves the stored address when creating a span:


Sources: src/sentry/src/Tracing/Aspect/DbConnectionAspect.php38-67 src/sentry/src/Tracing/Aspect/RedisConnectionAspect.php38-86 src/sentry/src/Tracing/Aspect/RpcEndpointAspect.php33-64 src/sentry/src/Tracing/Listener/EventHandleListener.php170-216 src/sentry/src/Tracing/Listener/EventHandleListener.php461-505

Tracing Control Flags

The tracing enable/disable flag allows dynamic control over span creation within a coroutine. This is used by CoroutineAspect to prevent recursive tracing when coroutines are created as part of the tracing infrastructure itself.

Sources: src/sentry/src/SentryContext.php42-55 src/sentry/src/Tracing/Aspect/CoroutineAspect.php47-51

Specialized Storage

The context also provides storage for operation-specific data:

  • Cron Check-In ID: Stores the check-in ID when a cron task starts, so the completion event can reference it
  • RPC Span Context: Temporarily holds a SpanContext during RPC call preparation (between path generation and actual send)
  • Elasticsearch Span Data: Stores server/request metadata extracted by ElasticsearchRequestAspect for later use by ElasticsearchAspect

Sources: src/sentry/src/SentryContext.php57-65 src/sentry/src/SentryContext.php147-160 src/sentry/src/SentryContext.php137-145 src/sentry/src/Crons/Listener/EventHandleListener.php67-93 src/sentry/src/Tracing/Aspect/RpcAspect.php63-90 src/sentry/src/Tracing/Aspect/ElasticsearchRequestAspect.php33-64

Coroutine Context Propagation

When new coroutines are created, context must be explicitly propagated to maintain trace continuity. The Sentry integration uses two CoroutineAspect classes to handle this propagation at different layers.

General Sentry Context Propagation

src/sentry/src/Aspect/CoroutineAspect.php1-80 ensures basic context (like the HTTP request) is copied to child coroutines and defers event flushing:


Key steps:

  1. Intercept Coroutine::create() call with priority PHP_INT_MAX - 1
  2. Capture parent coroutine ID and context keys
  3. Wrap the callable to restore context in the child coroutine
  4. Defer event flushing until the child coroutine completes

Sources: src/sentry/src/Aspect/CoroutineAspect.php35-68

Tracing Context Propagation

src/sentry/src/Tracing/Aspect/CoroutineAspect.php1-106 handles trace-specific context propagation when tracing is enabled. It runs with priority PHP_INT_MAX (higher than the general aspect) and creates a new transaction for child coroutines:


The trace context propagation creates three spans:

  1. coroutine.create: Captures the overhead of coroutine creation in the parent
  2. coroutine.prepare: Transaction in the child representing setup phase
  3. coroutine.execute: Span in the child representing actual callable execution

Sources: src/sentry/src/Tracing/Aspect/CoroutineAspect.php45-105

Usage Patterns in Aspects and Listeners

The following table shows which components use which SentryContext methods:

ComponentSet MethodsGet MethodsPurpose
DbConnectionAspectsetDbServerAddress
setDbServerPort
-Store DB connection info
EventHandleListener (DB)-getDbServerAddress
getDbServerPort
Retrieve for span data
RedisConnectionAspectsetRedisServerAddress
setRedisServerPort
-Store Redis connection info
EventHandleListener (Redis)-getRedisServerAddress
getRedisServerPort
Retrieve for span data
RpcEndpointAspectsetRpcServerAddress
setRpcServerPort
-Store RPC endpoint info
RpcAspect-getRpcServerAddress
getRpcServerPort
Retrieve for span data
RpcAspectsetRpcSpanContext
destroyRpcSpanContext
getRpcSpanContextPass SpanContext between methods
EventHandleListener (AMQP)setCarrier-Store trace from message headers
EventHandleListener (Kafka)setCarrier-Store trace from message headers
EventHandleListener (AsyncQueue)-getCarrierRetrieve from parent coroutine
ElasticsearchRequestAspectsetElasticsearchSpanData-Store request metadata
ElasticsearchAspect-getElasticsearchSpanDataRetrieve for span data
CoroutineAspect (Tracing)-isTracingDisabledCheck if tracing enabled
Crons EventHandleListenersetCronCheckInIdgetCronCheckInIdTrack check-in across events

Sources: src/sentry/src/Tracing/Aspect/DbConnectionAspect.php38-67 src/sentry/src/Tracing/Aspect/RedisConnectionAspect.php38-64 src/sentry/src/Tracing/Aspect/RpcEndpointAspect.php33-64 src/sentry/src/Tracing/Aspect/RpcAspect.php63-130 src/sentry/src/Tracing/Aspect/ElasticsearchRequestAspect.php33-64 src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php59-88 src/sentry/src/Tracing/Listener/EventHandleListener.php170-216 src/sentry/src/Tracing/Listener/EventHandleListener.php461-505 src/sentry/src/Tracing/Listener/EventHandleListener.php554-605 src/sentry/src/Tracing/Listener/EventHandleListener.php624-669 src/sentry/src/Tracing/Listener/EventHandleListener.php685-716 src/sentry/src/Crons/Listener/EventHandleListener.php67-129

Integration with Hyperf Context System

SentryContext is a thin wrapper around Hyperf\Context\Context, which provides coroutine-local storage. Each coroutine has its own isolated context storage that is automatically managed by the Hyperf framework.


The key methods used internally:

  • Context::set($key, $value): Store value in current coroutine's context
  • Context::get($key, $default, coroutineId: null): Retrieve value from current or specified coroutine
  • Context::destroy($key): Remove value from current coroutine's context

The optional $coroutineId parameter in Context::get() enables retrieving context from other coroutines, which is used by getCarrier(?int $coroutineId) to support cross-coroutine carrier retrieval.

Sources: src/sentry/src/SentryContext.php1-161

Example: Database Query Tracing Flow

This example demonstrates the complete flow of context management during a database query:


Step-by-step:

  1. Connection Phase: src/sentry/src/Tracing/Aspect/DbConnectionAspect.php56-65 intercepts getPdo() and extracts server information from the WeakMap cache
  2. Storage: Server address and port are stored in SentryContext (which delegates to Hyperf\Context\Context)
  3. Query Phase: src/sentry/src/Tracing/Aspect/DbAspect.php54-134 intercepts the query but doesn't yet have server info
  4. Event Emission: Database emits QueryExecuted event after the query completes
  5. Span Creation: src/sentry/src/Tracing/Listener/EventHandleListener.php170-216 retrieves server address/port from SentryContext and creates a span with complete metadata

Sources: src/sentry/src/Tracing/Aspect/DbConnectionAspect.php38-67 src/sentry/src/Tracing/Aspect/DbAspect.php54-134 src/sentry/src/Tracing/Listener/EventHandleListener.php170-216