Approach: orchestrator runs training jobs with strong checkpointing to an object store, retries with exponential backoff, migrates on preemption by rescheduling to new node and restoring latest checkpoint, and deterministically tracks "best model" across attempts by evaluating checkpoint metadata (e.g., validation metric) and keeping global best.python
import time, random
from typing import Optional
# Pseudocode interfaces
class JobAPI:
def submit(node, checkpoint_uri=None) -> job_id: ...
def status(job_id) -> ("RUNNING"|"FAILED"|"SUCCEEDED"|"PREEMPTED"): ...
def request_cancel(job_id): ...
def get_logs(job_id): ...
class ObjectStore:
def upload(path, data): ...
def list_prefix(prefix) -> [uris]: ...
def download(uri) -> data: ...
# Orchestrator
MAX_RETRIES = 5
BASE_BACKOFF = 5 # seconds
MAX_BACKOFF = 300
def choose_node():
# placeholder for scheduling policy
return "node-" + str(random.randint(1,10))
def latest_checkpoint_uri(job_name):
entries = ObjectStore.list_prefix(f"{job_name}/checkpoints/")
return max(entries, key=lambda u: metadata(u).timestamp) if entries else None
def metadata(uri):
# returns object with {timestamp, val_metric, step}
return ObjectStore.download(uri + ".meta")
def update_global_best(job_name, ckpt_uri):
meta = metadata(ckpt_uri)
best = ObjectStore.download(f"{job_name}/best.meta") if exists(f"{job_name}/best.meta") else None
if not best or meta.val_metric > best.val_metric:
ObjectStore.upload(f"{job_name}/best.ckpt", ckpt_uri) # pointer
ObjectStore.upload(f"{job_name}/best.meta", meta)
return True
return False
def orchestrate(job_name, entry_point):
attempt = 0
backoff = BASE_BACKOFF
global_best = None
while attempt <= MAX_RETRIES:
node = choose_node()
ckpt = latest_checkpoint_uri(job_name) # resume if possible
job_id = JobAPI.submit(node, checkpoint_uri=ckpt)
start = time.time()
while True:
s = JobAPI.status(job_id)
if s == "RUNNING":
time.sleep(2)
continue
if s == "SUCCEEDED":
# trainer should have uploaded final checkpoint and meta
final_ckpt = latest_checkpoint_uri(job_name)
update_global_best(job_name, final_ckpt)
return {"status":"SUCCEEDED", "best": ObjectStore.download(f"{job_name}/best.meta")}
if s == "PREEMPTED":
# immediate migration: preserve latest checkpoint, reschedule
latest = latest_checkpoint_uri(job_name)
if latest:
update_global_best(job_name, latest)
JobAPI.request_cancel(job_id)
attempt += 1
break # resubmit
if s == "FAILED":
# transient or deterministic failure: retry with backoff
JobAPI.request_cancel(job_id)
attempt += 1
time.sleep(min(backoff, MAX_BACKOFF))
backoff *= 2
break
# loop continues to resubmit until attempts exhausted
return {"status":"FAILED", "best": ObjectStore.download(f"{job_name}/best.meta") if exists(f"{job_name}/best.meta") else None}
Key points:- Checkpoints and metadata are authoritative; orchestrator picks latest by timestamp/step.- On preemption, we immediately reschedule to a new node using latest checkpoint.- Exponential backoff mitigates flapping; retries limited.- Global best stored atomically as pointer + meta to ensure consistent selection across retries.Edge cases:- Partial checkpoint uploads: use atomic rename or write-then-tag pattern.- Conflicting concurrent uploads: use compare-and-swap on best.meta.- Long resume time: add TTLs, spot/preemptible awareness.Alternatives:- Use lease-based node allocation, consensus service (etcd) for global best, or controller that coordinates multi-node synchronous checkpoints.