Skip to content

ContextVar cannot be updated in the handle #20

@scorpiord

Description

@scorpiord

When I use browser-use and bubus in the fastAPI application, ContextVar cannot be updated in the handle

test code:

import asyncio
from contextvars import ContextVar

from pydantic import BaseModel


class User(BaseModel):
    userid: int
    name: str
    user_code: str


user_ctx: ContextVar[User] = ContextVar('user_ctx', default=None)
user_ctx1: ContextVar[User] = ContextVar('user_ctx1', default=None)

class CtxEvent(BaseEvent):
    ctx: Any


class MyShow:

    def __init__(self):
        self.user_event_bus = EventBus(name=f"UserAgent")
        self.user_event_bus.on(CtxEvent, self.test_show)

    async def test_show(self, event: CtxEvent):
        print(f"test_show:{id(asyncio.get_running_loop())}")
        print(event.event_id)
        user = user_ctx.get()
        print(user)
        user1 = user_ctx1.get()
        print(user1)
        print(event.ctx.get(user_ctx))
        print(event.ctx.get(user_ctx1))

    async def test_show_1(self):
        print(f"test_show_1:{id(asyncio.get_running_loop())}")
        id(asyncio.get_running_loop())
        user = user_ctx.get()
        print(user)
        user1 = user_ctx1.get()
        print(user1)

my_show_instance = MyShow()


@system_router.get("/test")
async def test(user_code,user_code1):
    user_ctx.set(User(user_code=user_code,userid=1,name="user"))
    await asyncio.create_task(test1(user_code,user_code1))

async def test1(user_code,user_code1):

    user_ctx1.set(User(user_code=user_code1,userid=1,name="user"))

    my_show_instance.user_event_bus.dispatch(CtxEvent(ctx=contextvars.copy_context()))
    # await my_show_instance.test_show_1()

Can we support switching the execution context to the dispatch event’s context when handle runs?

For example, have base_event support accepting a context, and then use the provided context when executing handle.

ctx = getattr(event, "ctx", None)

if inspect.iscoroutinefunction(handler):
    if ctx:
        handler_task = ctx.run(asyncio.create_task(handler(event)))
    else:
        handler_task = asyncio.create_task(handler(event))

    result_value: Any = await asyncio.wait_for(handler_task, timeout=event_result.timeout)

elif inspect.isfunction(handler) or inspect.ismethod(handler):
    if ctx:
        result_value: Any = ctx.run(handler, event)
    else:
        result_value: Any = handler(event)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions