"""Dev only: refuse a Space deploy while any job depends on the live Space relay. A push rebuilds the Space, which drops every relay WebSocket and fails the requests in flight. A job that is still starting has no relay yet (it connects about 6 minutes in), and a relay that just dropped keeps its pending requests for a 120 s grace period, so both count as live. Run before `git push`: python dev/predeploy.py [SPACE_URL] # exit 0: safe to deploy; exit 1: live relays or PostTrain jobs (listed) """ import json, sys, urllib.request from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from compute_jobs import kind # noqa: E402 (the same job purposes the dashboard shows) url = (sys.argv[1] if len(sys.argv) > 1 else 'https://benchflow-posttrain-arena.hf.space').rstrip('/') blockers = [] try: status = json.load(urllib.request.urlopen(url + '/api/relay/status', timeout=30)) except Exception as error: sys.exit(f'Could not read {url}/api/relay/status ({error}); check by hand before deploying.') for r in status.get('connected', []): # open or inside the reconnect grace period blockers.append(f"relay {r['run_id']}: {'open' if r.get('open') else 'reconnecting'}, {r.get('requests', 0)} requests, {r.get('in_flight', 0)} in flight") try: from huggingface_hub import HfApi for job in HfApi().list_jobs(namespace='benchflow'): stage = str(job.status.stage).split('.')[-1] what = kind(getattr(job, 'labels', None) or {}) if what and stage in ('RUNNING', 'SCHEDULING'): blockers.append(f"job {(job.labels or {}).get('name') or job.id} ({what}): {stage.lower()}") except Exception as error: sys.exit(f'Could not list HF jobs ({type(error).__name__}); check https://huggingface.co/jobs/benchflow by hand before deploying.') for line in blockers: print(line) if blockers: sys.exit(f'{len(blockers)} live relay(s) or PostTrain job(s); deploying now could break them. Wait until they finish.') print('No relays and no running PostTrain jobs: safe to deploy.')