Skip to content

Commit 09e3f0e

Browse files
committed
add progress bar and per‑job timing metrics to run_parallel
1 parent 228bd29 commit 09e3f0e

1 file changed

Lines changed: 31 additions & 5 deletions

File tree

waters2mzml/parallel.py

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
2434
def _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

Comments
 (0)