Spaces:
Paused
Paused
File size: 2,536 Bytes
1a36c6b da839c2 1a36c6b da839c2 1a36c6b da839c2 1a36c6b da839c2 1a36c6b da839c2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | """Where jobs execute: Modal (default) or RunPod serverless.
Both backends expose the same two calls, so the API does not care which one is configured:
submit(job_input, execution_timeout_s, function) -> {"id": ..., "status": "IN_QUEUE"}
status(job_id) -> {"status", "output"?, "error"?, "executionTime"?, "delayTime"?}
Times are in milliseconds. The worker also reports its own wall time as ``output["worker_seconds"]``,
which is used when a backend does not report execution time itself (Modal).
`function` names the worker function (see worker/modal_app.py). Modal deploys all of them; RunPod's single
endpoint image only has the MuJoCo ones (``RunPodClient.FUNCTIONS``).
"""
from __future__ import annotations
import logging
import os
from pathlib import Path
from typing import Protocol
from .config import Settings
TERMINAL = {"COMPLETED", "FAILED", "CANCELLED", "TIMED_OUT"}
BACKENDS = ("modal", "runpod")
log = logging.getLogger("rosdiff.runs")
class BackendError(RuntimeError):
"""The backend could not be reached or refused the request. The run's status is left unchanged."""
class SimBackend(Protocol):
name: str
def supports(self, function: str) -> bool: ...
def submit(self, job_input: dict, execution_timeout_s: int, function: str) -> dict: ...
def status(self, job_id: str) -> dict: ...
def modal_credentials_present() -> bool:
if os.environ.get("MODAL_TOKEN_ID") and os.environ.get("MODAL_TOKEN_SECRET"):
return True
return Path(os.environ.get("MODAL_CONFIG_PATH", Path.home() / ".modal.toml")).is_file()
def make_backend(settings: Settings) -> SimBackend | None:
"""The configured backend, or None (with a log line saying why) when runs are not set up."""
if settings.sim_backend == "modal":
if not modal_credentials_present():
log.warning("simulation runs disabled: set MODAL_TOKEN_ID/MODAL_TOKEN_SECRET or run `modal token new`")
return None
from .modal_client import ModalClient
return ModalClient(settings.modal_app)
if settings.sim_backend == "runpod":
if not (settings.runpod_api_key and settings.runpod_endpoint_id):
log.warning("simulation runs disabled: RUNPOD_API_KEY and RUNPOD_ENDPOINT_ID are not set")
return None
from .runpod_client import RunPodClient
return RunPodClient(settings.runpod_api_key, settings.runpod_endpoint_id)
raise ValueError(f"SIM_BACKEND must be one of {', '.join(BACKENDS)}, got {settings.sim_backend!r}")
|