feat(live-runner): self-funding metered single-shot calls - #50
Draft
rickstaa wants to merge 5 commits into
Draft
Conversation
- hoist _post_empty into http.py as post_empty (TCPConnector(ssl=False), typed status errors via the shared error mapper) so payment callers can branch on 404/409/403/482 - route LivePaymentSession.send_payment through it; the new payment_url kwarg targets a specific payment endpoint such as the session-scoped one - parse payment_interval_ms from payment challenges and surface it as server_payment_interval on call results and streams - carry the challenge session_id and the fixed-price payment_session drop through call_runner(stream=True) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The orchestrator debits the prepaid balance on -livePaymentInterval while a metered (hour/720p) single-shot request is in flight and cancels it on the first under-funded tick; the signer's preroll only covers ~10s. Spawn a payment loop inside call_runner for the lifetime of the awaited request: first payment after one interval, cadence at 60% of the challenge's payment_interval_ms with a 3s fallback, stop on 404 (released) / 409 (fixed-price) / 403 (mismatch), skip on 482, retry transient errors. No opt-out flag: offchain mode is the no-payments path and fixed pricing never starts the loop. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A streamed single-shot response outlives the call_runner call, so the LiveRunnerCallStream owns its funding: the loop starts with the stream, aclose() cancels it before tearing down the transport, and a 404 from the payment endpoint sets a read-only released flag. No public start/stop controls - a single-shot stream is its request, so stopping funding without closing is not a meaningful state. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ed endpoint
Derive .../apps/{runner_id}/session/{session_id}/payment from the
single-shot runner URL and the challenge manifest_id so the loop gets
liveness semantics (404 once the session is released, 409 for fixed
pricing) instead of blind-crediting the generic /payment endpoint,
which stays as the fallback when the URL shape does not match.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Streams the story via call_runner(stream=True); with --signer-url the call pays its 402 challenge and keeps funding itself while the stream runs, demonstrating that metered single-shot calls need no payment code on the caller side. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
rickstaa
force-pushed
the
rs/single-shot-ongoing-payments
branch
from
July 29, 2026 11:59
ce44571 to
b0f46d4
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Metered (
hour/720p) single-shot calls currently pay only the initial 402 challenge. On go-livepeer master (since livepeer/go-livepeer#4000),ProxyLiveRunnerSingleShotreserves a paid session per request and debits it every-livePaymentInterval(5s default) — balance is checked before each debit, and the first under-funded tick releases the session and cancels the in-flight request. The signer'slivetype prerolls only ~10s, so any metered call longer than that dies unless the caller hand-writes a payment loop.This makes
call_runnerown that loop, the single-shot sibling of #31: whatever holds the session open funds it, and callers never hand-manage a background task.What this adds
live/lv2v), a payment task runs for exactly the lifetime of the awaited request and is cancelled the moment the response lands. Zero new public API — noauto_payflag: an opt-out is "broken mode" (the caller is blocked awaiting the response and can't fund manually), offchain (nosigner_url) is the natural no-payments path, and the loop can't overspend (the signer bills only elapsed seconds).stream=True): the stream outlives the call, soLiveRunnerCallStreamowns the task — auto-started, cancelled byaclose()before transport teardown, plus a read-onlyreleasedflag set when the orchestrator reports the session gone. No publicstop_payments(): a single-shot stream is its request, so "keep stream, stop funding" isn't a real state.payment_interval_mswhen advertised (go-livepeerrs/singleshot-payment-interval), 3s fallback on master.releasedon streams); 409 → fixed-price, stop; 403 → mismatch, stop + log; 482 → skip the cycle; transient errors retry next tick. Loop failures never mask the request result — the orchestrator cancels the call itself if funding actually stops.…/apps/{runner_id}/session/{manifest_id}/payment(derived from the runner URL + challengemanifest_id) for real liveness semantics, falling back to the generic/paymentcredit endpoint when the URL shape doesn't match.post_emptyhoisted intohttp.pywith typed status errors,send_payment(payment_url=),payment_interval_ms→server_payment_intervalon results/streams, challengesession_idcarried onto streams.Commits
323c964payment plumbing (post_empty, payment_url kwarg, interval parse)3936c77fund metered single-shot calls while they rune1c6f8fstream owns the payment loopf7ddca0session-scoped payment endpoint with generic fallbackb0f46d4examples/text/client.py: self-funding SSE clientTesting
Relation to #31
Lands first and defines the loop policy; #31 (persistent sessions) can rebase onto it and reuse the same helper.
reserve_session(auto_pay=True)andstop_payments()stay in #31 — reserved sessions outlive their calls, so external funding control is a real use case there.🤖 Generated with Claude Code