@@ -73,6 +73,7 @@ impl Server {
7373 #[ pyo3( signature = ( daemon_id, command, timeout=300 , env=None , cwd=None ) ) ]
7474 fn exec (
7575 & self ,
76+ py : Python ,
7677 daemon_id : String ,
7778 command : String ,
7879 timeout : u64 ,
@@ -101,18 +102,22 @@ impl Server {
101102 conn. send_message ( msg)
102103 . map_err ( |e| PyRuntimeError :: new_err ( format ! ( "Failed to send command: {}" , e) ) ) ?;
103104
104- self . runtime . block_on ( async {
105- // Wait for result with timeout
106- match tokio:: time:: timeout ( Duration :: from_secs ( timeout) , rx) . await {
107- Ok ( Ok ( result) ) => Ok ( PyCommandResult {
108- stdout : result. stdout ,
109- stderr : result. stderr ,
110- exit_code : result. exit_code ,
111- duration_ms : result. duration_ms ,
112- } ) ,
113- Ok ( Err ( _) ) => Err ( PyRuntimeError :: new_err ( "Command channel closed" ) ) ,
114- Err ( _) => Err ( PyTimeoutError :: new_err ( "Command execution timed out" ) ) ,
115- }
105+ // Release GIL while waiting for result to allow Python thread concurrency
106+ // Re-acquire GIL to return result or raise timeout error
107+ py. allow_threads ( || {
108+ self . runtime . block_on ( async {
109+ // Wait for result with timeout
110+ match tokio:: time:: timeout ( Duration :: from_secs ( timeout) , rx) . await {
111+ Ok ( Ok ( result) ) => Ok ( PyCommandResult {
112+ stdout : result. stdout ,
113+ stderr : result. stderr ,
114+ exit_code : result. exit_code ,
115+ duration_ms : result. duration_ms ,
116+ } ) ,
117+ Ok ( Err ( _) ) => Err ( PyRuntimeError :: new_err ( "Command channel closed" ) ) ,
118+ Err ( _) => Err ( PyTimeoutError :: new_err ( "Command execution timed out" ) ) ,
119+ }
120+ } )
116121 } )
117122 }
118123
0 commit comments