Update service call return values and error handling (#94657)

* Update return signature of service calls

* Add timeout error handling in websocket api for service calls

* Update recorder tests to remove assertion on service call

* Remove timeout behavior and update callers that depend on it today

* Fix tests

* Add missing else

* await coro directly

* Fix more tests

* Update the intent task to use wait instead of timeout

* Remove script service call limits and limit constants

* Update tests that depend on service call limits

* Use wait instead of wait_for and add test

* Update homeassistant/helpers/intent.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

---------

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
Allen Porter 2023-06-16 07:01:40 -07:00 committed by GitHub
parent 950b25bf42
commit 12129e9d21
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
63 changed files with 388 additions and 434 deletions

View file

@ -493,15 +493,36 @@ class ServiceIntentHandler(IntentHandler):
async def async_call_service(self, intent_obj: Intent, state: State) -> None:
"""Call service on entity."""
hass = intent_obj.hass
await hass.services.async_call(
self.domain,
self.service,
{ATTR_ENTITY_ID: state.entity_id},
context=intent_obj.context,
blocking=True,
limit=self.service_timeout,
await self._run_then_background(
hass.async_create_task(
hass.services.async_call(
self.domain,
self.service,
{ATTR_ENTITY_ID: state.entity_id},
context=intent_obj.context,
blocking=True,
),
f"intent_call_service_{self.domain}_{self.service}",
)
)
async def _run_then_background(self, task: asyncio.Task) -> None:
"""Run task with timeout to (hopefully) catch validation errors.
After the timeout the task will continue to run in the background.
"""
try:
await asyncio.wait({task}, timeout=self.service_timeout)
except asyncio.TimeoutError:
pass
except asyncio.CancelledError:
# Task calling us was cancelled, so cancel service call task, and wait for
# it to be cancelled, within reason, before leaving.
_LOGGER.debug("Service call was cancelled: %s", task.get_name())
task.cancel()
await asyncio.wait({task}, timeout=5)
raise
class IntentCategory(Enum):
"""Category of an intent."""