|
5 | 5 | from __future__ import annotations
|
6 | 6 |
|
7 | 7 | import asyncio
|
8 |
| -import concurrent.futures |
9 | 8 | import inspect
|
10 | 9 | import itertools
|
11 | 10 | import logging
|
@@ -289,49 +288,16 @@ def __init__(self, **kwargs):
|
289 | 288 | for msg_type in self.control_msg_types:
|
290 | 289 | self.control_handlers[msg_type] = getattr(self, msg_type)
|
291 | 290 |
|
292 |
| - self.control_queue: Queue[t.Any] = Queue() |
293 |
| - |
294 | 291 | # Storing the accepted parameters for do_execute, used in execute_request
|
295 | 292 | self._do_exec_accepted_params = _accepts_parameters(
|
296 | 293 | self.do_execute, ["cell_meta", "cell_id"]
|
297 | 294 | )
|
298 | 295 |
|
299 |
| - def dispatch_control(self, msg): |
300 |
| - self.control_queue.put_nowait(msg) |
301 |
| - |
302 |
| - async def poll_control_queue(self): |
303 |
| - while True: |
304 |
| - msg = await self.control_queue.get() |
305 |
| - # handle tracers from _flush_control_queue |
306 |
| - if isinstance(msg, (concurrent.futures.Future, asyncio.Future)): |
307 |
| - msg.set_result(None) |
308 |
| - continue |
| 296 | + async def dispatch_control(self, msg): |
| 297 | + # Ensure only one control message is processed at a time |
| 298 | + async with asyncio.Lock(): |
309 | 299 | await self.process_control(msg)
|
310 | 300 |
|
311 |
| - async def _flush_control_queue(self): |
312 |
| - """Flush the control queue, wait for processing of any pending messages""" |
313 |
| - tracer_future: concurrent.futures.Future[object] | asyncio.Future[object] |
314 |
| - if self.control_thread: |
315 |
| - control_loop = self.control_thread.io_loop |
316 |
| - # concurrent.futures.Futures are threadsafe |
317 |
| - # and can be used to await across threads |
318 |
| - tracer_future = concurrent.futures.Future() |
319 |
| - awaitable_future = asyncio.wrap_future(tracer_future) |
320 |
| - else: |
321 |
| - control_loop = self.io_loop |
322 |
| - tracer_future = awaitable_future = asyncio.Future() |
323 |
| - |
324 |
| - def _flush(): |
325 |
| - # control_stream.flush puts messages on the queue |
326 |
| - if self.control_stream: |
327 |
| - self.control_stream.flush() |
328 |
| - # put Future on the queue after all of those, |
329 |
| - # so we can wait for all queued messages to be processed |
330 |
| - self.control_queue.put(tracer_future) |
331 |
| - |
332 |
| - control_loop.add_callback(_flush) |
333 |
| - return awaitable_future |
334 |
| - |
335 | 301 | async def process_control(self, msg):
|
336 | 302 | """dispatch control requests"""
|
337 | 303 | if not self.session:
|
@@ -387,8 +353,6 @@ async def dispatch_shell(self, msg):
|
387 | 353 | """dispatch shell requests"""
|
388 | 354 | if not self.session:
|
389 | 355 | return
|
390 |
| - # flush control queue before handling shell requests |
391 |
| - await self._flush_control_queue() |
392 | 356 |
|
393 | 357 | idents, msg = self.session.feed_identities(msg, copy=False)
|
394 | 358 | try:
|
@@ -531,6 +495,19 @@ async def process_one(self, wait=True):
|
531 | 495 | t, dispatch, args = self.msg_queue.get_nowait()
|
532 | 496 | except (asyncio.QueueEmpty, QueueEmpty):
|
533 | 497 | return
|
| 498 | + |
| 499 | + if self.control_thread is None and self.control_stream is not None: |
| 500 | + # If there isn't a separate control thread then this main thread handles both shell |
| 501 | + # and control messages. Before processing a shell message we need to flush all control |
| 502 | + # messages and allow them all to be processed. |
| 503 | + await asyncio.sleep(0) |
| 504 | + self.control_stream.flush() |
| 505 | + |
| 506 | + socket = self.control_stream.socket |
| 507 | + while socket.poll(1): |
| 508 | + await asyncio.sleep(0) |
| 509 | + self.control_stream.flush() |
| 510 | + |
534 | 511 | await dispatch(*args)
|
535 | 512 |
|
536 | 513 | async def dispatch_queue(self):
|
@@ -578,9 +555,6 @@ def start(self):
|
578 | 555 | if self.control_stream:
|
579 | 556 | self.control_stream.on_recv(self.dispatch_control, copy=False)
|
580 | 557 |
|
581 |
| - control_loop = self.control_thread.io_loop if self.control_thread else self.io_loop |
582 |
| - |
583 |
| - asyncio.run_coroutine_threadsafe(self.poll_control_queue(), control_loop.asyncio_loop) |
584 | 558 | if self.shell_stream:
|
585 | 559 | self.shell_stream.on_recv(
|
586 | 560 | partial(
|
|
0 commit comments