Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bleak CoreBluetooth backend is leaking tasks? #111

Closed
zyv opened this issue Sep 15, 2019 · 3 comments · Fixed by #232
Closed

Bleak CoreBluetooth backend is leaking tasks? #111

zyv opened this issue Sep 15, 2019 · 3 comments · Fixed by #232
Assignees
Labels
Backend: Core Bluetooth Issues and PRs relating to the Core Bluetooth backend enhancement New feature or request
Milestone

Comments

@zyv
Copy link

zyv commented Sep 15, 2019

  • bleak version: 0.5.0
  • Python version: Python 3.7.4
  • Operating System: macOS Mojave 10.14.6 (18G87)

Description

If I close the event loop after using Bleak and disconnecting from the device, I get an error from asyncio saying that it destroyed a pending task:

DEBUG:bleak.backends.corebluetooth.CentralManagerDelegate:Peripheral Device disconnected!
ERROR:asyncio:Task was destroyed but it is pending!
task: <Task pending coro=<Application._handle_nsrunloop() running at /Users/zaytsev/PycharmProjects/huawei-lpv2/venv/lib/python3.7/site-packages/bleak/backends/corebluetooth/__init__.py:45>>

What I Did

    event_loop = asyncio.get_event_loop()

    try:
        event_loop.run_until_complete(run(...))
    finally:
        event_loop.close()
@hbldh
Copy link
Owner

hbldh commented Oct 7, 2019

Try adding a

from bleak.backends.corebluetooth.client import cbapp
cbapp.ns_run_loop_done = True
await event_loop.sleep(0.1)

somewhere in the end of your run method.

That might remove the warning.

@hbldh hbldh self-assigned this Oct 7, 2019
@hbldh hbldh added Backend: Core Bluetooth Issues and PRs relating to the Core Bluetooth backend enhancement New feature or request labels Oct 7, 2019
@hbldh
Copy link
Owner

hbldh commented Jun 2, 2020

Have not heard this from anyone else since. Will close for now.

@hbldh hbldh closed this as completed Jun 2, 2020
@dlech
Copy link
Collaborator

dlech commented Jun 18, 2020

This only halfway fixes the problem _central_manager_delegate_ready can still be pending.

For context, this happens when the app runs without actually scanning for devices or anything and therefore the CBManagerState never changes so is_ready() is always false.

dlech added a commit to pybricks/bleak that referenced this issue Jun 25, 2020
Previously on macOS, we had an `Application` class that was instantiated
on module import that registered a task on the current `asyncio` event
loop to pump the `NSRunLoop`.

This has some drawbacks:
- Since it starts running on module import, it can interfere with other
  code like introspection tools that don't actually want to run `bleak`.
- The polling task has to be manually stopped at the end of a program
  to prevent errors about a still running task (issue: hbldh#111).
- `bleak` can only be used with the event loop that was the current
  event loop when the module was imported. For example, this means that
  the new Python 3.8 API `asyncio.run()` can't be used since it creates
  a new event loop.

By introducing an event loop policy, we make it explicit that `bleak`
requires special handling of the `asyncio` event loop ("Explicit is
better than implicit.").

Also, with direct integration in the `asyncio` event loop, we can more
efficiently wait for events instead of having to wake up the `asyncio`
loop every millisecond to poll the `NSRunLoop`.
dlech added a commit to pybricks/bleak that referenced this issue Jun 26, 2020
This replaces the NSRunLoop integration in the corebluetooth backend
with a dispatch queue. This causes callbacks to be dispatched on a
background thread instead of on the main dispatch queue on the main
thread. `call_soon_threadsafe()` is used to synchronize the events
with the event loop where the central manager was created.

The NSRunLoop caused problems because it had to manually be called from
the main thread. This left an asyncio task that had to be manually
stopped at the end of a program to prevent errors about the still
running task (issue: hbldh#111). The NSRunLoop implementation was
also not very efficient since it was waking up the event loop every
millisecond to check for events.
dlech added a commit to pybricks/bleak that referenced this issue Jun 26, 2020
This replaces the NSRunLoop integration in the corebluetooth backend
with a dispatch queue. This causes callbacks to be dispatched on a
background thread instead of on the main dispatch queue on the main
thread. `call_soon_threadsafe()` is used to synchronize the events
with the event loop where the central manager was created.

The NSRunLoop caused problems because it had to manually be called from
the main thread. This left an asyncio task that had to be manually
stopped at the end of a program to prevent errors about the still
running task (issue: hbldh#111). The NSRunLoop implementation was
also not very efficient since it was waking up the event loop every
millisecond to check for events.
dlech added a commit to pybricks/bleak that referenced this issue Jun 26, 2020
This replaces the NSRunLoop integration in the corebluetooth backend
with a dispatch queue. This causes callbacks to be dispatched on a
background thread instead of on the main dispatch queue on the main
thread. `call_soon_threadsafe()` is used to synchronize the events
with the event loop where the central manager was created.

The NSRunLoop caused problems because it had to manually be called from
the main thread. This left an asyncio task that had to be manually
stopped at the end of a program to prevent errors about the still
running task (issue: hbldh#111). The NSRunLoop implementation was
also not very efficient since it was waking up the event loop every
millisecond to check for events.
dlech added a commit to pybricks/bleak that referenced this issue Jun 26, 2020
This replaces the NSRunLoop integration in the corebluetooth backend
with a dispatch queue. This causes callbacks to be dispatched on a
background thread instead of on the main dispatch queue on the main
thread. `call_soon_threadsafe()` is used to synchronize the events
with the event loop where the central manager was created.

The NSRunLoop caused problems because it had to manually be called from
the main thread. This left an asyncio task that had to be manually
stopped at the end of a program to prevent errors about the still
running task (issue: hbldh#111). The NSRunLoop implementation was
also not very efficient since it was waking up the event loop every
millisecond to check for events.
@hbldh hbldh added this to the Version 0.7.0 milestone Jun 30, 2020
hbldh added a commit that referenced this issue Jun 30, 2020
@hbldh hbldh mentioned this issue Jun 30, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Backend: Core Bluetooth Issues and PRs relating to the Core Bluetooth backend enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants