26
26
27
27
logger = getLogger (__name__ )
28
28
29
+ COUNTER = iter (range (10000 ))
29
30
30
31
class ApifyRequestQueueClient (RequestQueueClient ):
31
32
"""An Apify platform implementation of the request queue client."""
@@ -294,18 +295,25 @@ async def fetch_next_request(self) -> Request | None:
294
295
Returns:
295
296
The request or `None` if there are no more pending requests.
296
297
"""
298
+ call_time = next (COUNTER )
297
299
# Ensure the queue head has requests if available. Fetching the head with lock to prevent race conditions.
300
+ logger .debug (f'Before _fetch_lock, { call_time } ' )
298
301
async with self ._fetch_lock :
302
+ logger .debug (f'Fetching, { call_time } ' )
299
303
await self ._ensure_head_is_non_empty ()
300
304
301
305
# If queue head is empty after ensuring, there are no requests
302
306
if not self ._queue_head :
307
+ logger .debug (f'Empty, { call_time } ' )
303
308
return None
304
309
305
310
# Get the next request ID from the queue head
306
311
next_request_id = self ._queue_head .popleft ()
312
+ logger .debug (f'New request, { call_time } ' )
307
313
314
+ logger .debug (f'Before hydrate, { call_time } ' )
308
315
request = await self ._get_or_hydrate_request (next_request_id )
316
+ logger .debug (f'After hydrate, { call_time } ' )
309
317
310
318
# Handle potential inconsistency where request might not be in the main table yet
311
319
if request is None :
@@ -324,14 +332,15 @@ async def fetch_next_request(self) -> Request | None:
324
332
return None
325
333
326
334
# Use get request to ensure we have the full request object.
327
- request = await self .get_request (request .id )
335
+ # request = await self.get_request(request.id) This seems redundant
328
336
if request is None :
329
337
logger .debug (
330
338
'Request fetched from the beginning of queue was not found in the RQ' ,
331
339
extra = {'nextRequestId' : next_request_id },
332
340
)
333
341
return None
334
342
343
+ logger .debug (f'{ request .retry_count = } , { call_time } ' )
335
344
return request
336
345
337
346
@override
@@ -394,42 +403,48 @@ async def reclaim_request(
394
403
"""
395
404
# Check if the request was marked as handled and clear it. When reclaiming,
396
405
# we want to put the request back for processing.
406
+ call_time = next (COUNTER )
397
407
if request .was_already_handled :
398
408
request .handled_at = None
399
409
400
- try :
401
- # Update the request in the API.
402
- processed_request = await self ._update_request (request , forefront = forefront )
403
- processed_request .unique_key = request .unique_key
404
-
405
- # If the request was previously handled, decrement our handled count since
406
- # we're putting it back for processing.
407
- if request .was_already_handled and not processed_request .was_already_handled :
408
- self ._assumed_handled_count -= 1
409
-
410
- # Update the cache
411
- cache_key = unique_key_to_request_id (request .unique_key )
412
- self ._cache_request (
413
- cache_key ,
414
- processed_request ,
415
- hydrated_request = request ,
416
- )
410
+ async with self ._fetch_lock :
411
+ try :
412
+ # Update the request in the API.
413
+ logger .debug (f'Before _update_request reclaiming, { call_time } ' )
414
+ processed_request = await self ._update_request (request , forefront = forefront )
415
+ logger .debug (f'After _update_request reclaiming, { call_time } ' )
416
+ processed_request .unique_key = request .unique_key
417
+
418
+ # If the request was previously handled, decrement our handled count since
419
+ # we're putting it back for processing.
420
+ if request .was_already_handled and not processed_request .was_already_handled :
421
+ self ._assumed_handled_count -= 1
422
+
423
+ # Update the cache
424
+ cache_key = unique_key_to_request_id (request .unique_key )
425
+ self ._cache_request (
426
+ cache_key ,
427
+ processed_request ,
428
+ hydrated_request = request ,
429
+ )
417
430
418
- # If we're adding to the forefront, we need to check for forefront requests
419
- # in the next list_head call
420
- if forefront :
421
- self ._should_check_for_forefront_requests = True
431
+ # If we're adding to the forefront, we need to check for forefront requests
432
+ # in the next list_head call
433
+ if forefront :
434
+ self ._should_check_for_forefront_requests = True
422
435
423
- # Try to release the lock on the request
424
- try :
425
- await self ._delete_request_lock (request .id , forefront = forefront )
426
- except Exception as err :
427
- logger .debug (f'Failed to delete request lock for request { request .id } ' , exc_info = err )
428
- except Exception as exc :
429
- logger .debug (f'Error reclaiming request { request .id } : { exc !s} ' )
430
- return None
431
- else :
432
- return processed_request
436
+ # Try to release the lock on the request
437
+ try :
438
+ logger .debug (f'Before _delete_request_lock reclaiming, { call_time } ' )
439
+ await self ._delete_request_lock (request .id , forefront = forefront )
440
+ logger .debug (f'After _delete_request_lock reclaiming, { call_time } ' )
441
+ except Exception as err :
442
+ logger .debug (f'Failed to delete request lock for request { request .id } ' , exc_info = err )
443
+ except Exception as exc :
444
+ logger .debug (f'Error reclaiming request { request .id } : { exc !s} ' )
445
+ return None
446
+ else :
447
+ return processed_request
433
448
434
449
@override
435
450
async def is_empty (self ) -> bool :
@@ -438,9 +453,14 @@ async def is_empty(self) -> bool:
438
453
Returns:
439
454
True if the queue is empty, False otherwise.
440
455
"""
441
- head = await self ._list_head (limit = 1 , lock_time = None )
442
-
443
- return len (head .items ) == 0 and not self ._queue_has_locked_requests
456
+ call_time = next (COUNTER )
457
+ logger .debug (f'Before _list_head is_empty, { call_time } ' )
458
+ async with self ._fetch_lock :
459
+ logger .debug (f'During _list_head is_empty, { call_time } ' )
460
+ head = await self ._list_head (limit = 1 , lock_time = None )
461
+ logger .debug (f'After _list_head is_empty, { call_time } ' )
462
+ logger .debug (f'Finish _list_head is_empty, { call_time } ' )
463
+ return len (head .items ) == 0 and not self ._queue_has_locked_requests
444
464
445
465
async def _ensure_head_is_non_empty (self ) -> None :
446
466
"""Ensure that the queue head has requests if they are available in the queue."""
@@ -551,8 +571,9 @@ async def _list_head(
551
571
A collection of requests from the beginning of the queue.
552
572
"""
553
573
# Return from cache if available and we're not checking for new forefront requests
574
+ call_time = next (COUNTER )
554
575
if self ._queue_head and not self ._should_check_for_forefront_requests :
555
- logger .debug (f'Using cached queue head with { len (self ._queue_head )} requests' )
576
+ logger .debug (f'Using cached queue head with { len (self ._queue_head )} requests, { call_time } ' )
556
577
557
578
# Create a list of requests from the cached queue head
558
579
items = []
@@ -571,7 +592,7 @@ async def _list_head(
571
592
queue_has_locked_requests = self ._queue_has_locked_requests ,
572
593
lock_time = lock_time ,
573
594
)
574
-
595
+ logger . debug ( f'Updating cached queue head with { len ( self . _queue_head ) } requests, { call_time } ' )
575
596
leftover_buffer = list [str ]()
576
597
if self ._should_check_for_forefront_requests :
577
598
leftover_buffer = list (self ._queue_head )
@@ -615,13 +636,14 @@ async def _list_head(
615
636
),
616
637
hydrated_request = request ,
617
638
)
618
-
639
+ logger . debug ( f'Adding to head, { call_time } ' )
619
640
self ._queue_head .append (request .id )
641
+ logger .debug (f'Cached queue head with { len (self ._queue_head )} requests, { call_time } ' )
620
642
621
643
for leftover_request_id in leftover_buffer :
622
644
# After adding new requests to the forefront, any existing leftover locked request is kept in the end.
623
645
self ._queue_head .append (leftover_request_id )
624
-
646
+ logger . debug ( f'Cached queue head with { len ( self . _queue_head ) } requests, { call_time } ' )
625
647
return RequestQueueHead .model_validate (response )
626
648
627
649
async def _prolong_request_lock (
0 commit comments