@@ -21,6 +21,16 @@ class RetryPolicy:
2121 backoff_factor : float = 2.0
2222
2323
24+ def _progress_bar (done : int , total : int , width : int = 30 ) -> str :
25+ """
26+ Render a simple text progress bar.
27+ Example: [██████------] 6/12
28+ """
29+ filled = int (width * done / total )
30+ bar = "█" * filled + "-" * (width - filled )
31+ return f"[{ bar } ] { done } /{ total } "
32+
33+
2434def _is_retryable (exc : Exception ) -> bool :
2535 return isinstance (exc , MsconvertError )
2636
@@ -38,24 +48,30 @@ def _run_with_retries(
3848 do_postprocess : bool ,
3949 retry_policy : RetryPolicy ,
4050) -> JobResult :
51+ start = time .perf_counter ()
4152 last_exc : Exception | None = None
4253
4354 for attempt in range (retry_policy .max_retries + 1 ):
4455 try :
4556 logger .debug (f"Starting job for { raw_dir } (attempt { attempt + 1 } )" )
46- return process_single_raw (
57+ result = process_single_raw (
4758 raw_dir = raw_dir ,
4859 msconvert_path = msconvert_path ,
4960 output_dir = output_dir ,
5061 centroid = centroid ,
5162 use_docker = use_docker ,
5263 do_postprocess = do_postprocess ,
5364 )
65+ duration = time .perf_counter () - start
66+ logger .info (f"Job completed for { raw_dir } in { duration :.2f} s" )
67+ return result
68+
5469 except Exception as exc :
5570 last_exc = exc
5671
5772 if not _is_retryable (exc ):
58- logger .error (f"Fatal error on { raw_dir } : { exc } " )
73+ duration = time .perf_counter () - start
74+ logger .error (f"Fatal error on { raw_dir } after { duration :.2f} s: { exc } " )
5975 return JobResult (
6076 raw_dir = raw_dir ,
6177 mzml_path = None ,
@@ -64,7 +80,10 @@ def _run_with_retries(
6480 )
6581
6682 if attempt == retry_policy .max_retries :
67- logger .error (f"Retries exhausted for { raw_dir } : { exc } " )
83+ duration = time .perf_counter () - start
84+ logger .error (
85+ f"Retries exhausted for { raw_dir } after { duration :.2f} s: { exc } "
86+ )
6887 return JobResult (
6988 raw_dir = raw_dir ,
7089 mzml_path = None ,
@@ -79,6 +98,8 @@ def _run_with_retries(
7998 )
8099 time .sleep (delay )
81100
101+ duration = time .perf_counter () - start
102+ logger .error (f"Unknown failure on { raw_dir } after { duration :.2f} s" )
82103 return JobResult (
83104 raw_dir = raw_dir ,
84105 mzml_path = None ,
@@ -145,12 +166,17 @@ def run_parallel(
145166
146167 results .append (result )
147168
169+ # Progress bar
170+ bar = _progress_bar (idx , total )
148171 if result .success :
149- logger .info (f"[OK] ( { idx } / { total } ) { raw_dir } " )
172+ logger .info (f"{ bar } [OK] { raw_dir } " )
150173 else :
151174 logger .error (
152- f"[FAIL] ( { idx } / { total } ) { raw_dir } — { result .error .splitlines ()[- 1 ]} "
175+ f"{ bar } [FAIL] { raw_dir } — { result .error .splitlines ()[- 1 ]} "
153176 )
154177
178+ ok = sum (r .success for r in results )
179+ fail = total - ok
180+ logger .info (f"Completed { total } jobs: { ok } OK, { fail } failed" )
155181 results .sort (key = lambda r : str (r .raw_dir ))
156182 return results
0 commit comments