()
| 48 | |
| 49 | |
| 50 | def main() -> int: |
| 51 | parser = argparse.ArgumentParser() |
| 52 | parser.add_argument('--ids', default='') |
| 53 | args = parser.parse_args() |
| 54 | ids = [x.strip() for x in args.ids.split(',') if x.strip()] if args.ids else failed_ids() |
| 55 | state = load_json(STATUS_PATH, {'attempts': {}, 'completed': [], 'failed': []}) |
| 56 | done = done_ids() |
| 57 | todo = [bid for bid in ids if bid not in done] |
| 58 | print(json.dumps({'todo_count': len(todo), 'todo': todo[:30]}, ensure_ascii=False, indent=2)) |
| 59 | BATCH_LOG.parent.mkdir(parents=True, exist_ok=True) |
| 60 | for bid in todo: |
| 61 | attempts = int(state['attempts'].get(bid, 0)) |
| 62 | while attempts < MAX_RETRIES: |
| 63 | attempts += 1 |
| 64 | state['attempts'][bid] = attempts |
| 65 | save_json(STATUS_PATH, state) |
| 66 | proc = subprocess.run( |
| 67 | [sys.executable, str(SCRIPT), '--ids', bid, '--model', MODEL], |
| 68 | cwd=str(REPO_ROOT), |
| 69 | text=True, |
| 70 | capture_output=True, |
| 71 | env=dict(os.environ), |
| 72 | ) |
| 73 | with BATCH_LOG.open('a', encoding='utf-8') as fh: |
| 74 | fh.write(f'## {bid} attempt {attempts} rc={proc.returncode}\n') |
| 75 | fh.write(proc.stdout[-4000:]) |
| 76 | if proc.stderr: |
| 77 | fh.write('\n[stderr]\n') |
| 78 | fh.write(proc.stderr[-4000:]) |
| 79 | fh.write('\n\n') |
| 80 | if bid in done_ids(): |
| 81 | if bid not in state['completed']: |
| 82 | state['completed'].append(bid) |
| 83 | state['failed'] = [row for row in state['failed'] if row.get('id') != bid] |
| 84 | save_json(STATUS_PATH, state) |
| 85 | print(f'[done] {bid} in {attempts} attempt(s)') |
| 86 | break |
| 87 | state['failed'] = [row for row in state['failed'] if row.get('id') != bid] |
| 88 | state['failed'].append({'id': bid, 'attempt': attempts, 'returncode': proc.returncode}) |
| 89 | save_json(STATUS_PATH, state) |
| 90 | print(f'[retry] {bid} attempt {attempts}/{MAX_RETRIES} rc={proc.returncode}') |
| 91 | if attempts >= MAX_RETRIES: |
| 92 | break |
| 93 | time.sleep(SLEEP * attempts) |
| 94 | time.sleep(SLEEP) |
| 95 | print(json.dumps({'completed': len(state['completed']), 'failed': len(state['failed'])}, ensure_ascii=False, indent=2)) |
| 96 | save_json(STATUS_PATH, state) |
| 97 | return 0 |
| 98 | |
| 99 | |
| 100 | if __name__ == '__main__': |
no test coverage detected