-
Notifications
You must be signed in to change notification settings - Fork 14
refactor: Rework client timeout #384
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
Changes from all commits
87911c4
2aa165f
bdb814a
431a458
b1d81db
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,12 +11,13 @@ | |
| class ResourceClient(BaseClient): | ||
| """Base class for sub-clients manipulating a single resource.""" | ||
|
|
||
| def _get(self) -> dict | None: | ||
| def _get(self, timeout_secs: int | None = None) -> dict | None: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could have the default timeout constant as the default as well, right?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It could. I guess this makes only difference if someone decides to use the client directly and not through Currently it set on |
||
| try: | ||
| response = self.http_client.call( | ||
| url=self.url, | ||
| method='GET', | ||
| params=self._params(), | ||
| timeout_secs=timeout_secs, | ||
| ) | ||
|
|
||
| return parse_date_fields(pluck_data(response.json())) | ||
|
|
@@ -26,22 +27,24 @@ def _get(self) -> dict | None: | |
|
|
||
| return None | ||
|
|
||
| def _update(self, updated_fields: dict) -> dict: | ||
| def _update(self, updated_fields: dict, timeout_secs: int | None = None) -> dict: | ||
| response = self.http_client.call( | ||
| url=self._url(), | ||
| method='PUT', | ||
| params=self._params(), | ||
| json=updated_fields, | ||
| timeout_secs=timeout_secs, | ||
| ) | ||
|
|
||
| return parse_date_fields(pluck_data(response.json())) | ||
|
|
||
| def _delete(self) -> None: | ||
| def _delete(self, timeout_secs: int | None = None) -> None: | ||
| try: | ||
| self.http_client.call( | ||
| url=self._url(), | ||
| method='DELETE', | ||
| params=self._params(), | ||
| timeout_secs=timeout_secs, | ||
| ) | ||
|
|
||
| except ApifyApiError as exc: | ||
|
|
@@ -52,12 +55,13 @@ def _delete(self) -> None: | |
| class ResourceClientAsync(BaseClientAsync): | ||
| """Base class for async sub-clients manipulating a single resource.""" | ||
|
|
||
| async def _get(self) -> dict | None: | ||
| async def _get(self, timeout_secs: int | None = None) -> dict | None: | ||
| try: | ||
| response = await self.http_client.call( | ||
| url=self.url, | ||
| method='GET', | ||
| params=self._params(), | ||
| timeout_secs=timeout_secs, | ||
| ) | ||
|
|
||
| return parse_date_fields(pluck_data(response.json())) | ||
|
|
@@ -67,22 +71,24 @@ async def _get(self) -> dict | None: | |
|
|
||
| return None | ||
|
|
||
| async def _update(self, updated_fields: dict) -> dict: | ||
| async def _update(self, updated_fields: dict, timeout_secs: int | None = None) -> dict: | ||
| response = await self.http_client.call( | ||
| url=self._url(), | ||
| method='PUT', | ||
| params=self._params(), | ||
| json=updated_fields, | ||
| timeout_secs=timeout_secs, | ||
| ) | ||
|
|
||
| return parse_date_fields(pluck_data(response.json())) | ||
|
|
||
| async def _delete(self) -> None: | ||
| async def _delete(self, timeout_secs: int | None = None) -> None: | ||
| try: | ||
| await self.http_client.call( | ||
| url=self._url(), | ||
| method='DELETE', | ||
| params=self._params(), | ||
| timeout_secs=timeout_secs, | ||
| ) | ||
|
|
||
| except ApifyApiError as exc: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,6 +17,9 @@ | |
| import httpx | ||
| from apify_shared.types import JSONSerializable | ||
|
|
||
| _SMALL_TIMEOUT = 5 # For fast and common actions. Suitable for idempotent actions. | ||
| _MEDIUM_TIMEOUT = 30 # For actions that may take longer. | ||
|
|
||
|
|
||
| class DatasetClient(ResourceClient): | ||
| """Sub-client for manipulating a single dataset.""" | ||
|
|
@@ -34,7 +37,7 @@ def get(self) -> dict | None: | |
| Returns: | ||
| The retrieved dataset, or None, if it does not exist. | ||
| """ | ||
| return self._get() | ||
| return self._get(timeout_secs=_SMALL_TIMEOUT) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's strange to have no way to override this... Could we have a timeout parameter here as well?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there any use-case for this? |
||
|
|
||
| def update(self, *, name: str | None = None) -> dict: | ||
| """Update the dataset with specified fields. | ||
|
|
@@ -49,14 +52,14 @@ def update(self, *, name: str | None = None) -> dict: | |
| """ | ||
| updated_fields = {'name': name} | ||
|
|
||
| return self._update(filter_out_none_values_recursively(updated_fields)) | ||
| return self._update(filter_out_none_values_recursively(updated_fields), timeout_secs=_SMALL_TIMEOUT) | ||
|
|
||
| def delete(self) -> None: | ||
| """Delete the dataset. | ||
|
|
||
| https://docs.apify.com/api/v2#/reference/datasets/dataset/delete-dataset | ||
| """ | ||
| return self._delete() | ||
| return self._delete(timeout_secs=_SMALL_TIMEOUT) | ||
|
|
||
| def list_items( | ||
| self, | ||
|
|
@@ -539,6 +542,7 @@ def push_items(self, items: JSONSerializable) -> None: | |
| params=self._params(), | ||
| data=data, | ||
| json=json, | ||
| timeout_secs=_MEDIUM_TIMEOUT, | ||
| ) | ||
|
|
||
| def get_statistics(self) -> dict | None: | ||
|
|
@@ -554,6 +558,7 @@ def get_statistics(self) -> dict | None: | |
| url=self._url('statistics'), | ||
| method='GET', | ||
| params=self._params(), | ||
| timeout_secs=_SMALL_TIMEOUT, | ||
| ) | ||
| return pluck_data(response.json()) | ||
| except ApifyApiError as exc: | ||
|
|
@@ -578,7 +583,7 @@ async def get(self) -> dict | None: | |
| Returns: | ||
| The retrieved dataset, or None, if it does not exist. | ||
| """ | ||
| return await self._get() | ||
| return await self._get(timeout_secs=_SMALL_TIMEOUT) | ||
|
|
||
| async def update(self, *, name: str | None = None) -> dict: | ||
| """Update the dataset with specified fields. | ||
|
|
@@ -593,14 +598,14 @@ async def update(self, *, name: str | None = None) -> dict: | |
| """ | ||
| updated_fields = {'name': name} | ||
|
|
||
| return await self._update(filter_out_none_values_recursively(updated_fields)) | ||
| return await self._update(filter_out_none_values_recursively(updated_fields), timeout_secs=_SMALL_TIMEOUT) | ||
|
|
||
| async def delete(self) -> None: | ||
| """Delete the dataset. | ||
|
|
||
| https://docs.apify.com/api/v2#/reference/datasets/dataset/delete-dataset | ||
| """ | ||
| return await self._delete() | ||
| return await self._delete(timeout_secs=_SMALL_TIMEOUT) | ||
|
|
||
| async def list_items( | ||
| self, | ||
|
|
@@ -990,6 +995,7 @@ async def push_items(self, items: JSONSerializable) -> None: | |
| params=self._params(), | ||
| data=data, | ||
| json=json, | ||
| timeout_secs=_MEDIUM_TIMEOUT, | ||
| ) | ||
|
|
||
| async def get_statistics(self) -> dict | None: | ||
|
|
@@ -1005,6 +1011,7 @@ async def get_statistics(self) -> dict | None: | |
| url=self._url('statistics'), | ||
| method='GET', | ||
| params=self._params(), | ||
| timeout_secs=_SMALL_TIMEOUT, | ||
| ) | ||
| return pluck_data(response.json()) | ||
| except ApifyApiError as exc: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So if you pass None, it will still use the default timeout?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is same as the previous implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm. I understand it's BC and BC is sacred, but I would expect None to mean "no timeout"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To limit the scope of this change, I will avoid adding unnecessary breaking change to this PR, but it might be added in own PR if needed.