@@ -192,14 +192,14 @@ listed in `KeyValueStoreKeysPage::items`. Its fields:
192192| ` get_request(id) ` | ` &str ` | ` Option<RequestQueueRequest> ` | Reads a request. |
193193| ` update_request(request, forefront) ` | ` &RequestQueueRequest ` , ` bool ` | ` RequestQueueOperationInfo ` | Updates a request. |
194194| ` delete_request(id) ` | ` &str ` | ` () ` | Deletes a request. |
195- | ` list_and_lock_head(lock_secs, limit) ` | ` i64 ` , ` Option<i64> ` | ` Value ` | Locks head requests. |
196- | ` batch_add_requests(requests, forefront ) ` | ` &[RequestQueueRequest] ` , ` bool ` | ` Value ` | Batch add. |
197- | ` batch_delete_requests(requests) ` | ` &[impl Serialize] ` | ` Value ` | Batch delete. |
198- | ` list_requests(options) ` | ` ListRequestsOptions { limit, exclusive_start_id, cursor, filter } ` | ` Value ` | List requests (cursor/filter pagination). |
195+ | ` list_and_lock_head(lock_secs, limit) ` | ` i64 ` , ` Option<i64> ` | ` LockedRequestQueueHead ` | Locks head requests. |
196+ | ` batch_add_requests(requests, options ) ` | ` &[RequestQueueRequest] ` , ` BatchAddRequestsOptions ` | ` BatchRequestsOperationResult ` | Batch add, with automatic chunking, bounded parallelism, and retries for rate-limited requests . |
197+ | ` batch_delete_requests(requests) ` | ` &[impl Serialize] ` | ` BatchRequestsOperationResult ` | Batch delete (max 25 requests per call; larger inputs are rejected client-side) . |
198+ | ` list_requests(options) ` | ` ListRequestsOptions { limit, exclusive_start_id, cursor, filter } ` | ` RequestQueueRequestsPage ` | List requests (cursor/filter pagination). |
199199| ` paginate_requests(page_limit) ` | ` Option<i64> ` | ` RequestQueueRequestsIterator ` | Lazy request iterator. |
200- | ` prolong_request_lock(id, lock_secs, forefront) ` | ` &str ` , ` i64 ` , ` bool ` | ` Value ` | Extend a lock. |
200+ | ` prolong_request_lock(id, lock_secs, forefront) ` | ` &str ` , ` i64 ` , ` bool ` | ` RequestLockInfo ` | Extend a lock. |
201201| ` delete_request_lock(id, forefront) ` | ` &str ` , ` bool ` | ` () ` | Release a lock. |
202- | ` unlock_requests() ` | — | ` Value ` | Release all this client's locks. |
202+ | ` unlock_requests() ` | — | ` UnlockRequestsResult ` | Release all this client's locks. |
203203
204204` paginate_requests(page_limit) ` returns a ` RequestQueueRequestsIterator ` — a lazy, page-fetching
205205iterator (parity with the Store iterator in [ Store, users and logs] ( misc.md#apify-store--clientstore ) ).
@@ -241,22 +241,62 @@ while let Some(request) = iter.next().await? {
241241# }
242242```
243243
244- The ` forefront ` boolean (on ` add_request ` , ` update_request ` , ` batch_add_requests ` ,
245- ` prolong_request_lock ` , ` delete_request_lock ` ) controls queue ordering: ` true ` puts the
246- request(s) at the ** front** of the queue so they are handled before the existing backlog;
247- ` false ` (the usual choice) appends them at the ** back** .
244+ The ` forefront ` boolean (on ` add_request ` , ` update_request ` ,
245+ ` prolong_request_lock ` , ` delete_request_lock ` ) and the ` BatchAddRequestsOptions::forefront ` field
246+ (on ` batch_add_requests ` ) control queue ordering: ` true ` puts the request(s) at the ** front** of
247+ the queue so they are handled before the existing backlog; ` false ` (the usual choice) appends
248+ them at the ** back** .
248249
249- Some request-queue methods return an untyped ` serde_json::Value ` because the API responses are
250- open-ended and most callers do not consume them structurally. Their shapes (read fields with
251- ` value.get("...") ` ):
250+ ### ` batch_add_requests `
252251
253- - ` list_and_lock_head ` → an object with ` items ` (the locked head requests), ` limit ` ,
254- ` queueModifiedAt ` , ` hadMultipleClients ` , and the granted ` lockSecs ` .
255- - ` batch_add_requests ` / ` batch_delete_requests ` → an object with ` processedRequests ` and
256- ` unprocessedRequests ` arrays.
257- - ` list_requests ` → an object with ` items ` (the page of requests), ` count ` , ` limit ` , and
258- ` exclusiveStartId ` for cursor continuation.
259- - ` unlock_requests ` → an object reporting how many locks were released (` unlockedCount ` ).
252+ ` batch_add_requests(requests, options) ` is the efficient way to add many requests at once —
253+ significantly cheaper than calling ` add_request ` in a loop. It mirrors the reference client's
254+ ` batchAddRequests ` :
255+
256+ - The input is automatically split into chunks that respect both the API's per-call request-count
257+ limit (25) and its request-body byte-size limit (~ 9 MiB), so there is no need to chunk manually.
258+ - Chunks are sent with up to ` options.max_parallel ` requests in flight at once (default 5).
259+ - Any request an API call reports as ` unprocessed ` (typically due to rate limiting) is retried
260+ automatically with exponential backoff, up to ` options.max_unprocessed_requests_retries ` times
261+ (default 3). A request still unprocessed after every retry is reported in
262+ ` BatchRequestsOperationResult::unprocessed_requests ` rather than failing the call.
263+ - Every request should set ` RequestQueueRequest::unique_key ` (or rely on the API's ` url `
264+ fallback) so a retried request can be correlated back to the original input.
265+
266+ ``` rust,no_run
267+ use apify_client::models::RequestQueueRequest;
268+ use apify_client::BatchAddRequestsOptions;
269+ # use apify_client::ApifyClient;
270+ # async fn run(client: ApifyClient) -> Result<(), Box<dyn std::error::Error>> {
271+ let queue = client.request_queues().get_or_create(None).await?;
272+ let queue_client = client.request_queue(&queue.id);
273+
274+ let requests: Vec<RequestQueueRequest> = (0..3)
275+ .map(|i| RequestQueueRequest {
276+ id: None,
277+ url: format!("https://example.com/{i}"),
278+ unique_key: Some(format!("page-{i}")),
279+ method: Some("GET".to_string()),
280+ user_data: None,
281+ extra: Default::default(),
282+ })
283+ .collect();
284+
285+ let result = queue_client
286+ .batch_add_requests(&requests, BatchAddRequestsOptions::default())
287+ .await?;
288+ println!(
289+ "added {} request(s), {} unprocessed",
290+ result.processed_requests.len(),
291+ result.unprocessed_requests.len()
292+ );
293+ # Ok(())
294+ # }
295+ ```
296+
297+ ` batch_delete_requests ` does ** not** auto-chunk (matching the reference client): it accepts at
298+ most 25 requests per call, identified by ` id ` and/or ` unique_key ` (not the full
299+ ` RequestQueueRequest ` shape), and returns ` ApifyClientError::InvalidArgument ` for a larger input.
260300
261301### ` RequestQueueRequest ` and request-queue return types
262302
@@ -304,6 +344,14 @@ Relevant return-type fields:
304344 ` was_already_handled: bool ` .
305345- ` RequestQueueHead ` : ` limit: i64 ` , ` had_multiple_clients: bool ` ,
306346 ` items: Vec<RequestQueueRequest> ` , ` extra: Extra ` (any other fields returned by the API).
347+ - ` LockedRequestQueueHead ` (from ` list_and_lock_head ` ): same fields as ` RequestQueueHead ` plus
348+ ` lock_secs: i64 ` , ` queue_has_locked_requests: Option<bool> ` , ` client_key: Option<String> ` .
349+ - ` RequestQueueRequestsPage ` (from ` list_requests ` ): ` limit: i64 ` , ` items: Vec<RequestQueueRequest> ` ,
350+ ` cursor ` / ` next_cursor ` / ` exclusive_start_id ` (all ` Option<String> ` ) for pagination.
351+ - ` BatchRequestsOperationResult ` (from ` batch_add_requests ` / ` batch_delete_requests ` ):
352+ ` processed_requests: Vec<ProcessedRequest> ` , ` unprocessed_requests: Vec<UnprocessedRequest> ` .
353+ - ` RequestLockInfo ` (from ` prolong_request_lock ` ): ` lock_expires_at: DateTime<Utc> ` .
354+ - ` UnlockRequestsResult ` (from ` unlock_requests ` ): ` unlocked_count: i64 ` .
307355- ` KeyValueStoreKeysPage ` : ` limit: i64 ` , ` is_truncated: bool ` , ` exclusive_start_key ` ,
308356 ` next_exclusive_start_key ` (both ` Option<String> ` ), ` items: Vec<KeyValueStoreKey> ` .
309357
0 commit comments