Skip to content

Fix: make hyper primitive dynamic evaluation state safe for concurrent asyncio tasks - #428

Open
purvi1508 wants to merge 1 commit into
google:mainfrom
purvi1508:main
Open

purvi1508 wants to merge 1 commit into
google:mainfrom
purvi1508:main

Conversation

@purvi1508

Copy link
Copy Markdown

The problem I am trying to Solve?

DynamicEvaluationContext.apply() (the thing behind pg.oneof, pg.manyof, pg.floatv etc.) needs to remember "what decision is currently active" while the code runs. It is used to store this in two unsafe ways:
A plain instance attribute (self._decision_getter) on the context object.
Thread-local storage (threading.local), which only keeps things separate per OS thread — not per asyncio.Task.

The problem: modern Python code (like agents, servers, or anything using asyncio) often runs many tasks on the same thread at the same time, taking turns. If two tasks call context.apply(...) on the same context around the same time, they'd overwrite each other's decision, causing wrong results or crashes.

Why this doesn't break anything
The old thread_local_* functions are untouched. I didn't delete or modify them — I only added new context_local_* functions next to them. Anyone using thread_local_* elsewhere is unaffected.
contextvars behaves like threading.local for normal thread-based code. If you're not using asyncio, nothing changes — each thread still gets its own isolated storage, same as before.
Regular (single-threaded, non-async) usage is 100% identical. All existing tests that check basic oneof/manyof/apply/collect behavior still pass unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant