@@ -624,17 +624,26 @@ def poll_gemini_batch(batch_name: str, timeout_hours: float = 25) -> Dict[str, A
624624
625625 print (f"\n Polling job: { batch_name } " )
626626 while time .time () < deadline :
627- batch_job = client .batches .get (name = batch_name )
627+ try :
628+ batch_job = client .batches .get (name = batch_name )
629+ except Exception as exc :
630+ err_str = str (exc )
631+ if "404" in err_str or "NOT_FOUND" in err_str :
632+ print (f" Job not found (404) — may have expired: { batch_name } " )
633+ return {"state" : "failed" , "error" : "NOT_FOUND (expired or invalid)" }
634+ raise
635+ # state may be "JOB_STATE_SUCCEEDED" or "JobState.JOB_STATE_SUCCEEDED"
628636 state = str (batch_job .state )
637+ state_normalized = state .split ("." )[- 1 ] # strip "JobState." prefix if present
629638
630- if state == "JOB_STATE_SUCCEEDED" :
639+ if state_normalized == "JOB_STATE_SUCCEEDED" :
631640 print (" Job SUCCEEDED!" )
632641 return {"state" : "succeeded" , "job" : batch_job }
633- elif state == "JOB_STATE_FAILED" :
642+ elif state_normalized == "JOB_STATE_FAILED" :
634643 error = getattr (batch_job , "error" , "unknown error" )
635644 print (f" Job FAILED: { error } " )
636645 return {"state" : "failed" , "error" : str (error ), "job" : batch_job }
637- elif state == "JOB_STATE_CANCELLED" :
646+ elif state_normalized == "JOB_STATE_CANCELLED" :
638647 print (" Job CANCELLED" )
639648 return {"state" : "failed" , "error" : "cancelled" }
640649
@@ -674,8 +683,8 @@ def download_gemini_results(batch_job) -> List[Dict[str, Any]]:
674683 print (f" Downloading results: { file_name } " )
675684
676685 try :
677- # Download the result file
678- content = client .files .download (name = file_name )
686+ # Download the result file (SDK uses file= not name=)
687+ content = client .files .download (file = file_name )
679688 if isinstance (content , bytes ):
680689 content = content .decode ("utf-8" )
681690
@@ -963,13 +972,24 @@ def resume_backfill(db_path: Path) -> None:
963972 return
964973
965974 print (f"Found { len (pending )} pending jobs to resume" )
966- for job in pending :
967- print (f"\n Resuming: { job ['batch_id' ]} " )
968- result = poll_gemini_batch (job ["batch_id" ])
975+ imported_count = 0
976+ failed_count = 0
977+ for i , job in enumerate (pending ):
978+ print (f"\n Resuming [{ i + 1 } /{ len (pending )} ]: { job ['batch_id' ]} " )
979+ try :
980+ result = poll_gemini_batch (job ["batch_id" ])
981+ except Exception as exc :
982+ print (f" ERROR polling job: { exc } " )
983+ save_checkpoint (store , batch_id = job ["batch_id" ], status = "failed" ,
984+ error = str (exc )[:500 ],
985+ completed_at = datetime .now (timezone .utc ).isoformat ())
986+ failed_count += 1
987+ continue
969988
970989 if result ["state" ] == "succeeded" :
971990 batch_results = download_gemini_results (result ["job" ])
972991 import_results (store , batch_results , job ["batch_id" ])
992+ imported_count += 1
973993
974994 # Log usage to Supabase (best-effort)
975995 batch_job = result .get ("job" )
@@ -986,9 +1006,11 @@ def resume_backfill(db_path: Path) -> None:
9861006 save_checkpoint (store , batch_id = job ["batch_id" ], status = "failed" ,
9871007 error = result .get ("error" , "unknown" ),
9881008 completed_at = datetime .now (timezone .utc ).isoformat ())
1009+ failed_count += 1
9891010
9901011 final_stats = store .get_enrichment_stats ()
991- print (f"\n Enrichment: { final_stats ['enriched' ]} /{ final_stats ['total_chunks' ]} ({ final_stats ['percent' ]} %)" )
1012+ print (f"\n Imported { imported_count } jobs, { failed_count } failed" )
1013+ print (f"Enrichment: { final_stats ['enriched' ]} /{ final_stats ['total_chunks' ]} ({ final_stats ['percent' ]} %)" )
9921014
9931015 finally :
9941016 store .close ()
0 commit comments