From 756654c8dd8271afda8b405816ceb2cdba1b93d2 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Mon, 29 Jun 2026 21:29:51 +0200 Subject: [PATCH] feat(live-runner): env-var fallback for register_runner provisioning fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provisioning is an operator/deployment concern, not app logic. Today the app must read and forward connection, auth, pricing and capacity into register_runner() — pricing especially "feels strange" since the app just forwards an operator-set value. Let these be supplied via the environment when omitted, so an unchanged image can be provisioned at deploy time (env / compose / k8s) without forwarding them in code. An explicit argument always wins (env is the fallback, not an override): orchestrator_url -> LIVEPEER_ORCHESTRATOR_URL secret -> LIVEPEER_ORCH_SECRET runner_url -> LIVEPEER_RUNNER_URL price_per_unit -> LIVEPEER_PRICE_PER_UNIT (default 0) pixels_per_unit -> LIVEPEER_PIXELS_PER_UNIT (default 1) price_unit -> LIVEPEER_PRICE_UNIT (default "USD") capacity -> LIVEPEER_CAPACITY (default 1) App identity/behavior (app, mode, callbacks) intentionally stays in code. This is SDK ergonomics only — it does not change go-livepeer's trust model. Dynamic registration still reports the price to the orchestrator either way; env vs arg only changes where the operator configures it. Static remains the path for orchestrator-owned pricing. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01Ue3DyejYHXX5HYmjxtJZbg --- src/livepeer_gateway/live_runner.py | 34 +++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/livepeer_gateway/live_runner.py b/src/livepeer_gateway/live_runner.py index 5a38e2e..2243caf 100644 --- a/src/livepeer_gateway/live_runner.py +++ b/src/livepeer_gateway/live_runner.py @@ -445,20 +445,20 @@ def _release_session_id(self, session_id: str) -> None: async def register_runner( - orchestrator_url: str, + orchestrator_url: Optional[str] = None, *, - secret: str, - runner_url: str, + secret: Optional[str] = None, + runner_url: Optional[str] = None, app: str, - price_per_unit: int = 0, - pixels_per_unit: int = 1, - price_unit: str = "USD", + price_per_unit: Optional[int] = None, + pixels_per_unit: Optional[int] = None, + price_unit: Optional[str] = None, runner_id: str = "", mode: str = "persistent", label: str = "", version: str = "", status: str = "ready", - capacity: int = 1, + capacity: Optional[int] = None, gpu: Optional[LiveRunnerGPU] = None, auto_detect_gpu: bool = True, timeout: float = 5.0, @@ -467,6 +467,26 @@ async def register_runner( on_session_reserve: Optional[LiveRunnerSessionCallback] = None, on_session_release: Optional[LiveRunnerSessionCallback] = None, ) -> LiveRunnerRegistration: + # Provisioning (connection, auth, pricing, capacity) falls back to LIVEPEER_* + # env vars when omitted, so an operator can configure it at deploy time instead + # of the app forwarding it in code; an explicit argument always wins. + orchestrator_url = orchestrator_url or os.environ.get("LIVEPEER_ORCHESTRATOR_URL") + secret = secret or os.environ.get("LIVEPEER_ORCH_SECRET") + runner_url = runner_url or os.environ.get("LIVEPEER_RUNNER_URL") + if not (orchestrator_url and secret and runner_url): + raise LivepeerGatewayError( + "orchestrator_url, secret and runner_url are required: pass them or set " + "LIVEPEER_ORCHESTRATOR_URL / LIVEPEER_ORCH_SECRET / LIVEPEER_RUNNER_URL" + ) + if price_per_unit is None: + price_per_unit = int(os.environ.get("LIVEPEER_PRICE_PER_UNIT", "0")) + if pixels_per_unit is None: + pixels_per_unit = int(os.environ.get("LIVEPEER_PIXELS_PER_UNIT", "1")) + if price_unit is None: + price_unit = os.environ.get("LIVEPEER_PRICE_UNIT", "USD") + if capacity is None: + capacity = int(os.environ.get("LIVEPEER_CAPACITY", "1")) + if gpu is None and auto_detect_gpu: gpu = detect_process_gpu()