@@ -1236,6 +1236,8 @@ def sync_pod_status(
12361236 redis_running = False
12371237 pod_done_count = 0
12381238
1239+ all_crashed = True
1240+
12391241 try :
12401242 for name , pod in pods .items ():
12411243 running = False
@@ -1250,22 +1252,39 @@ def sync_pod_status(
12501252 elif phase == "Failed" and pstatus .get ("reason" ) == "Evicted" :
12511253 evicted = True
12521254
1253- status .podStatus [name ].evicted = evicted
1255+ pod_status = status .podStatus [name ]
1256+ pod_status .evicted = evicted
12541257
12551258 if "containerStatuses" in pstatus :
12561259 cstatus = pstatus ["containerStatuses" ][0 ]
12571260
1258- self .handle_terminated_pod (
1259- name , role , status , cstatus ["state" ].get ("terminated" )
1261+ terminated = cstatus ["state" ].get ("terminated" )
1262+
1263+ self .handle_terminated_pod (name , role , status , terminated )
1264+
1265+ waiting = cstatus ["state" ].get ("waiting" )
1266+ pod_status .backoffWait = (
1267+ waiting and waiting .get ("reason" ) == "CrashLoopBackOff"
12601268 )
12611269
1270+ if role == "crawler" :
1271+ # consider crashed if:
1272+ # - in 'waiting' state with CrashLoopBackOff reason
1273+ # - in 'terminated' state with non-zero exit code (will be brief)
1274+ all_crashed = all_crashed and bool (
1275+ pod_status .backoffWait
1276+ or (terminated and pod_status .exitCode != 0 )
1277+ )
1278+
12621279 if role == "crawler" :
12631280 crawler_running = crawler_running or running
12641281 if phase == "Succeeded" :
12651282 pod_done_count += 1
12661283 elif role == "redis" :
12671284 redis_running = redis_running or running
12681285
1286+ status .allCrashed = all_crashed
1287+
12691288 # pylint: disable=broad-except
12701289 except Exception :
12711290 logger .exception (
@@ -1294,13 +1313,14 @@ def handle_terminated_pod(
12941313
12951314 pod_status = status .podStatus [name ]
12961315
1316+ # detect reason
1317+ exit_code = terminated .get ("exitCode" )
1318+
12971319 pod_status .isNewExit = pod_status .exitTime != exit_time
12981320 if pod_status .isNewExit and role == "crawler" :
12991321 pod_status .exitTime = exit_time
13001322 status .anyCrawlPodNewExit = True
1301-
1302- # detect reason
1303- exit_code = terminated .get ("exitCode" )
1323+ status .lastCrawlPodExitCode = exit_code
13041324
13051325 if exit_code == 0 :
13061326 pod_status .reason = "done"
@@ -1877,6 +1897,21 @@ async def update_crawl_state(
18771897 status .stopReason = await self .is_crawl_stopping (crawl , status , stats )
18781898 status .stopping = status .stopReason is not None
18791899
1900+ # if all crashed and last exit was rate-limit exit code (18),
1901+ # set to rate limited state now and return
1902+ if status .allCrashed and status .lastCrawlPodExitCode == 18 :
1903+ if not status .rateLimitedAtTime :
1904+ status .rateLimitedAtTime = date_to_str (dt_now ())
1905+
1906+ await self .set_state (
1907+ "rate-limited" ,
1908+ status ,
1909+ crawl ,
1910+ allowed_from = RUNNING_STATES ,
1911+ )
1912+ status .resync_after = self .fast_retry_secs
1913+ return status
1914+
18801915 # mark crawl as pausing or stopping
18811916 if status .stopping :
18821917 if status .stopReason in PAUSED_STATES :
0 commit comments