mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-10-26 13:16:24 +00:00
* fix(skills): let skill_manage lock waiters wake across event loops The sync tool wrapper runs every call under its own asyncio.run, and ToolNode runs same-turn calls on separate threads. The per-(user, skill) asyncio.Lock bound itself to the first contending loop, so a release from another thread never woke that waiter, and a third caller failed with "bound to a different event loop". Reuse the read-before-write gate lock: each waiter parks on its own loop without holding an executor thread, and release wakes every waiter to re-contend, so a cancelled waiter cannot strand the skill. Keep the gate's waiters in arrival order, so same-turn calls on one skill still take the lock in the order they reached it, as with asyncio.Lock. Guard the registry lookup, which the sync path runs on several threads. Fixes #5846 * fix(skills): hand the skill lock to the oldest waiter Reusing the read-before-write gate let a later same-skill call overtake one already waiting. Release unlocked the gate and woke every waiter, so a call whose storage lookup finished in that same loop step took the free lock first. asyncio.Lock on main never lets a new caller pass a queued one. Give skill_manage its own small lock. Release hands the lock straight to the oldest waiter and keeps it locked, so a later caller queues behind it. Each waiter still parks on its own future and wakes on its own loop, so waiting holds no executor thread. Claiming the future settles a race with its cancellation, and a waiter cancelled after the handoff passes the lock on. Releasing an unlocked skill lock raises, as with asyncio.Lock. read_before_write_middleware.py is back to main. --------- Co-authored-by: Totoro-qaq <279883115+Totoro-qaq@users.noreply.github.com>