runIsolate<T> method

Future<T> runIsolate<T>(
  1. Future<T> computation()
)

Runs a computation in a new isolate with this context.

This serializes the current context and factory configuration, passes them to the new isolate, and then runs the computation with the context set in the new isolate.

On web platforms, this will run in the current thread as web doesn't support isolates.

Implementation

Future<T> runIsolate<T>(Future<T> Function() computation) async {
  // Serialize the current factory
  final oldFactory = _getAndCacheOTelFactory();
  final serializedFactory = oldFactory.serialize();
  final serializedContext = serialize();
  final factoryFactory = oldFactory.factoryFactory;

  Future<T> childMain() async {
    // Set up the factory in the new isolate.
    OTelFactory.otelFactory =
        OTelFactory.deserialize(serializedFactory, factoryFactory);

    // Deserialize the parent's context in the new isolate. Per the OTel
    // spec ([trace/api.md §SpanContext]: "Each propagators' deserialization
    // must set IsRemote to true on a parent SpanContext"), upgrade the
    // propagated SpanContext to isRemote=true on the receiving side — same
    // semantic as a SpanContext extracted from W3C trace-context HTTP
    // headers. Crossing an isolate boundary is the same kind of process
    // boundary.
    final deserialized = deserialize(serializedContext);
    final propagatedSpanContext = deserialized.spanContext;
    final isolateContext =
        (propagatedSpanContext != null && !propagatedSpanContext.isRemote)
            ? deserialized.copyWithSpanContext(
                OTelFactory.otelFactory!.spanContext(
                  traceId: propagatedSpanContext.traceId,
                  spanId: propagatedSpanContext.spanId,
                  parentSpanId: propagatedSpanContext.parentSpanId,
                  traceFlags: propagatedSpanContext.traceFlags,
                  traceState: propagatedSpanContext.traceState,
                  isRemote: true,
                ),
              )
            : deserialized;
    _currentContext = isolateContext;
    _rootContext ??= isolateContext;

    // Run the computation in a zone carrying the deserialized context.
    return runZoned(
      computation,
      zoneValues: {_zoneKey: isolateContext},
    );
  }

  // Spawn via the platform bridge, which re-installs the parent's
  // error handler inside the child isolate first (api#94).
  return runIsolateWithErrorHandlerBridge(childMain);
}