- 2026-11-14 -- Fixed: an RPC plugin never runs an op whose caller gave up, a pumped plugin's ops take no lock, and a served plugin's ops stay on the serving thread (
net_utils/rpc/plugin_core.py_make_handlernew_abandoned,RpcPlugin._turn,RpcPlugin.serve;net_utils/preview/look_capture.pydocstring). Three findings of the review of 0.25.0's threaded server, each measured first.- An abandoned op is dropped. A caller that timed out is told the host is not reachable, and the person runs it again; its first request, still waiting its turn, ran too once the host freed up (the review measured 22 of 30 abandoned ops running). At its turn, on the thread it runs on, an op whose caller hung up is not run.
- No lock where one thread answers. 0.25.0 took its op lock on the pumped and served paths too: an op there that pumps the host's loop itself (a nested tick) stopped its own thread for good. The lock is now the threaded server's alone (
_turn). servekeeps its contract. With aQCoreApplicationin the process a served plugin's op was handed to the main thread, which nobody pumped, and timed out:test_plugin_corefollowed bytest_look_capturein one session hung for 60 s. A served plugin's ops are never marshalled; every other path still goes through the marshaller.- How the check reads a caller gone: a probe through
selectors(epoll, kqueue: no descriptor ceiling, where Linux'sselect()refuses one past 1023), and only a closed or reset socket counts; a probe that cannot tell runs the op. A host op waits for its turn inRpcPlugin.TURN_POLL(0.5 s) steps and asks between them, so a waiter whose caller hung up leaves the queue at once, not when the host frees up. The turn is the request's own server's (_turn(server, gone)), never read off the plugin, whose serverstopclears before that server stops. - Test(s): red first, then green:
test_plugin_core.pynewtest_an_op_whose_caller_gave_up_never_runs,test_a_pumped_op_may_pump_the_hosts_loop_itself,test_a_served_plugin_runs_its_ops_on_the_serving_thread_whatever_qt_there_is,test_a_caller_on_a_high_file_descriptor_is_served(Linux),test_a_request_while_the_plugin_stops_still_waits_its_turn(both red against aselect()probe and a turn read off the plugin: the release review's two findings in this change); the abandoned-op test also holds the waiters to leaving while the host is busy; the one-at-a-time and peer-reset tests wait on thread counts, not a sleep or a 3.10-only thread name.test_plugin_core,test_look_capture,test_rpc,test_sync_rpc_core152 passed, 6 skipped, three runs in a row;test_plugin_coreon Linux 71 run, 8 skipped. Staged into the five plugin payloads.