ariadne: async (http-get-async) state_exec intrinsic (§13.8) - #473
Merged
Merged
Conversation
Add register_net_intrinsics(cvc::app&) (inc/cvc/ariadne/net_intrinsics.h),
binding a program-lane verb (http-get-async URL [HEADERS]) that fetches over the
cvc::net facade OFF the scheduler thread and hands the result back to a DSL
program via the async runtime -- so a program can await an HTTP response without
blocking the evaluator/host thread.
Mechanism (the nav_compute pattern): the verb runs the BLOCKING cvc::net::send on
app.computePool() via compute_async, returns immediately with a UNIQUE '#'-suffixed
reply channel, and the worker posts the marshalled response to that channel through
the one thread-safe seam, exec_scheduler().post_message. A program awaits with the
existing (msg-recv <chan>), which parks the process (not the OS thread) and, when
drain_ingress delivers, resumes with the value threaded into the enclosing
expression. The reply is a dict { ok status body(bytes) url headers(list) error };
the body is bytes (the state_exec bytes bridge), so it round-trips byte-exact. The
worker ALWAYS posts a dict (an error dict on a transport/arg failure), so a parked
recv never hangs.
(get-attr (msg-recv (http-get-async "https://host/x")) "status") ; => e.g. 200
Two-step (verb + msg-recv), not a transparent (http-get url) returning the body: a
host verb is a native_fn(span<value_t>) with no intrinsics_context at call time, so
it cannot read the calling pid or self-park -- only a core intrinsic like msg-recv
can. Transparent single-verb await needs a new evaluator hook (a follow-up). It is
registered host-level via register_action_intrinsics (it needs cvc::net + the app),
never a core state_exec builtin -- core must not depend on net/app. Guarded on
CVC_STATE_EXEC and cvc::net::have_http_backend().
Tests (ariadne_runtime_test, AriadneNetIntrinsics, offline via the set_http_client
fake): full-dict await (status/ok/error + the bytes body round-tripping through
state-data-set), error-path resume (a transport failure still resumes with an error
dict), and a BlockingHttpClient proof that drain() returns while the fetch is still
in flight (the scheduler thread is not blocked). 0/20 flaky; the full
ariadne_runtime_test (102) stays green.
Deferred (roadmap §13.8): a transparent (http-get url) verb, chunked/streaming
bodies, and the dedicated libcurl-multi I/O thread (today each in-flight fetch
blocks one compute-pool worker). Native only until the wasm worker/-sASYNCIFY fetch
path is confirmed.
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.
Adds
register_net_intrinsics(cvc::app&)binding a program-lane verb(http-get-async URL [HEADERS])that fetches over thecvc::netfacade (#468) off the scheduler thread and hands the result to a DSL program through the async runtime — so a program can await an HTTP response without blocking the evaluator/host thread.Mechanism (the nav_compute pattern)
The verb runs the blocking
cvc::net::sendonapp.computePool()viacompute_async, returns immediately with a unique#-suffixed reply channel, and the worker posts the marshalled response to that channel through the one thread-safe seam,exec_scheduler().post_message. A program awaits with the existing(msg-recv <chan>), which parks the process (not the OS thread) and, whendrain_ingressdelivers, resumes with the value threaded into the enclosing expression. The reply is a dict{ ok status body(bytes) url headers(list) error }; the body isbytes(the #469 bridge), so it round-trips byte-exact. The worker always posts a dict (an error dict on failure), so a parked recv never hangs.Why two-step, not transparent
(http-get url)A host verb is a
native_fn(span<value_t>)with nointrinsics_contextat call time, so it cannot read the calling pid or self-park — only a core intrinsic likemsg-recvcan. So the verb submits + returns the channel andmsg-recvdoes the parking. A transparent single-verb(http-get url)returning the body needs a new evaluator park-token hook (a follow-up). Registered host-level viaregister_action_intrinsics(it needscvc::net+ the app) — never a core state_exec builtin, since core must not depend on net/app. Guarded onCVC_STATE_EXEC+cvc::net::have_http_backend().Tests
ariadne_runtime_test→AriadneNetIntrinsics, all offline via PR1'sset_http_clientfake:state-data-set(exercises the state_exec: data-channelbytesas a raw std::string (coherent with ?data + the HTTP cache) #469 bridge end-to-end);BlockingHttpClientshowsdrain()returns while the fetch is still in flight (the scheduler thread isn't blocked).0/20 flaky; the full
ariadne_runtime_test(102) stays green. No platform-specific code, but the background-worker model is native-only until the wasm worker/-sASYNCIFYfetch path is confirmed.Deferred (roadmap §13.8)
A transparent
(http-get url)verb (new evaluator hook), chunked/streaming bodies, and the dedicated libcurl-multiI/O thread (today each in-flight fetch blocks one compute-pool worker). Independent of the §13.9 cache PRs (#468/#469/#472, all merged) — this is the async transport slice.