Fix data update coordinator garbage collection (#137299)
parent
fa8225d0a2
commit
0766b47161
|
@ -146,6 +146,10 @@ class Debouncer[_R_co]:
|
||||||
"""Cancel any scheduled call, and prevent new runs."""
|
"""Cancel any scheduled call, and prevent new runs."""
|
||||||
self._shutdown_requested = True
|
self._shutdown_requested = True
|
||||||
self.async_cancel()
|
self.async_cancel()
|
||||||
|
# Release hard references to parent function
|
||||||
|
# https://github.com/home-assistant/core/issues/137237
|
||||||
|
self._function = None
|
||||||
|
self._job = None
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_cancel(self) -> None:
|
def async_cancel(self) -> None:
|
||||||
|
|
|
@ -4,6 +4,7 @@ import asyncio
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
import logging
|
import logging
|
||||||
from unittest.mock import AsyncMock, Mock
|
from unittest.mock import AsyncMock, Mock
|
||||||
|
import weakref
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -529,3 +530,37 @@ async def test_background(
|
||||||
async_fire_time_changed(hass, utcnow() + timedelta(seconds=1))
|
async_fire_time_changed(hass, utcnow() + timedelta(seconds=1))
|
||||||
await hass.async_block_till_done(wait_background_tasks=False)
|
await hass.async_block_till_done(wait_background_tasks=False)
|
||||||
assert len(calls) == 2
|
assert len(calls) == 2
|
||||||
|
|
||||||
|
|
||||||
|
async def test_shutdown_releases_parent_class(hass: HomeAssistant) -> None:
|
||||||
|
"""Test shutdown releases parent class.
|
||||||
|
|
||||||
|
See https://github.com/home-assistant/core/issues/137237
|
||||||
|
"""
|
||||||
|
calls = []
|
||||||
|
|
||||||
|
class SomeClass:
|
||||||
|
def run_func(self) -> None:
|
||||||
|
calls.append(None)
|
||||||
|
|
||||||
|
my_class = SomeClass()
|
||||||
|
my_class_weak_ref = weakref.ref(my_class)
|
||||||
|
|
||||||
|
debouncer = debounce.Debouncer(
|
||||||
|
hass,
|
||||||
|
_LOGGER,
|
||||||
|
cooldown=0.01,
|
||||||
|
immediate=True,
|
||||||
|
function=my_class.run_func,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Debouncer keeps a reference to the function, prevening GC
|
||||||
|
del my_class
|
||||||
|
await debouncer.async_call()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert len(calls) == 1
|
||||||
|
assert my_class_weak_ref() is not None
|
||||||
|
|
||||||
|
# Debouncer shutdown releases the class
|
||||||
|
debouncer.async_shutdown()
|
||||||
|
assert my_class_weak_ref() is None
|
||||||
|
|
Loading…
Reference in New Issue