elad-bar / ha-blueiris

Integration with Blue Iris Video Security Software
182 stars 42 forks source link

Ensure entity update is scheduled with event loop #172

Closed nemec closed 2 years ago

nemec commented 2 years ago

I was getting errors regarding non-thread-safe operations in the BI entity update code in the latest version. It was filling my logs with massive stack traces each time an update was triggered. I narrowed it down to the fact that homeassistant.helpers.event.async_track_time_interval, which is used for scheduling BI updates, can accept either a callable or an awaitable. If a callable, it's scheduled in a new thread/threadpool that's not coordinated with the Home Assistant async event loop. Therefore, in _update_entities when you call self._hass.async_create_task(self.async_update(now)) it's scheduling an async task cross-thread with no event loop. To fix this, I turned _update_entities into an awaitable method and verified that the callback is run with an async event loop.

I believe the code works fine without change, but there may be a small thread safety risk and it really fills up the logs.

Traceback (most recent call last):
  File "/usr/lib/python3.10/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/home/me/prg/src/home-assistant-core/config/custom_components/blueiris/managers/home_assistant.py", line 128, in _update_entities
    def _update_entities(self, now):
  File "/home/me/prg/src/home-assistant-core/homeassistant/core.py", line 484, in async_create_task
    task = self.loop.create_task(target)
  File "/usr/lib/python3.10/asyncio/base_events.py", line 438, in create_task
    task = tasks.Task(coro, loop=self, name=name)
  File "/usr/lib/python3.10/asyncio/base_events.py", line 752, in call_soon
    self._check_thread()
  File "/usr/lib/python3.10/asyncio/base_events.py", line 789, in _check_thread
    raise RuntimeError(
RuntimeError: Non-thread-safe operation invoked on an event loop other than the current one
2022-06-02 20:39:21 ERROR (Thread-2 (_monitor)) [homeassistant] Error doing job: Task was destroyed but it is pending!:   File "/usr/lib/python3.10/threading.py", line 966, in _bootstrap
    self._bootstrap_inner()
  File "/usr/lib/python3.10/threading.py", line 1009, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.10/threading.py", line 946, in run
    self._target(*self._args, **self._kwargs)
  File "/usr/lib/python3.10/concurrent/futures/thread.py", line 83, in _worker
    work_item.run()
  File "/usr/lib/python3.10/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/home/me/prg/src/home-assistant-core/config/custom_components/blueiris/managers/home_assistant.py", line 128, in _update_entities
    self._hass.async_create_task(self.async_update(now))
  File "/home/me/prg/src/home-assistant-core/homeassistant/core.py", line 484, in async_create_task
    task = self.loop.create_task(target)
  File "/usr/lib/python3.10/asyncio/base_events.py", line 438, in create_task
    task = tasks.Task(coro, loop=self, name=name)

System: