Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions appdaemon/plugin_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,23 +469,23 @@ async def wait_for_plugins(self, timeout: float | None = None):
self.AD.loop.create_task(event.wait(), name=f"waiting for {plugin_name} to be ready")
for plugin_name, event in self._ready_events()
]
readiness = self.AD.loop.create_task(
asyncio.wait(wait_tasks, timeout=timeout, return_when=asyncio.ALL_COMPLETED),
name="waiting for all plugins to be ready",
)
if wait_tasks:
readiness = self.AD.loop.create_task(
asyncio.wait(wait_tasks, timeout=timeout, return_when=asyncio.ALL_COMPLETED),
name="waiting for all plugins to be ready",
)

early_stop = self.AD.loop.create_task(self.AD.stop_event.wait(), name="waiting for appdaemon to stop")
await self.AD.loop.create_task(
asyncio.wait((readiness, early_stop), timeout=timeout, return_when=asyncio.FIRST_COMPLETED),
name="waiting for plugins or stop event",
)
if readiness.done():
# The readiness wait completed
self.logger.info("All plugins ready")
elif self.AD.stopping:
self.logger.info("AppDaemon stopping before all plugins ready, cancelling readiness waits")
for task in wait_tasks:
task.cancel()
early_stop = self.AD.loop.create_task(self.AD.stop_event.wait(), name="waiting for appdaemon to stop")
await self.AD.loop.create_task(
asyncio.wait((readiness, early_stop), timeout=timeout, return_when=asyncio.FIRST_COMPLETED),
name="waiting for plugins or stop event",
)
if self.AD.stopping:
self.logger.info("AppDaemon stopping before all plugins ready, cancelling readiness waits")
for task in wait_tasks:
task.cancel()
return
self.logger.info("All plugins ready")

def get_config_for_namespace(self, namespace: str) -> PluginConfig:
plugin_name = self.get_plugin_from_namespace(namespace)
Expand Down
17 changes: 17 additions & 0 deletions tests/functional/test_startup.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,20 @@ async def test_hello_world(ad: AppDaemon, caplog: pytest.LogCaptureFixture, app_

assert "Hello from AppDaemon" in caplog.text
assert "You are now ready to run Apps!" in caplog.text


@pytest.mark.ci
@pytest.mark.functional
@pytest.mark.asyncio(loop_scope="session")
async def test_no_plugins(ad_obj: AppDaemon, caplog: pytest.LogCaptureFixture) -> None:
"""Ensure that apps start correctly when there are no plugins configured."""
ad_obj.config.plugins = {}
ad_obj.app_dir = ad_obj.config_dir / "apps/hello_world"

ad_obj.start()
with caplog.at_level(logging.INFO, logger="AppDaemon"):
async with ad_obj.app_management.app_run_context("hello_world"):
await ad_obj.utility.app_update_event.wait()

await ad_obj.stop()
assert not any(r.levelname == "ERROR" for r in caplog.records)
Loading