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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions