Repository navigation
feat!: expose the timeout tiers on the public API - #1046
Merged
Merged
Conversation
Mirrors the Python client: three tiers (short 5 s, medium 30 s, long 360 s) plus `noTimeout`, each method assigned one, tier durations and a `timeoutMaxSecs` cap set on the constructor, a per-call `timeout` override on every method, and a warning when a requested timeout is capped. The timeout of a retried request now doubles from the requested value on every attempt instead of compounding. BREAKING CHANGE: The `timeoutSecs` option of `ApifyClient` is replaced by `timeoutShortSecs`, `timeoutMediumSecs`, `timeoutLongSecs` and `timeoutMaxSecs`. Methods outside the storage clients now use the `short` or `medium` tier instead of the global 360 s. Every method that sends a request accepts a `timeout` option, so methods without options gained an options parameter and methods that take a payload gained a second one. The run timeout option of `ActorClient.start()` / `call()`, `TaskClient.start()` / `call()` and `RunClient.resurrect()` is renamed from `timeout` to `runTimeout`. The `timeoutSecs` option of `KeyValueStoreClient.setRecord()` is renamed to `timeout`.
Contributor
|
See more at https://github.com/apify/apify-client-js/actions/runs/34573272623#summary-103179907823 |
# Conflicts: # test/http_client.test.ts
janbuchar
reviewed
Sep 10, 2026
The number a timeout takes is a count of seconds, which the option name now says. `runTimeout` becomes `runTimeoutSecs` for the same reason. BREAKING CHANGE: the per-call `timeout` option is `timeoutSecs` on every method, `ApifyRequestConfig.timeout` is `timeoutSecs`, and the run timeout of `start()`, `call()` and `resurrect()` is `runTimeoutSecs`.
# Conflicts: # test/http_client.test.ts
This was referenced Sep 10, 2026
# Conflicts: # src/resource_clients/dataset.ts
janbuchar
approved these changes
Sep 12, 2026
vdusek
added a commit
that referenced
this pull request
Sep 14, 2026
Non-public members in this repo carried a leading underscore on top of the `private` / `protected` keyword. Crawlee v4 dropped that convention and we agreed to follow it here. This renames every such member across `src/`, so none are left. `LoggerActorRedirect._log()` and `_outputWithConsole()` in `src/resource_clients/log.ts` keep their names, since both come from the `Logger` base class in `@apify/log`. The code samples in `CONTRIBUTING.md` and the public API report follow the rename. ## Renamed helpers The protected helpers on the base clients show up in the API report, so subclasses calling the old names have to switch. Where a bare name would collide with a public method, the helper got a suffix. | Old | New | | --- | --- | | `_url` | `buildUrl` | | `_publicUrl` | `buildPublicUrl` | | `_params` | `buildParams` | | `_subResourceOptions` | `subResourceOptions` | | `_toSafeId` | `toSafeId` | | `_listPaginatedFromCallback` | `listPaginatedFromCallback` | | `_get` | `getResource` | | `_update` | `updateResource` | | `_delete` | `deleteResource` | | `_waitForFinish` | `waitForJobFinish` | | `_list` | `listResources` | | `_listPaginated` | `listResourcesPaginated` | | `_create` | `createResource` | | `_getOrCreate` | `getOrCreateResource` | | `_batchAddRequests` | `addRequestBatch` | | `_batchAddRequestsWithRetries` | `addRequestBatchWithRetries` | The names match what #1046 picked for the files it touches, so whichever of the two lands second rebases onto near-identical lines. ## ApifyApiError.clientMethod `clientMethod` scrapes the stack with `\._?([A-Za-z]+)`, and the underscore was what turned an internal frame like `ActorCollectionClient._list` into the public-looking `list`. A public method that returns the promise of a shared helper without awaiting it leaves only the helper's frame on the async stack, so after the rename the field would report `listResources` to users. A `PUBLIC_METHOD_BY_HELPER` map in `apify_api_error.ts` maps helper frames back to the public method, and `test/apify_api_error.test.ts` covers both the Node and the browser build. Closes #1057 *✍️ Drafted by Claude Code*
B4nan
pushed a commit
that referenced
this pull request
Sep 30, 2026
### Issue - Closes #1029 - This is a port of the following: - apify/apify-client-python#653 - apify/apify-client-python#664 - apify/apify-client-python#962 ### Description The client already chose a timeout per method internally, but the only public knob was the global `timeoutSecs`, so a call that legitimately takes longer had no way to ask for more time. The tiers are now public, following the Python client, and every method that sends a request takes a `timeoutSecs` option. | Tier | Default | Covers | | --- | --- | --- | | `short` | 5 s | metadata reads and writes | | `medium` | 30 s | listing, batch and trigger calls | | `long` | 360 s | downloads, uploads and streaming | | `noTimeout` | none | polling that waits for a job to finish | Every method keeps the tier its Python counterpart has. `timeoutMaxSecs` caps a single attempt and bounds the growth across retries, which doubles from the requested value (T, 2T, 4T, 8T). The six `waitForFinish` methods get the API's one-minute hold on top of their tier, so the client doesn't abort a request the API is still holding and start a second run on retry. `timeoutSecs` takes a tier name, a number of seconds, or `'noTimeout'`. The unit lives in the option name rather than in the value, the way `waitSecs` and `timeoutMaxSecs` already do. The last commit also drops the leading underscore from non-public members, as agreed in review. Where the underscore was covering a collision with a public member, the helper got a new name: `_url` to `buildUrl`, `_params` to `buildParams`, `_get` to `getResource`, `_list` to `listResources`, `_waitForFinish` to `waitForJobFinish`, `_batchAddRequests` to `addRequestBatch`, and `ApifyClient._options` to `subClientOptions`. `src/apify_api_error.ts` and `src/statistics.ts` are left for #1057. ## Testing `test/client_timeouts.test.ts` covers the tier defaults, per-call overrides, the `waitForFinish` hold, `runTimeoutSecs` and the `requestQueue(id, { timeoutSecs })` cap. `test/http_client.test.ts` covers the cap warning and the retry growth. `test/apify_api_error.test.ts` guards `clientMethod`, which reads the renamed helpers off the stack. ## Breaking changes - `timeoutSecs` on the constructor is replaced by `timeoutShortSecs`, `timeoutMediumSecs`, `timeoutLongSecs` and `timeoutMaxSecs`. - Outside the storage clients, methods used the global 360 s and now use `short` or `medium`, so a call that waited out a slow API can fail sooner. - The run timeout of `ActorClient.start()` / `call()`, `TaskClient.start()` / `call()` and `RunClient.resurrect()` is now `runTimeoutSecs`. TypeScript reports a leftover `timeout` at compile time, and the option schemas are strict, so JavaScript gets an `ArgumentValidationError` instead of a silently dropped run limit. - `client.httpClient.call()` takes `timeoutSecs` in seconds, where the axios field it replaces took milliseconds. A direct call that passed `timeout: 30000` becomes `timeoutSecs: 30`. - Methods without options gained an options parameter, and methods that take a payload gained a second one. - The `protected` helpers of `ApiClient`, `ResourceClient` and `ResourceCollectionClient` are renamed, which reaches anyone subclassing them. `KeyValueStoreClient.setRecord()` keeps its `timeoutSecs`, and a plain number still means what it did in v2, so Crawlee's `setValue()` needs no paired PR. The option now takes a tier name or `'noTimeout'` as well. The same goes for `client.requestQueue(id, { timeoutSecs })`, which caps the tier of every request that queue client sends. *✍️ Drafted by Claude Code*
B4nan
pushed a commit
that referenced
this pull request
Sep 30, 2026
Non-public members in this repo carried a leading underscore on top of the `private` / `protected` keyword. Crawlee v4 dropped that convention and we agreed to follow it here. This renames every such member across `src/`, so none are left. `LoggerActorRedirect._log()` and `_outputWithConsole()` in `src/resource_clients/log.ts` keep their names, since both come from the `Logger` base class in `@apify/log`. The code samples in `CONTRIBUTING.md` and the public API report follow the rename. ## Renamed helpers The protected helpers on the base clients show up in the API report, so subclasses calling the old names have to switch. Where a bare name would collide with a public method, the helper got a suffix. | Old | New | | --- | --- | | `_url` | `buildUrl` | | `_publicUrl` | `buildPublicUrl` | | `_params` | `buildParams` | | `_subResourceOptions` | `subResourceOptions` | | `_toSafeId` | `toSafeId` | | `_listPaginatedFromCallback` | `listPaginatedFromCallback` | | `_get` | `getResource` | | `_update` | `updateResource` | | `_delete` | `deleteResource` | | `_waitForFinish` | `waitForJobFinish` | | `_list` | `listResources` | | `_listPaginated` | `listResourcesPaginated` | | `_create` | `createResource` | | `_getOrCreate` | `getOrCreateResource` | | `_batchAddRequests` | `addRequestBatch` | | `_batchAddRequestsWithRetries` | `addRequestBatchWithRetries` | The names match what #1046 picked for the files it touches, so whichever of the two lands second rebases onto near-identical lines. ## ApifyApiError.clientMethod `clientMethod` scrapes the stack with `\._?([A-Za-z]+)`, and the underscore was what turned an internal frame like `ActorCollectionClient._list` into the public-looking `list`. A public method that returns the promise of a shared helper without awaiting it leaves only the helper's frame on the async stack, so after the rename the field would report `listResources` to users. A `PUBLIC_METHOD_BY_HELPER` map in `apify_api_error.ts` maps helper frames back to the public method, and `test/apify_api_error.test.ts` covers both the Node and the browser build. Closes #1057 *✍️ Drafted by Claude Code*
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue
Description
The client already chose a timeout per method internally, but the only public knob was the global
timeoutSecs, so a call that legitimately takes longer had no way to ask for more time. The tiers are now public, following the Python client, and every method that sends a request takes atimeoutSecsoption.shortmediumlongnoTimeoutEvery method keeps the tier its Python counterpart has.
timeoutMaxSecscaps a single attempt and bounds the growth across retries, which doubles from the requested value (T, 2T, 4T, 8T). The sixwaitForFinishmethods get the API's one-minute hold on top of their tier, so the client doesn't abort a request the API is still holding and start a second run on retry.timeoutSecstakes a tier name, a number of seconds, or'noTimeout'. The unit lives in the option name rather than in the value, the waywaitSecsandtimeoutMaxSecsalready do.The last commit also drops the leading underscore from non-public members, as agreed in review. Where the underscore was covering a collision with a public member, the helper got a new name:
_urltobuildUrl,_paramstobuildParams,_gettogetResource,_listtolistResources,_waitForFinishtowaitForJobFinish,_batchAddRequeststoaddRequestBatch, andApifyClient._optionstosubClientOptions.src/apify_api_error.tsandsrc/statistics.tsare left for #1057.Testing
test/client_timeouts.test.tscovers the tier defaults, per-call overrides, thewaitForFinishhold,runTimeoutSecsand therequestQueue(id, { timeoutSecs })cap.test/http_client.test.tscovers the cap warning and the retry growth.test/apify_api_error.test.tsguardsclientMethod, which reads the renamed helpers off the stack.Breaking changes
timeoutSecson the constructor is replaced bytimeoutShortSecs,timeoutMediumSecs,timeoutLongSecsandtimeoutMaxSecs.shortormedium, so a call that waited out a slow API can fail sooner.ActorClient.start()/call(),TaskClient.start()/call()andRunClient.resurrect()is nowrunTimeoutSecs. TypeScript reports a leftovertimeoutat compile time, and the option schemas are strict, so JavaScript gets anArgumentValidationErrorinstead of a silently dropped run limit.client.httpClient.call()takestimeoutSecsin seconds, where the axios field it replaces took milliseconds. A direct call that passedtimeout: 30000becomestimeoutSecs: 30.protectedhelpers ofApiClient,ResourceClientandResourceCollectionClientare renamed, which reaches anyone subclassing them.KeyValueStoreClient.setRecord()keeps itstimeoutSecs, and a plain number still means what it did in v2, so Crawlee'ssetValue()needs no paired PR. The option now takes a tier name or'noTimeout'as well. The same goes forclient.requestQueue(id, { timeoutSecs }), which caps the tier of every request that queue client sends.✍️ Drafted by Claude Code