mirror of
https://github.com/home-assistant/core.git
synced 2025-07-13 16:27:08 +00:00
Improve rate limit handling in Habitica integration (#121763)
* Adjustments to requests and update interval due to rate limiting * Use debounced refresh for to-do lists * Use debounced refresh in switch and buttons * Request refresh only if a to-do was changed * Update task order provisionally in the coordinator
This commit is contained in:
parent
66a8733333
commit
4b62dcfd19
@ -113,7 +113,7 @@ class HabiticaButton(HabiticaBase, ButtonEntity):
|
||||
translation_key="service_call_exception",
|
||||
) from e
|
||||
else:
|
||||
await self.coordinator.async_refresh()
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
|
@ -15,6 +15,7 @@ from habitipy.aio import HabitipyAsync
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||
from homeassistant.helpers.debounce import Debouncer
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
||||
from .const import DOMAIN
|
||||
@ -41,7 +42,13 @@ class HabiticaDataUpdateCoordinator(DataUpdateCoordinator[HabiticaData]):
|
||||
hass,
|
||||
_LOGGER,
|
||||
name=DOMAIN,
|
||||
update_interval=timedelta(seconds=30),
|
||||
update_interval=timedelta(seconds=60),
|
||||
request_refresh_debouncer=Debouncer(
|
||||
hass,
|
||||
_LOGGER,
|
||||
cooldown=5,
|
||||
immediate=False,
|
||||
),
|
||||
)
|
||||
self.api = habitipy
|
||||
|
||||
@ -51,6 +58,9 @@ class HabiticaDataUpdateCoordinator(DataUpdateCoordinator[HabiticaData]):
|
||||
tasks_response = await self.api.tasks.user.get()
|
||||
tasks_response.extend(await self.api.tasks.user.get(type="completedTodos"))
|
||||
except ClientResponseError as error:
|
||||
if error.status == HTTPStatus.TOO_MANY_REQUESTS:
|
||||
_LOGGER.debug("Currently rate limited, skipping update")
|
||||
return self.data
|
||||
raise UpdateFailed(f"Error communicating with API: {error}") from error
|
||||
|
||||
return HabiticaData(user=user_response, tasks=tasks_response)
|
||||
@ -73,4 +83,4 @@ class HabiticaDataUpdateCoordinator(DataUpdateCoordinator[HabiticaData]):
|
||||
translation_key="service_call_exception",
|
||||
) from e
|
||||
else:
|
||||
await self.async_refresh()
|
||||
await self.async_request_refresh()
|
||||
|
@ -93,7 +93,7 @@ class BaseHabiticaListEntity(HabiticaBase, TodoListEntity):
|
||||
translation_key=f"delete_{self.entity_description.key}_failed",
|
||||
) from e
|
||||
|
||||
await self.coordinator.async_refresh()
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
async def async_move_todo_item(
|
||||
self, uid: str, previous_uid: str | None = None
|
||||
@ -121,9 +121,22 @@ class BaseHabiticaListEntity(HabiticaBase, TodoListEntity):
|
||||
translation_key=f"move_{self.entity_description.key}_item_failed",
|
||||
translation_placeholders={"pos": str(pos)},
|
||||
) from e
|
||||
else:
|
||||
# move tasks in the coordinator until we have fresh data
|
||||
tasks = self.coordinator.data.tasks
|
||||
new_pos = (
|
||||
tasks.index(next(task for task in tasks if task["id"] == previous_uid))
|
||||
+ 1
|
||||
if previous_uid
|
||||
else 0
|
||||
)
|
||||
old_pos = tasks.index(next(task for task in tasks if task["id"] == uid))
|
||||
tasks.insert(new_pos, tasks.pop(old_pos))
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
async def async_update_todo_item(self, item: TodoItem) -> None:
|
||||
"""Update a Habitica todo."""
|
||||
refresh_required = False
|
||||
current_item = next(
|
||||
(task for task in (self.todo_items or []) if task.uid == item.uid),
|
||||
None,
|
||||
@ -132,7 +145,6 @@ class BaseHabiticaListEntity(HabiticaBase, TodoListEntity):
|
||||
if TYPE_CHECKING:
|
||||
assert item.uid
|
||||
assert current_item
|
||||
assert item.due
|
||||
|
||||
if (
|
||||
self.entity_description.key is HabiticaTodoList.TODOS
|
||||
@ -142,18 +154,24 @@ class BaseHabiticaListEntity(HabiticaBase, TodoListEntity):
|
||||
else:
|
||||
date = None
|
||||
|
||||
try:
|
||||
await self.coordinator.api.tasks[item.uid].put(
|
||||
text=item.summary,
|
||||
notes=item.description or "",
|
||||
date=date,
|
||||
)
|
||||
except ClientResponseError as e:
|
||||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key=f"update_{self.entity_description.key}_item_failed",
|
||||
translation_placeholders={"name": item.summary or ""},
|
||||
) from e
|
||||
if (
|
||||
item.summary != current_item.summary
|
||||
or item.description != current_item.description
|
||||
or item.due != current_item.due
|
||||
):
|
||||
try:
|
||||
await self.coordinator.api.tasks[item.uid].put(
|
||||
text=item.summary,
|
||||
notes=item.description or "",
|
||||
date=date,
|
||||
)
|
||||
refresh_required = True
|
||||
except ClientResponseError as e:
|
||||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key=f"update_{self.entity_description.key}_item_failed",
|
||||
translation_placeholders={"name": item.summary or ""},
|
||||
) from e
|
||||
|
||||
try:
|
||||
# Score up or down if item status changed
|
||||
@ -164,6 +182,7 @@ class BaseHabiticaListEntity(HabiticaBase, TodoListEntity):
|
||||
score_result = (
|
||||
await self.coordinator.api.tasks[item.uid].score["up"].post()
|
||||
)
|
||||
refresh_required = True
|
||||
elif (
|
||||
current_item.status is TodoItemStatus.COMPLETED
|
||||
and item.status == TodoItemStatus.NEEDS_ACTION
|
||||
@ -171,6 +190,7 @@ class BaseHabiticaListEntity(HabiticaBase, TodoListEntity):
|
||||
score_result = (
|
||||
await self.coordinator.api.tasks[item.uid].score["down"].post()
|
||||
)
|
||||
refresh_required = True
|
||||
else:
|
||||
score_result = None
|
||||
|
||||
@ -189,8 +209,8 @@ class BaseHabiticaListEntity(HabiticaBase, TodoListEntity):
|
||||
persistent_notification.async_create(
|
||||
self.hass, message=msg, title="Habitica"
|
||||
)
|
||||
|
||||
await self.coordinator.async_refresh()
|
||||
if refresh_required:
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
|
||||
class HabiticaTodosListEntity(BaseHabiticaListEntity):
|
||||
@ -254,7 +274,7 @@ class HabiticaTodosListEntity(BaseHabiticaListEntity):
|
||||
translation_placeholders={"name": item.summary or ""},
|
||||
) from e
|
||||
|
||||
await self.coordinator.async_refresh()
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
|
||||
class HabiticaDailiesListEntity(BaseHabiticaListEntity):
|
||||
|
Loading…
x
Reference in New Issue
Block a user