Skip to content

Commit 0b35bbe

Browse files
vdusekclaude
andauthored
refactor!: update default timeout tiers on non-storage resource clients (#664)
## Goal Update default timeout tiers on individual resource client methods. ## Tier philosophy | Tier | Value | Use for | |------|-------|---------| | `short` (5s) | Simple metadata CRUD | get/update/delete single resources, quick checks | | `medium` (30s) | Moderate operations | list with pagination, create, batch ops, triggering runs/builds | | `long` (360s) | Heavy operations | downloading/streaming large data, large payloads | | `no_timeout` | Indefinite | Polling/waiting (`wait_for_finish`, `call`, streaming logs) | ## Current state Only storage clients (Dataset, KVS, RQ) were tiered in PR #653. Everything else defaults to `'long'` — meaning even a simple `actor.get()` has a 360s timeout. ## Changes description ### ActorClient | Method | Current | Recommended | Rationale | |--------|---------|-------------|-----------| | `get()` | long | **short** | Simple metadata fetch | | `update()` | long | **short** | Simple metadata update | | `delete()` | long | **short** | Simple delete | | `start()` | long | **medium** | Triggers a run, returns run info (some server processing) | | `call()` | long | **no_timeout** | Starts run AND waits for finish — can take minutes or even much more | | `build()` | long | **medium** | Triggers a build, returns quickly | | `default_build()` | long | **short** | Simple metadata fetch | | `last_run()` | long | **short** | Simple metadata fetch | | `validate_input()` | long | **short** | Quick validation call | ### ActorCollectionClient | Method | Current | Recommended | Rationale | |--------|---------|-------------|-----------| | `list()` | long | **medium** | Paginated list, could be large | | `create()` | long | **medium** | Creates resource, some processing | ### ActorVersionClient | Method | Current | Recommended | Rationale | |--------|---------|-------------|-----------| | `get()` | long | **short** | Simple metadata | | `update()` | long | **short** | Simple metadata | | `delete()` | long | **short** | Simple delete | ### ActorVersionCollectionClient | Method | Current | Recommended | Rationale | |--------|---------|-------------|-----------| | `list()` | long | **short** | Typically small lists | | `create()` | long | **short** | Simple create | ### ActorEnvVarClient | Method | Current | Recommended | Rationale | |--------|---------|-------------|-----------| | `get()` | long | **short** | Simple metadata | | `update()` | long | **short** | Simple metadata | | `delete()` | long | **short** | Simple delete | ### ActorEnvVarCollectionClient | Method | Current | Recommended | Rationale | |--------|---------|-------------|-----------| | `list()` | long | **short** | Small lists | | `create()` | long | **short** | Simple create | ### BuildClient | Method | Current | Recommended | Rationale | |--------|---------|-------------|-----------| | `get()` | long | **short** | Simple metadata | | `delete()` | long | **short** | Simple delete | | `abort()` | long | **short** | Sends abort signal, returns immediately | | `get_open_api_definition()` | long | **medium** | Could be a larger JSON payload | | `wait_for_finish()` | no_timeout | no_timeout | Already correct | ### BuildCollectionClient | Method | Current | Recommended | Rationale | |--------|---------|-------------|-----------| | `list()` | long | **medium** | Paginated list | ### RunClient | Method | Current | Recommended | Rationale | |--------|---------|-------------|-----------| | `get()` | long | **short** | Simple metadata | | `update()` | long | **short** | Simple metadata | | `delete()` | long | **short** | Simple delete | | `abort()` | long | **short** | Sends abort signal | | `wait_for_finish()` | no_timeout | no_timeout | Already correct | | `metamorph()` | long | **medium** | Triggers transformation | | `resurrect()` | long | **medium** | Restarts a run | | `reboot()` | long | **medium** | Reboots a run | | `get_streamed_log()` | long | **long** | Streaming, keep long | | `charge()` | long | **short** | Quick API call | | `get_status_message_watcher()` | long | **long** | Long-lived watcher | ### RunCollectionClient | Method | Current | Recommended | Rationale | |--------|---------|-------------|-----------| | `list()` | long | **medium** | Paginated list | ### TaskClient | Method | Current | Recommended | Rationale | |--------|---------|-------------|-----------| | `get()` | long | **short** | Simple metadata | | `update()` | long | **short** | Simple metadata | | `delete()` | long | **short** | Simple delete | | `start()` | long | **medium** | Triggers a run | | `call()` | long | **no_timeout** | Starts and waits for completion | | `get_input()` | long | **short** | Simple metadata | | `update_input()` | long | **short** | Simple metadata update | | `last_run()` | long | **short** | Simple metadata | ### TaskCollectionClient | Method | Current | Recommended | Rationale | |--------|---------|-------------|-----------| | `list()` | long | **medium** | Paginated list | | `create()` | long | **medium** | Creates resource | ### ScheduleClient | Method | Current | Recommended | Rationale | |--------|---------|-------------|-----------| | `get()` | long | **short** | Simple metadata | | `update()` | long | **short** | Simple metadata | | `delete()` | long | **short** | Simple delete | | `get_log()` | long | **medium** | Returns list of schedule invocations | ### ScheduleCollectionClient | Method | Current | Recommended | Rationale | |--------|---------|-------------|-----------| | `list()` | long | **medium** | Paginated list | | `create()` | long | **short** | Simple create | ### WebhookClient | Method | Current | Recommended | Rationale | |--------|---------|-------------|-----------| | `get()` | long | **short** | Simple metadata | | `update()` | long | **short** | Simple metadata | | `delete()` | long | **short** | Simple delete | | `test()` | long | **medium** | Triggers test dispatch | ### WebhookCollectionClient | Method | Current | Recommended | Rationale | |--------|---------|-------------|-----------| | `list()` | long | **medium** | Paginated list | | `create()` | long | **short** | Simple create | ### WebhookDispatchClient | Method | Current | Recommended | Rationale | |--------|---------|-------------|-----------| | `get()` | long | **short** | Simple metadata | ### WebhookDispatchCollectionClient | Method | Current | Recommended | Rationale | |--------|---------|-------------|-----------| | `list()` | long | **medium** | Paginated list | ### StoreCollectionClient | Method | Current | Recommended | Rationale | |--------|---------|-------------|-----------| | `list()` | long | **medium** | Paginated list | ### LogClient | Method | Current | Recommended | Rationale | |--------|---------|-------------|-----------| | `get()` | long | **long** | This is not metadata call. Logs can be large — keep as is | | `get_as_bytes()` | long | **long** | Same | | `stream()` | long | **long** | Streaming — long is reasonable | ### UserClient | Method | Current | Recommended | Rationale | |--------|---------|-------------|-----------| | `get()` | long | **short** | Simple metadata | | `monthly_usage()` | long | **short** | Simple metadata | | `limits()` | long | **short** | Simple metadata | | `update_limits()` | long | **short** | Simple metadata update | ### Storage Collection Clients (currently all `long`) | Client.Method | Current | Recommended | Rationale | |--------|---------|-------------|-----------| | `DatasetCollectionClient.list()` | long | **medium** | Paginated list | | `DatasetCollectionClient.get_or_create()` | long | **short** | Quick idempotent op | | `KeyValueStoreCollectionClient.list()` | long | **medium** | Paginated list | | `KeyValueStoreCollectionClient.get_or_create()` | long | **short** | Quick idempotent op | | `RequestQueueCollectionClient.list()` | long | **medium** | Paginated list | | `RequestQueueCollectionClient.get_or_create()` | long | **short** | Quick idempotent op | ## Summary of Changes - **~60 methods** `long` → `short` (simple CRUD on non-storage resources) - **~20 methods** `long` → `medium` (list operations, creates, trigger operations) - **2 methods** `long` → `no_timeout` (`actor.call()`, `task.call()`) - **~10 methods** stay `long` (log operations, streaming, data-heavy ops) - **Storage clients** (dataset, kvs, request_queue) already well-tiered — only their collection clients need updates ## Test plan - [x] CI passes --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent b0b2dac commit 0b35bbe

23 files changed

+136
-136
lines changed

src/apify_client/_resource_clients/actor.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ def __init__(
8585
**kwargs,
8686
)
8787

88-
def get(self, *, timeout: Timeout = 'long') -> Actor | None:
88+
def get(self, *, timeout: Timeout = 'short') -> Actor | None:
8989
"""Retrieve the Actor.
9090
9191
https://docs.apify.com/api/v2#/reference/actors/actor-object/get-actor
@@ -129,7 +129,7 @@ def update(
129129
pricing_infos: list[dict[str, Any]] | None = None,
130130
actor_permission_level: ActorPermissionLevel | None = None,
131131
tagged_builds: dict[str, None | dict[str, str]] | None = None,
132-
timeout: Timeout = 'long',
132+
timeout: Timeout = 'short',
133133
) -> Actor:
134134
"""Update the Actor with the specified fields.
135135
@@ -209,7 +209,7 @@ def update(
209209
result = self._update(timeout=timeout, **actor_fields.model_dump(by_alias=True, exclude_none=True))
210210
return ActorResponse.model_validate(result).data
211211

212-
def delete(self, *, timeout: Timeout = 'long') -> None:
212+
def delete(self, *, timeout: Timeout = 'short') -> None:
213213
"""Delete the Actor.
214214
215215
https://docs.apify.com/api/v2#/reference/actors/actor-object/delete-actor
@@ -233,7 +233,7 @@ def start(
233233
force_permission_level: ActorPermissionLevel | None = None,
234234
wait_for_finish: int | None = None,
235235
webhooks: list[dict] | None = None,
236-
timeout: Timeout = 'long',
236+
timeout: Timeout = 'medium',
237237
) -> Run:
238238
"""Start the Actor and immediately return the Run object.
239239
@@ -310,7 +310,7 @@ def call(
310310
force_permission_level: ActorPermissionLevel | None = None,
311311
wait_duration: timedelta | None = None,
312312
logger: Logger | None | Literal['default'] = 'default',
313-
timeout: Timeout = 'long',
313+
timeout: Timeout = 'no_timeout',
314314
) -> Run | None:
315315
"""Start the Actor and wait for it to finish before returning the Run object.
316316
@@ -386,7 +386,7 @@ def build(
386386
tag: str | None = None,
387387
use_cache: bool | None = None,
388388
wait_for_finish: int | None = None,
389-
timeout: Timeout = 'long',
389+
timeout: Timeout = 'medium',
390390
) -> Build:
391391
"""Build the Actor.
392392
@@ -444,7 +444,7 @@ def default_build(
444444
self,
445445
*,
446446
wait_for_finish: int | None = None,
447-
timeout: Timeout = 'long',
447+
timeout: Timeout = 'short',
448448
) -> BuildClient:
449449
"""Retrieve Actor's default build.
450450
@@ -533,7 +533,7 @@ def validate_input(
533533
*,
534534
build_tag: str | None = None,
535535
content_type: str | None = None,
536-
timeout: Timeout = 'long',
536+
timeout: Timeout = 'short',
537537
) -> bool:
538538
"""Validate an input for the Actor that defines an input schema.
539539
@@ -581,7 +581,7 @@ def __init__(
581581
**kwargs,
582582
)
583583

584-
async def get(self, *, timeout: Timeout = 'long') -> Actor | None:
584+
async def get(self, *, timeout: Timeout = 'short') -> Actor | None:
585585
"""Retrieve the Actor.
586586
587587
https://docs.apify.com/api/v2#/reference/actors/actor-object/get-actor
@@ -625,7 +625,7 @@ async def update(
625625
pricing_infos: list[dict[str, Any]] | None = None,
626626
actor_permission_level: ActorPermissionLevel | None = None,
627627
tagged_builds: dict[str, None | dict[str, str]] | None = None,
628-
timeout: Timeout = 'long',
628+
timeout: Timeout = 'short',
629629
) -> Actor:
630630
"""Update the Actor with the specified fields.
631631
@@ -705,7 +705,7 @@ async def update(
705705
result = await self._update(timeout=timeout, **actor_fields.model_dump(by_alias=True, exclude_none=True))
706706
return ActorResponse.model_validate(result).data
707707

708-
async def delete(self, *, timeout: Timeout = 'long') -> None:
708+
async def delete(self, *, timeout: Timeout = 'short') -> None:
709709
"""Delete the Actor.
710710
711711
https://docs.apify.com/api/v2#/reference/actors/actor-object/delete-actor
@@ -729,7 +729,7 @@ async def start(
729729
force_permission_level: ActorPermissionLevel | None = None,
730730
wait_for_finish: int | None = None,
731731
webhooks: list[dict] | None = None,
732-
timeout: Timeout = 'long',
732+
timeout: Timeout = 'medium',
733733
) -> Run:
734734
"""Start the Actor and immediately return the Run object.
735735
@@ -806,7 +806,7 @@ async def call(
806806
force_permission_level: ActorPermissionLevel | None = None,
807807
wait_duration: timedelta | None = None,
808808
logger: Logger | None | Literal['default'] = 'default',
809-
timeout: Timeout = 'long',
809+
timeout: Timeout = 'no_timeout',
810810
) -> Run | None:
811811
"""Start the Actor and wait for it to finish before returning the Run object.
812812
@@ -886,7 +886,7 @@ async def build(
886886
tag: str | None = None,
887887
use_cache: bool | None = None,
888888
wait_for_finish: int | None = None,
889-
timeout: Timeout = 'long',
889+
timeout: Timeout = 'medium',
890890
) -> Build:
891891
"""Build the Actor.
892892
@@ -944,7 +944,7 @@ async def default_build(
944944
self,
945945
*,
946946
wait_for_finish: int | None = None,
947-
timeout: Timeout = 'long',
947+
timeout: Timeout = 'short',
948948
) -> BuildClientAsync:
949949
"""Retrieve Actor's default build.
950950
@@ -1033,7 +1033,7 @@ async def validate_input(
10331033
*,
10341034
build_tag: str | None = None,
10351035
content_type: str | None = None,
1036-
timeout: Timeout = 'long',
1036+
timeout: Timeout = 'short',
10371037
) -> bool:
10381038
"""Validate an input for the Actor that defines an input schema.
10391039

src/apify_client/_resource_clients/actor_collection.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def list(
4949
offset: int | None = None,
5050
desc: bool | None = None,
5151
sort_by: Literal['createdAt', 'stats.lastRunStartedAt'] | None = 'createdAt',
52-
timeout: Timeout = 'long',
52+
timeout: Timeout = 'medium',
5353
) -> ListOfActors:
5454
"""List the Actors the user has created or used.
5555
@@ -94,7 +94,7 @@ def create(
9494
actor_standby_idle_timeout: timedelta | None = None,
9595
actor_standby_build: str | None = None,
9696
actor_standby_memory_mbytes: int | None = None,
97-
timeout: Timeout = 'long',
97+
timeout: Timeout = 'medium',
9898
) -> Actor:
9999
"""Create a new Actor.
100100
@@ -194,7 +194,7 @@ async def list(
194194
offset: int | None = None,
195195
desc: bool | None = None,
196196
sort_by: Literal['createdAt', 'stats.lastRunStartedAt'] | None = 'createdAt',
197-
timeout: Timeout = 'long',
197+
timeout: Timeout = 'medium',
198198
) -> ListOfActors:
199199
"""List the Actors the user has created or used.
200200
@@ -239,7 +239,7 @@ async def create(
239239
actor_standby_idle_timeout: timedelta | None = None,
240240
actor_standby_build: str | None = None,
241241
actor_standby_memory_mbytes: int | None = None,
242-
timeout: Timeout = 'long',
242+
timeout: Timeout = 'medium',
243243
) -> Actor:
244244
"""Create a new Actor.
245245

src/apify_client/_resource_clients/actor_env_var.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def __init__(
3131
**kwargs,
3232
)
3333

34-
def get(self, *, timeout: Timeout = 'long') -> EnvVar | None:
34+
def get(self, *, timeout: Timeout = 'short') -> EnvVar | None:
3535
"""Return information about the Actor environment variable.
3636
3737
https://docs.apify.com/api/v2#/reference/actors/environment-variable-object/get-environment-variable
@@ -53,7 +53,7 @@ def update(
5353
is_secret: bool | None = None,
5454
name: str,
5555
value: str,
56-
timeout: Timeout = 'long',
56+
timeout: Timeout = 'short',
5757
) -> EnvVar:
5858
"""Update the Actor environment variable with specified fields.
5959
@@ -74,7 +74,7 @@ def update(
7474
)
7575
return EnvVarResponse.model_validate(result).data
7676

77-
def delete(self, *, timeout: Timeout = 'long') -> None:
77+
def delete(self, *, timeout: Timeout = 'short') -> None:
7878
"""Delete the Actor environment variable.
7979
8080
https://docs.apify.com/api/v2#/reference/actors/environment-variable-object/delete-environment-variable
@@ -106,7 +106,7 @@ def __init__(
106106
**kwargs,
107107
)
108108

109-
async def get(self, *, timeout: Timeout = 'long') -> EnvVar | None:
109+
async def get(self, *, timeout: Timeout = 'short') -> EnvVar | None:
110110
"""Return information about the Actor environment variable.
111111
112112
https://docs.apify.com/api/v2#/reference/actors/environment-variable-object/get-environment-variable
@@ -128,7 +128,7 @@ async def update(
128128
is_secret: bool | None = None,
129129
name: str,
130130
value: str,
131-
timeout: Timeout = 'long',
131+
timeout: Timeout = 'short',
132132
) -> EnvVar:
133133
"""Update the Actor environment variable with specified fields.
134134
@@ -149,7 +149,7 @@ async def update(
149149
)
150150
return EnvVarResponse.model_validate(result).data
151151

152-
async def delete(self, *, timeout: Timeout = 'long') -> None:
152+
async def delete(self, *, timeout: Timeout = 'short') -> None:
153153
"""Delete the Actor environment variable.
154154
155155
https://docs.apify.com/api/v2#/reference/actors/environment-variable-object/delete-environment-variable

src/apify_client/_resource_clients/actor_env_var_collection.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def __init__(
2929
**kwargs,
3030
)
3131

32-
def list(self, *, timeout: Timeout = 'long') -> ListOfEnvVars:
32+
def list(self, *, timeout: Timeout = 'short') -> ListOfEnvVars:
3333
"""List the available Actor environment variables.
3434
3535
https://docs.apify.com/api/v2#/reference/actors/environment-variable-collection/get-list-of-environment-variables
@@ -49,7 +49,7 @@ def create(
4949
is_secret: bool | None = None,
5050
name: str,
5151
value: str,
52-
timeout: Timeout = 'long',
52+
timeout: Timeout = 'short',
5353
) -> EnvVar:
5454
"""Create a new Actor environment variable.
5555
@@ -90,7 +90,7 @@ def __init__(
9090
**kwargs,
9191
)
9292

93-
async def list(self, *, timeout: Timeout = 'long') -> ListOfEnvVars:
93+
async def list(self, *, timeout: Timeout = 'short') -> ListOfEnvVars:
9494
"""List the available Actor environment variables.
9595
9696
https://docs.apify.com/api/v2#/reference/actors/environment-variable-collection/get-list-of-environment-variables
@@ -110,7 +110,7 @@ async def create(
110110
is_secret: bool | None = None,
111111
name: str,
112112
value: str,
113-
timeout: Timeout = 'long',
113+
timeout: Timeout = 'short',
114114
) -> EnvVar:
115115
"""Create a new Actor environment variable.
116116

src/apify_client/_resource_clients/actor_version.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def __init__(
4949
**kwargs,
5050
)
5151

52-
def get(self, *, timeout: Timeout = 'long') -> Version | None:
52+
def get(self, *, timeout: Timeout = 'short') -> Version | None:
5353
"""Return information about the Actor version.
5454
5555
https://docs.apify.com/api/v2#/reference/actors/version-object/get-version
@@ -76,7 +76,7 @@ def update(
7676
git_repo_url: str | None = None,
7777
tarball_url: str | None = None,
7878
github_gist_url: str | None = None,
79-
timeout: Timeout = 'long',
79+
timeout: Timeout = 'short',
8080
) -> Version:
8181
"""Update the Actor version with specified fields.
8282
@@ -115,7 +115,7 @@ def update(
115115
result = self._update(timeout=timeout, **version_fields.model_dump(by_alias=True, exclude_none=True))
116116
return VersionResponse.model_validate(result).data
117117

118-
def delete(self, *, timeout: Timeout = 'long') -> None:
118+
def delete(self, *, timeout: Timeout = 'short') -> None:
119119
"""Delete the Actor version.
120120
121121
https://docs.apify.com/api/v2#/reference/actors/version-object/delete-version
@@ -165,7 +165,7 @@ def __init__(
165165
**kwargs,
166166
)
167167

168-
async def get(self, *, timeout: Timeout = 'long') -> Version | None:
168+
async def get(self, *, timeout: Timeout = 'short') -> Version | None:
169169
"""Return information about the Actor version.
170170
171171
https://docs.apify.com/api/v2#/reference/actors/version-object/get-version
@@ -192,7 +192,7 @@ async def update(
192192
git_repo_url: str | None = None,
193193
tarball_url: str | None = None,
194194
github_gist_url: str | None = None,
195-
timeout: Timeout = 'long',
195+
timeout: Timeout = 'short',
196196
) -> Version:
197197
"""Update the Actor version with specified fields.
198198
@@ -231,7 +231,7 @@ async def update(
231231
result = await self._update(timeout=timeout, **version_fields.model_dump(by_alias=True, exclude_none=True))
232232
return VersionResponse.model_validate(result).data
233233

234-
async def delete(self, *, timeout: Timeout = 'long') -> None:
234+
async def delete(self, *, timeout: Timeout = 'short') -> None:
235235
"""Delete the Actor version.
236236
237237
https://docs.apify.com/api/v2#/reference/actors/version-object/delete-version

src/apify_client/_resource_clients/actor_version_collection.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def __init__(
4444
**kwargs,
4545
)
4646

47-
def list(self, *, timeout: Timeout = 'long') -> ListOfVersions:
47+
def list(self, *, timeout: Timeout = 'short') -> ListOfVersions:
4848
"""List the available Actor versions.
4949
5050
https://docs.apify.com/api/v2#/reference/actors/version-collection/get-list-of-versions
@@ -70,7 +70,7 @@ def create(
7070
git_repo_url: str | None = None,
7171
tarball_url: str | None = None,
7272
github_gist_url: str | None = None,
73-
timeout: Timeout = 'long',
73+
timeout: Timeout = 'short',
7474
) -> Version:
7575
"""Create a new Actor version.
7676
@@ -131,7 +131,7 @@ def __init__(
131131
**kwargs,
132132
)
133133

134-
async def list(self, *, timeout: Timeout = 'long') -> ListOfVersions:
134+
async def list(self, *, timeout: Timeout = 'short') -> ListOfVersions:
135135
"""List the available Actor versions.
136136
137137
https://docs.apify.com/api/v2#/reference/actors/version-collection/get-list-of-versions
@@ -157,7 +157,7 @@ async def create(
157157
git_repo_url: str | None = None,
158158
tarball_url: str | None = None,
159159
github_gist_url: str | None = None,
160-
timeout: Timeout = 'long',
160+
timeout: Timeout = 'short',
161161
) -> Version:
162162
"""Create a new Actor version.
163163

0 commit comments

Comments
 (0)