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

Do async_setup_platform in background #36244

Merged
merged 17 commits into from Jun 1, 2020
Merged

Do async_setup_platform in background #36244

merged 17 commits into from Jun 1, 2020

Conversation

balloob
Copy link
Member

@balloob balloob commented May 29, 2020

Breaking change

Proposed change

Make EntityComponent.async_setup(…) no longer wait until platform.async_setup_platform(…) is done.

This makes sense for various reasons:

  • Setting up a platform involves setting up the integration and then the entities. There is no reason for the entity component (ie light) to wait for this
  • We were waiting for async_setup_platform to finish, but async_add_entities was not part of what was awaited for.
  • We use hass.async_create_task so we still make sure they are finished before we finish startup.

I expect an even faster startup time now :)

It could happen previously that an integration was forwarding their config entry or making a discovery for sensor integration and then had to wait for sensor to set up all its platforms first (for no good reason).

CC @bdraco

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New integration (thank you!)
  • New feature (which adds functionality to an existing integration)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Example entry for configuration.yaml:

# Example configuration.yaml

Additional information

  • This PR fixes or closes issue: fixes #
  • This PR is related to issue:
  • Link to documentation pull request:

Checklist

  • The code change is tested and works locally.
  • Local tests pass. Your PR cannot be merged unless tests pass
  • There is no commented out code in this PR.
  • I have followed the development checklist
  • The code has been formatted using Black (black --fast homeassistant tests)
  • Tests have been added to verify that the new code works.

If user exposed functionality or configuration variables are added/changed:

If the code communicates with devices, web services, or third-party tools:

  • The manifest file has all fields filled out correctly.
    Updated and included derived files by running: python3 -m script.hassfest.
  • New or updated dependencies have been added to requirements_all.txt.
    Updated by running python3 -m script.gen_requirements_all.
  • Untested files have been added to .coveragerc.

The integration reached or maintains the following Integration Quality Scale:

  • No score or internal
  • 🥈 Silver
  • 🥇 Gold
  • 🏆 Platinum

@project-bot project-bot bot added this to Needs review in Dev May 29, 2020
@probot-home-assistant probot-home-assistant bot added core new-feature small-pr PRs with less than 30 lines. labels May 29, 2020
@@ -273,7 +273,7 @@ async def preload_stream(hass, _):

request_stream(hass, source, keepalive=True, options=camera.stream_options)

async_when_setup(hass, DOMAIN_STREAM, preload_stream)
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, preload_stream)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why isn't the old approach good? I'm just curious.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bug. It needs to iterate over the entities. When stream is set up it's not ready with adding entities. So listening to START at least guarantees all platforms have set up their entities. It's still not perfect as camera entities might be loaded after start that also have preload stream activated…

@MartinHjelmare
Copy link
Member

MartinHjelmare commented May 29, 2020

Regarding bullet number 2 in the description: In the entity platform helper setup we do wait for the entity addition that is done as part of the platform setup. If an entity is added later, that is not waited for.

Copy link
Member

@pvizeli pvizeli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah make sense and make it real async

@bdraco
Copy link
Member

bdraco commented May 29, 2020

Startup was slightly faster on my test install. Its mostly I/O bound / python load time (primarily the ecdsa module since we don't have gmpy2 installed and are doing the math in pure python) at this point.
2020-05-29 16:39:06 INFO (MainThread) [homeassistant.bootstrap] Home Assistant initialized in 10.77s

@bdraco
Copy link
Member

bdraco commented May 29, 2020

The slow setup wait message now only shows what I would expect instead of climate and sensor being included as they are no longer blocked. 👍

2020-05-29 16:45:47 INFO (MainThread) [homeassistant.bootstrap] Waiting on integrations to complete setup: nws, nut

@balloob
Copy link
Member Author

balloob commented May 29, 2020

Regarding bullet number 2 in the description: In the entity platform helper setup we do wait for the entity addition that is done as part of the platform setup. If an entity is added later, that is not waited for.

You're right Martin. I have removed that code now :)

@bdraco
Copy link
Member

bdraco commented May 29, 2020

Still working as expected for me

2020-05-29 21:21:45 INFO (MainThread) [homeassistant.bootstrap] Waiting on integrations to complete setup: nws, nut
2020-05-29 21:22:45 INFO (MainThread) [homeassistant.bootstrap] Waiting on integrations to complete setup: nws, nut
2020-05-29 21:23:45 INFO (MainThread) [homeassistant.bootstrap] Waiting on integrations to complete setup: nws, nut
2020-05-29 21:24:45 INFO (MainThread) [homeassistant.bootstrap] Waiting on integrations to complete setup: nws, nut

Tests are almost in good shape

@MartinHjelmare
Copy link
Member

Are there any integrations that rely on waiting for the platform setup to add its entities before starting another task? Eg by awaiting forwarding the config entry.

This is a breaking change for integrations and most integrations don't have full test coverage.

@balloob
Copy link
Member Author

balloob commented May 29, 2020

That would not have been possible. Discory/forward is always done with async_create_task because of the circular dependency where hue needs to be set up for light.hue to be set up.

There are integrations that keep track when all platforms are loaded, but that will work the same as we are still waiting for all these tasks to finish.

@MartinHjelmare
Copy link
Member

It's possible as you mention in the second paragraph. That's what I mean.

I don't think it's the same as now we can only wait for home assistant start. So integrations that assume that entities will be loaded when the platform setup is done may start the next task too early.

@balloob
Copy link
Member Author

balloob commented May 29, 2020

The only thing that is now being run in the background compared to before is users explicit platform configuration:

light:
  platform: bla

Discovery mechanism and forward config entry has not been changed, as it was already in the background.

@MartinHjelmare
Copy link
Member

The important change is that the platform setup doesn't wait for entities now. Integrations that rely on that will experience breakage.

@balloob
Copy link
Member Author

balloob commented May 29, 2020

Integrations are unable to load their own platforms from async_setup because of a circular dependency (platforms require component to be set up).

So this would only break if an integration relies on another integration that is exposing entities. We don't have any. All our integrations providing automations do so in a generic manner and don't depend on setting up a specific integration.

I don't foresee this to be a problem.

@MartinHjelmare
Copy link
Member

To be clear: In the existing code there's a straight await dependency from the entity component setup to the platform setup. There's no background scheduling in that line. We do need to schedule to the background the entry forwarding that starts the entity component setup but there's nothing stopping us from having another task wait for the forwarding to be done. If we assume that entities will be added when the entry forwarding is done, and we rely on that to start our second task, this PR will break that assumption.

@balloob
Copy link
Member Author

balloob commented May 29, 2020

Hmm maybe device_sun_light_trigger because it doesn't active its automation until Home Assistant is started (that event didn't exist when it was written)

@balloob
Copy link
Member Author

balloob commented May 29, 2020

Entry forwarding is not impacting by this PR. Forwarding an entry ends up calling EntityComponent.async_setup_entry. That whole chain is still intact without backgrounding.

This only impacts loading user supplied YAML platform config.

@bdraco
Copy link
Member

bdraco commented May 30, 2020

diff --git a/tests/components/websocket_api/test_auth.py b/tests/components/websocket_api/test_auth.py
index a3b2fa1a6f..dc26ac06db 100644
--- a/tests/components/websocket_api/test_auth.py
+++ b/tests/components/websocket_api/test_auth.py
@@ -31,6 +31,7 @@ async def test_auth_events(
     )
 
     await test_auth_active_with_token(hass, no_auth_websocket_client, hass_access_token)
+    await hass.async_block_till_done()
 
     assert len(connected_evt) == 1
     assert not disconnected_evt

Fixed the websocket tests for me. Assumption is that the async_dispatcher_send job doesn't finish before the test checks

while pytest tests/components/websocket_api/test_*.py; do :; done

@bdraco
Copy link
Member

bdraco commented May 30, 2020

Looks like one more here (but didn't fail locally for me)

--- a/tests/components/websocket_api/conftest.py
+++ b/tests/components/websocket_api/conftest.py
@@ -16,6 +16,7 @@ async def websocket_client(hass, hass_ws_client):
 async def no_auth_websocket_client(hass, aiohttp_client):
     """Websocket connection that requires authentication."""
     assert await async_setup_component(hass, "websocket_api", {})
+    await hass.async_block_till_done()
 
     client = await aiohttp_client(hass.http.app)
     ws = await client.ws_connect(URL)

@bdraco
Copy link
Member

bdraco commented May 30, 2020

diff --git a/tests/components/local_file/test_camera.py b/tests/components/local_file/test_camera.py
index ce31ca5061..348bd94d32 100644
--- a/tests/components/local_file/test_camera.py
+++ b/tests/components/local_file/test_camera.py
@@ -25,6 +25,7 @@ async def test_loading_file(hass, hass_client):
                 }
             },
         )
+        await hass.async_block_till_done()
 
     client = await hass_client()
 
@@ -57,6 +58,7 @@ async def test_file_not_readable(hass, caplog):
                 }
             },
         )
+        await hass.async_block_till_done()
 
     assert "Could not read" in caplog.text
     assert "config_test" in caplog.text

The websocket api ones are stumping me.

@bdraco
Copy link
Member

bdraco commented May 31, 2020

🤞 I think the last push on #36304 will fix it. Any time we call assert await async_setup_component(hass, "websocket_api", {}) and then block until done a second time in the same test (the no_auth_websocket_client does a setup as well) it was timing out because it was blocking forever

@bdraco
Copy link
Member

bdraco commented May 31, 2020

Got a clean run on #36304. Taking out all the debug prints and pushing again

Dev automation moved this from Needs review to Reviewer approved May 31, 2020
Copy link
Member

@bdraco bdraco left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

161 files. That was a bit of a death march. Nice work 👍

@bdraco
Copy link
Member

bdraco commented May 31, 2020

3.7 tests passed, for some reason it remade the 3.8 env so its taking longer

@balloob balloob merged commit 276f3af into dev Jun 1, 2020
Dev automation moved this from Reviewer approved to Done Jun 1, 2020
@balloob balloob deleted the async-setup-platform branch June 1, 2020 05:18
@balloob
Copy link
Member Author

balloob commented Jun 1, 2020

💃 💃 💃 💃 💃 💃 💃

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Dev
  
Done
Development

Successfully merging this pull request may close these issues.

None yet

5 participants