mode icon indicating copy to clipboard operation
mode copied to clipboard

Potential MethodQueue bug?

Open jheinnic opened this issue 4 years ago • 1 comments

Checklist

  • [X] I have included information about relevant versions
  • [X] I have verified that the issue persists when using the master branch of Mode.

Steps to reproduce

  1. Define any simple async function
  2. Create a mode.threads.QueueServiceThread and call its start() method.
  3. Call the async function with service.
  4. Prepare a debugger with breakpoints at two locations: -- The beginning of MethodQueue, currently line 331 of mode/threads.py -- The if self._loop is None block of ServiceBase's loop @property, currently line 146 of mode/services.py
  5. Run with the debugger
  6. Observe first expected Breakpoint stop
  7. Resume execution

Expected behavior

The program should run to completion without stopping at the second breakpoint at all

Before proceeding to (7), notice that we have passed an explicit event loop argument. I do not expect to need to hit the second breakpoint before the program completes because the event loop is known at this point and I have no further Service initialization to do.

Actual behavior

Given that we have passed a loop argument explicitly to MethodQueue, I would not expect to land in the second breakpoint, especially while the first breakpoint is still on the call stack. But on resuming after the first, expected breakpoint, we land in a second, unexpected stop, with MethodQueue requesting the default event loop to satisfy its own None reference.

Reading the code carefully we can see that MethodQueue does not ever do anything with its EventLoop parameter--neither pass it to its own super.init() method, more to any of its child objects.

I imagine that this code should either not receive an EventLoop argument, or it should pass that argument to its own call to ServiceBase.init() before initializing its Queue and Event objects. I am not sure which solution would be preferred. Although the former seems more consistent with Python 3.8's deprecation of explicit EventLoop arguments, perhaps the latter would be more sensitive to compatibility with Python 3.6 and 3.7 for the time being.

Full traceback

Traceback (most recent call last):
  __init__, threads.py:332
  method_queue, threads.py:411
  on_thread_started, threads.py:418
  _serve, threads.py:252
  _run, events.py:81
  _run_once, base_events.py:1859
  run_forever, base_events.py:570
  run_until_complete, base_events.py:603
  _start_thread, threads.py:211
  run, threads.py:66
    _bootstrap_inner, threading.py:932
    _bootstrap, threading.py:890

Versions

  • Python version 3.8.5
  • Mode version 4.3.2
  • Operating system MacOSX 10.13.6

jheinnic avatar Aug 21 '20 02:08 jheinnic

Code block that implements (1) to (3)

import asyncio
from mode import QueueServiceThread


async def my_func(a: int) -> None:
    print(a)


async def use_queue_service() -> None:
    service: QueueServiceThread = QueueServiceThread()
    await service.start();
    await service.call_thread(my_func, 5)


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(
        use_queue_service()
    )

jheinnic avatar Aug 21 '20 11:08 jheinnic