Skip to content

FastAPI: Context change in sync route does not appear in background tasks #3586

Open
@freud14-tm

Description

@freud14-tm

Describe your environment

OS: Ubuntu
Python version: 3.11.0

Package version:
opentelemetry-api==1.34.1
opentelemetry-sdk==1.34.1
opentelemetry-instrumentation-fastapi==0.55b1

What happened?

When having a sync route in FastAPI and launching a background task, the changes done to the context do not appear in the context of the background task.

Steps to Reproduce

from fastapi import BackgroundTasks, FastAPI
from opentelemetry import context, trace
from opentelemetry.context import set_value
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter

app = FastAPI()

# =========================================================================== #
# Optional: Bug is reproducible with or without setuping the resource, tracer
# provider and FastAPI instrumentor,
resource = Resource.create(attributes={SERVICE_NAME: "pricing-recommendation-engine"})

provider = TracerProvider(resource=resource)
trace.set_tracer_provider(provider)

# provider.add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))

FastAPIInstrumentor().instrument_app(app)
# =========================================================================== #


def my_background_task():
    print(context.get_current())


def add_test_value_to_context():
    ctx = context.get_current()
    ctx = set_value("test_key", "test_value", context=ctx)
    context.attach(ctx)


@app.get("/sync-endpoint")
def sync_endpoint(background_tasks: BackgroundTasks):
    print(context.get_current())
    add_test_value_to_context()
    print(context.get_current())
    background_tasks.add_task(my_background_task)
    return "Hello, World!"


@app.get("/async-endpoint")
async def async_endpoint(background_tasks: BackgroundTasks):
    print(context.get_current())
    add_test_value_to_context()
    print(context.get_current())
    background_tasks.add_task(my_background_task)
    return "Hello, World!"
uvicorn fastapi_context_bug:app

On endpoint /sync-endpoint, we get this:

{'current-span-b13884d6-004f-41b3-84b0-8704e8205ff6': _Span(name="GET /sync-endpoint", context=SpanContext(trace_id=0x3d1bdba09cbb92564db952045e92ab94, span_id=0x93ec8565cd311ed4, trace_flags=0x01, trace_state=[], is_remote=False))}
{'current-span-b13884d6-004f-41b3-84b0-8704e8205ff6': _Span(name="GET /sync-endpoint", context=SpanContext(trace_id=0x3d1bdba09cbb92564db952045e92ab94, span_id=0x93ec8565cd311ed4, trace_flags=0x01, trace_state=[], is_remote=False)), 'test_key': 'test_value'}
INFO:     127.0.0.1:45994 - "GET /sync-endpoint HTTP/1.1" 200 OK
{'current-span-b13884d6-004f-41b3-84b0-8704e8205ff6': _Span(name="GET /sync-endpoint", context=SpanContext(trace_id=0x3d1bdba09cbb92564db952045e92ab94, span_id=0x93ec8565cd311ed4, trace_flags=0x01, trace_state=[], is_remote=False))}

On endpoint /async-endpoint, we get this:

{'current-span-b13884d6-004f-41b3-84b0-8704e8205ff6': _Span(name="GET /async-endpoint", context=SpanContext(trace_id=0xf1009be126c6edf441c7f465fcc05e7e, span_id=0xfa1e818754376b97, trace_flags=0x01, trace_state=[], is_remote=False))}
{'current-span-b13884d6-004f-41b3-84b0-8704e8205ff6': _Span(name="GET /async-endpoint", context=SpanContext(trace_id=0xf1009be126c6edf441c7f465fcc05e7e, span_id=0xfa1e818754376b97, trace_flags=0x01, trace_state=[], is_remote=False)), 'test_key': 'test_value'}
INFO:     127.0.0.1:48510 - "GET /async-endpoint HTTP/1.1" 200 OK
{'current-span-b13884d6-004f-41b3-84b0-8704e8205ff6': _Span(name="GET /async-endpoint", context=SpanContext(trace_id=0xf1009be126c6edf441c7f465fcc05e7e, span_id=0xfa1e818754376b97, trace_flags=0x01, trace_state=[], is_remote=False)), 'test_key': 'test_value'}

Expected Result

The sync route should behave as the async route.

Actual Result

See above.

Additional context

No response

Would you like to implement a fix?

None

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions