Module: Sashiko::Context
- Defined in:
- lib/sashiko/context.rb
Overview
Helpers for propagating OTel Context across concurrency boundaries.
OpenTelemetry::Context uses fiber-local storage, so spans started in a new Thread or detached Fiber have no parent by default. These helpers capture the caller’s Context and re-attach it inside the forked unit of work, so parent/child span relationships survive the boundary.
Class Method Summary collapse
-
.attach(carrier) ⇒ Object
Re-attach a context captured via #carrier.
-
.carrier ⇒ Object
—- Cross-boundary propagation via W3C Trace Context —————.
-
.current ⇒ Object
Yield the current OTel Context.
-
.fiber(&block) ⇒ Object
Fiber.new { work } that preserves the current OTel Context.
-
.parallel_map(enumerable, &block) ⇒ Object
Map block over enumerable, each element executed on its own thread, all with the Context captured at call time.
-
.thread(&block) ⇒ Object
Thread.new { work } that preserves the current OTel Context.
-
.with(context) ⇒ Object
Run ‘block` with the given Context attached.
Class Method Details
.attach(carrier) ⇒ Object
Re-attach a context captured via #carrier. Yields with that context as current. The extracted context is “remote” from OTel’s POV, so spans started inside become children of the original span.
66 |
# File 'lib/sashiko/context.rb', line 66 def attach(carrier, &) = with(OpenTelemetry.propagation.extract(carrier), &) |
.carrier ⇒ Object
—- Cross-boundary propagation via W3C Trace Context —————
Serialize the current OTel Context into a plain Hash of string headers (traceparent, tracestate). The hash contains only strings, so it’s Ractor-shareable as-is, JSON-serializable, and safe to pass through any boundary:
- Sidekiq/ActiveJob job arguments
- Kafka/SQS message attributes
- Ractor.new(...) arguments
- HTTP request headers
57 58 59 60 61 |
# File 'lib/sashiko/context.rb', line 57 def carrier h = {} #: Hash[String, String] OpenTelemetry.propagation.inject(h) ::Ractor.make_shareable(h) end |
.current ⇒ Object
Yield the current OTel Context. Typically captured at submit time, then passed to #attach inside the worker.
14 |
# File 'lib/sashiko/context.rb', line 14 def current = OpenTelemetry::Context.current |
.fiber(&block) ⇒ Object
Fiber.new { work } that preserves the current OTel Context. Returns the Fiber; caller resumes it.
29 30 31 32 |
# File 'lib/sashiko/context.rb', line 29 def fiber(&block) ctx = current Fiber.new { with(ctx, &block) } end |
.parallel_map(enumerable, &block) ⇒ Object
Map block over enumerable, each element executed on its own thread, all with the Context captured at call time. Returns [result, …] in input order. Useful for fanning out instrumented work (e.g. parallel tool calls, parallel HTTP) from inside a traced method.
38 39 40 41 42 43 44 45 |
# File 'lib/sashiko/context.rb', line 38 def parallel_map(enumerable, &block) ctx = current enumerable .map.with_index { |item, i| Thread.new { [i, with(ctx) { block.call(item) }] } } .map(&:value) .sort_by(&:first) .map(&:last) end |
.thread(&block) ⇒ Object
Thread.new { work } that preserves the current OTel Context. Returns the Thread so callers can .join / .value as usual.
22 23 24 25 |
# File 'lib/sashiko/context.rb', line 22 def thread(&block) ctx = current Thread.new { with(ctx, &block) } end |
.with(context) ⇒ Object
Run ‘block` with the given Context attached. Caller owns detach ordering — use #with for the auto-managed form.
18 |
# File 'lib/sashiko/context.rb', line 18 def with(context, &) = OpenTelemetry::Context.with_current(context, &) |