Skip to content

Custom HTTP handlers - #3880

Merged
vigoo merged 81 commits into
mainfrom
gol-554-http-handler-corpus
Sep 24, 2026
Merged

vigoo merged 81 commits into
mainfrom
gol-554-http-handler-corpus

Conversation

@vigoo

@vigoo vigoo commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

Purpose

Implements the custom HTTP handler platform (GOL-554–563) and the MoonBit, Rust, TypeScript, and Scala SDK APIs (GOL-564, GOL-565, GOL-567, GOL-568).

Task Implemented scope
GOL-554 Shared language-neutral conformance corpus, JSON Schema, and TypeScript/Bun integrity checker.
GOL-555 Router/file/provider metadata, validation, codecs, extraction, persistence, and low-level SDK support.
GOL-556 Mounted dispatch descriptors, immutable read-only indexes, strict path decoding, routing precedence, security barriers, and requested-method CORS preflight.
GOL-557 Exact-absolute-path, metadata-first bounded executor filesystem reads, shared with existing CLI/REST inspection.
GOL-558 Request-private ephemeral invocation sessions, bounded input/output, same-execution reattachment, completion tracking, and disconnect cleanup.
GOL-559 Direct immutable-file serving from shared blob storage, deployment-index caching, ranges, validators, and GET/HEAD without executor calls.
GOL-560 Offline OpenAPI 3.1 validation, mount-relative rebasing, deterministic merging with typed operations, and reference/security/conflict checks.
GOL-561 Live durable-agent filesystem serving over existing executor reads, including initialization/restoration, ranges, bounded streaming, and cancellation.
GOL-562 Canonical streaming HTTP request/response envelopes and mounted handler delivery through invocation sessions.
GOL-563 Lazy deployment-pinned OpenAPI provider invocation, bounded single-flight caching, invalidation fencing, and JSON/YAML serving.
GOL-564 MoonBit router declarations, parser/emitter/runtime support, streaming HTTP helpers, live-file exposure, OpenAPI providers, and examples.
GOL-565 Dedicated Rust router macros/APIs, canonical streaming types, file mappings, OpenAPI providers, compile-time validation, and deployed fixtures.
GOL-567 TypeScript defineHttpRouter, Web and raw streaming adapters, host-free contract helpers, exposeFiles, OpenAPI serialization, and CLI integration coverage.
GOL-568 Scala router annotations/macros/codegen, lightweight HTTP/AgentStream types, live-file exposure, OpenAPI providers, and deployed examples.

The normative HTTP_HANDLERS.md specification is attached to GOL-554, not tracked in Git. The shared corpus lives in golem-service-base/tests/fixtures/http-handlers/.

Routing, authorization, and file serving

  • Complete concrete-method endpoints precede eligible mounted fallbacks; reserved routes retain precedence. Selection/security failures do not fall through to parent mounts. Existing atomic deployment selection is reused.
  • Paths decode once per segment. HTTP mappings resolve to exact absolute filesystem paths before executor calls; the executor performs no URI decoding or mount/root/suffix resolution. Existing CLI/REST inspection uses the same bounded read protocol.
  • Mount authentication, session policy, and CORS remain host-owned and precede file lookup or handler execution. Trusted ingress is explicit and defaults to no trust; routing, redirects, and guest envelopes share validated public-origin information.
  • Immutable indexes reuse upload-computed BLAKE3 hashes and sizes: deployment does not redownload or rehash contents. Worker-service reads the selected deployment's read-only files directly from shared blob storage, caching indexes rather than file contents.
  • Immutable GET/HEAD supports MIME inference, nosniff, strong BLAKE3 ETags, conditional requests, and single byte ranges. HEAD ignores ranges; malformed/multiple ranges return the full representation. Indexed missing blobs and size mismatches are server errors, never handler fallback; late stream errors abort delivery. Filesystem, S3, memory, and SQLite reads use bounded chunks.
  • Live-file HTTP access initializes absent durable agents and restores non-resident ones without invoking an exported guest method. Reads use the concrete constructor identity and current normal lifecycle revision, while the selected target stays fixed. Ordered mappings advance only on absence, not directories, symlinks, permission errors, or initialization/read failures.
  • Live reads support GET/HEAD and single ranges without immutable validators. Metadata and bytes come from one admitted read; bounded read-ahead and the namespace/serialization guard prevent mixing file generations. HTTP deadlines belong to worker-service, not the executor. EOF, failure, cancellation, and disconnect release the read.

Streaming handlers

  • A handler receives the canonical seven-field request and returns a three-field response with stream<list<u8>> bodies. Raw adapters preserve valid repeated headers and opaque values, including repeated Set-Cookie; cross-name ordering is not promised.
  • Each HTTP exchange owns one private ephemeral invocation. Input is not polled before acceptance supplies stream mappings. Transport recovery reattaches the same execution and reconciles ACKs/cursors; it does not create a replacement invocation after ambiguous acceptance or process loss.
  • An early result is not invocation completion. Unknown-length responses withhold successful EOF until session success; positive Content-Length responses retain their final byte. HEAD/204/205/304/zero-length responses dispose bodies unpolled and await completion. Post-head failure aborts transport instead of fabricating successful EOF.
  • Executor execution stays Running through post-result stream production and settlement, including replay. Interruption retains its typed outcome rather than becoming a runtime error/retry. Disconnect cleanup cancels streams and uses existing pending cancellation/interruption; interruption is pause, not rollback. Serving-process death cannot guarantee remote cleanup without a lease, and no lease is added.
  • Official Hyper, hyper-util, and Poem remain the HTTP stack; no vendored parser or second framing parser. Equal duplicate Content-Length may normalize; HTTP/1 TE+CL follows chunked framing and closes the connection. Differing/comma Content-Length is rejected. Strict rejection of distinctions already normalized by the transport is unsupported by design. Guest response heads are validated before encoding.

OpenAPI providers

  • openapi_provider_method names an ordinary parameterless, non-streaming method. Providers run only for OpenAPI requests, under a fixed system context and at the selected deployment's component revision; ordinary routing, handlers, and static/live files do not execute provider code.
  • OpenAPI 3.1 documents are validated offline. Paths and supported local references are rebased under mounts and merged deterministically with typed operations. Equivalent-path/method collisions, incompatible components/path metadata, duplicate operation IDs, and unsupported references are rejected. External references are never fetched.
  • Golem owns the public document's top-level identity/origin; effective operation security is preserved. Provider timeout, size, validation, or merge failures affect only OpenAPI responses and produce safe diagnostics, not provider payloads or secrets.
  • Bounded single-flight generations cache JSON/YAML from the same merged model. Deployment, domain, security, and secret changes invalidate the cache; generation fencing prevents invalidated work from publishing stale results.

SDKs and remaining scope

MoonBit, Rust, TypeScript, and Scala now expose named ephemeral routers with independently optional handlers, immutable mappings, and OpenAPI providers, plus ordered live-file mappings on eligible ordinary durable agents. They reuse normal configuration, registration, and invocation machinery. Tests cover declaration validation, metadata, generated clients, streaming ownership, and deployed examples. TypeScript provides both normalized Web APIs and a raw escape hatch; Scala does not require an unrelated HTTP/OpenAPI framework.

GOL-566 (Effect HttpRouter/OpenAPI integration) remains follow-up work and is not claimed as implemented here. Low-level Effect metadata support and shared TypeScript contract helpers are present. External deployment/access changes and backward-compatibility layers are not included.

Verification

  • The last fully green combined platform run before the four SDK additions was CI 35517318356: 54 passed, 7 skipped, with Docs passing. These links describe that exact earlier head, not the newest merge.
  • Platform verification includes executor unit/lifecycle/replay tests; SQLite/PostgreSQL HTTP, file, and OpenAPI integrations; real HTTP/1.1 and HTTP/2 streaming/disconnect tests; storage range/drop tests; provider/cache race tests; and shared corpus consumers.
  • The live-file backpressure fixture remains 32 MiB but uses deterministic poorly compressible bytes: a protobuf+gzip regression proves it exceeds the inner receive window. Both PostgreSQL and SQLite held-response mutation tests passed without weakening blocking assertions or increasing timeouts.
  • SDK additions include Rust macro/runtime tests, MoonBit parser/emitter/runtime tests, Scala macro/codegen/stream tests, TypeScript contract/type/runtime tests, and CLI build/deployment/client-generation tests. Corpus integrity checks alone are not runtime conformance certification.
  • Latest-main merge follows main's removal of tracked Effect WASMs; all three remain generated, ignored build artifacts. Local npm run check:contracts, npm run check:artifacts, and merge diff checks passed.
  • Full CI for the newly merged head is pending; this section will be updated with its result.

This PR remains unmerged; merging the PR or deploying is not part of this update.

@netlify

netlify Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for golemcloud canceled.

Name Link
🔨 Latest commit 03f5a88
🔍 Latest deploy log https://app.netlify.com/projects/golemcloud/deploys/6ab4e45472c9260008bb5129

vigoo and others added 3 commits September 14, 2026 18:11
Introduce explicit agent kinds, structural file mappings, and the Any HTTP matcher across shared schemas, WIT, protobuf, and SDK metadata emitters. Validate router and filesystem metadata, reject unsupported HTTP deployment compilation, and cover codec, persistence, and extraction boundaries.

Amp-Thread-ID: https://ampcode.com/threads/T-01a09fef-5b1e-75be-89e8-6a7c32655f65
Co-authored-by: Amp <amp@ampcode.com>
@github-actions

github-actions Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

📖 Docs preview: https://docs-ebx2a3y0u-golem-cloud.vercel.app

Built from commit 03f5a88c4bbce924223dc6f0c998cd797faa780c by docs.yaml.

vigoo and others added 20 commits September 15, 2026 09:26
Load shared typed-route selection cases and assert fixture-derived captures. Pin root, HEAD, and concrete ANY method distinctions.

Test-first commit: typed_literal_dead_end_backtracks_to_parameter_route intentionally fails against the baseline matcher (None instead of complete). The other nine router tests pass. This is a local intermediate commit; the subsequent matcher implementation must resolve the failure before integration.

Oracle reviewed; masking failure isolated. Bounded bug-finder run found no bugs in the test changes.

Amp-Thread-ID: https://ampcode.com/threads/T-01a0a416-30eb-77d5-a492-84dce752c251
Co-authored-by: Amp <amp@ampcode.com>
Share strict segment decoding with mapping compilation while retaining declaration-specific restrictions. Preserve original public path, opaque query and trailing-slash intent separately from decoded segments.

P01 deliberately rejects malformed escapes, raw non-pchar text, traversal and encoded separators before domain lookup. Root now uses zero segments. Trailing-slash matching is introduced with the compiled match representation separately.

Verified common path/mapping/schema tests (10 tests, including 18 path and 11 mapping corpus cases), worker custom API tests (121), and OIDC tests (28). Oracle reviewed; bounded bug-finder reported no bugs.

Amp-Thread-ID: https://ampcode.com/threads/T-01a0a416-30eb-77d5-a492-84dce752c251
Co-authored-by: Amp <amp@ampcode.com>
@vigoo vigoo changed the title Add shared custom HTTP handler conformance corpus Custom HTTP handlers Sep 15, 2026
/// the returned file has finished streaming. This is observation, not a durable guest invocation.
/// Metadata is captured from the opened descriptor; path metadata only rejects unsafe opens.
/// Directories never select an index file. No returned error contains a host path.
pub(crate) async fn open_file_for_inspection<Adapter: SandboxFilesystemAdapter>(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do we need the new "inspection" operation for, regarding the custom http routing / file serving spec?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file operation serves the existing agent filesystem API as well as HTTP live-file delivery; it is not a separate HTTP-only executor API. The old implementation buffered the complete file. Streaming needs safe opening, metadata/byte selection and bounded production while retaining filesystem ownership against concurrent mutation.

Following our discussion, removed the separate inspection scheduling/lifecycle policy. Reads and listings now enter common worker scheduling and use normal activation, initialization, reconstruction, updates and failure handling. Native requests/bytes are not journaled. Existing filesystem ownership is held while the producer reads and released after successful production, rather than waiting for consumer-observed EOF. Static immutable files still use blob storage and need no executor. Runtime tests cover initialization, recovery, Suspend/resume, update and backpressure.

Implemented/reviewed in 71e9f29. Oracle review approved the final fixes. After the latest main merge, CI is green: https://github.com/golemcloud/golem/actions/runs/35634342722 (54 passed, 7 skipped).


/// Executor-local admission, shared by all requests, including requests for absent agents.
#[derive(Debug)]
pub struct FileReadAdmission {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a separate mechanism to limit file reads? We already have various limits coming from the user's plan, enforced by the executor.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed; removed FileReadAdmission, its registry/reservations/semaphore, configuration and admission-only errors. No replacement per-account quota was introduced. Bounded buffering remains per response, but there is no new aggregate outstanding-file-read limit. Slow-consumer backpressure may keep the agent occupied just as ordinary sequential work can; that is the accepted behaviour.

Implemented/reviewed in 71e9f29. Oracle review approved the final fixes. After the latest main merge, CI is green: https://github.com/golemcloud/golem/actions/runs/35634342722 (54 passed, 7 skipped).

store.data().set_suspended();
/// Publishes the early stream-bearing result and drives its producers to completion.
/// Live execution and replay use the same trap classification as the guest export.
pub(crate) async fn materialize_streaming_result<Ctx: WorkerCtx>(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explain what needed to be changed about streaming invocation, why, and how it affects other use cases

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old suspension point could mark an invocation suspended when the function returned, although returned streams were still running. That left the post-return part of the invocation with incorrect interrupt handling.

We keep execution running through stream materialization/settlement and suspend afterward. This is more than moving one call: interrupt delivery, typed trap/error classification, replay failure handling and session settlement must remain consistent over that extended interval. It affects streaming RPC/entity/custom-HTTP invocations; non-streaming invocations have no additional stream-production interval. Oracle reviewed the broader changes and confirmed they are related correctness fixes, which we agreed to retain with regression coverage.

Implemented/reviewed in 71e9f29. Oracle review approved the final fixes. After the latest main merge, CI is green: https://github.com/golemcloud/golem/actions/runs/35634342722 (54 passed, 7 skipped).

@@ -13,22 +13,24 @@
// limitations under the License.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not expecct other changes to the invocation loop than supporting the new file-system access commands, explain

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The revision removes inspection-specific scheduling and lifecycle machinery. Native reads/listings use the common loop and normal worker activation/reconstruction/update/failure handling; a suspended unfinished invocation must resume before boundary-only native work runs.

One ordering change remains: main keeps persisted invocations in oplog-derived status and transient commands in an in-memory deque, processing the latter first. To avoid a read overtaking an already accepted invocation, transient filesystem requests capture their position relative to persisted work. select_next_work applies that common policy, giving A -> read -> B when accepted in that order, without journaling the read. invocation_queue contains this ordering/pruning policy, not another execution loop or admission system. The separate streaming-interrupt correctness fix is explained in the adjacent invocation.rs thread. Runtime tests include ordinary Suspend and the concurrent-agent permit-wait path.

Implemented/reviewed in 71e9f29. Oracle review approved the final fixes. After the latest main merge, CI is green: https://github.com/golemcloud/golem/actions/runs/35634342722 (54 passed, 7 skipped).

Comment thread golem-worker-executor/src/worker/mod.rs Outdated
worker_event_service: Arc<dyn WorkerEventService + Send + Sync>,

queue: Arc<RwLock<VecDeque<QueuedWorkerInvocation>>>,
queue: Arc<StdMutex<VecDeque<QueuedWorkerInvocation>>>,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explain the change

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restored Tokio's async RwLock. The synchronous lock had been introduced to remove cancelled requests directly from Drop; that mechanism is now removed. Abandoned transient requests are pruned at enqueue/selection and lifecycle boundaries instead. Accepted durable invocations are never pruned just because their caller disconnected. A cancelled transient record may remain until the next pruning boundary, which is the agreed tradeoff.

Implemented/reviewed in 71e9f29. Oracle review approved the final fixes. After the latest main merge, CI is green: https://github.com/golemcloud/golem/actions/runs/35634342722 (54 passed, 7 skipped).

//
// http://license.golem.cloud/LICENSE

//! Retry-owning invocation sessions used by the custom HTTP adapter.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole module deserves better structuring and more inline (and doc comment on extracted methods etc) documentation

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done: split http_session into driver, progress and transport responsibilities and added method/module documentation for protocol state transitions, input/output accounting and recovery ownership. HTTP envelope/body adaptation remains outside the session protocol. The separate recovery correctness changes have regression tests and are described in the RawHandler thread below.

Implemented/reviewed in 71e9f29. Oracle review approved the final fixes. After the latest main merge, CI is green: https://github.com/golemcloud/golem/actions/runs/35634342722 (54 passed, 7 skipped).

@@ -0,0 +1,231 @@
// Copyright 2024-2026 Golem Cloud

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow the existing practice of file layout - if there is a cache/tests.rs then the cache module should be in cache/mod.rs not in cache.rs. Apply this rule to the whole changeset

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done: applied the directory-module convention throughout the affected modules, including cache/mod.rs alongside cache/tests.rs and the HTTP schema module. Removed the superseded flat module files.

Implemented/reviewed in 71e9f29. Oracle review approved the final fixes. After the latest main merge, CI is green: https://github.com/golemcloud/golem/actions/runs/35634342722 (54 passed, 7 skipped).

pub(super) const DOCUMENT_BYTE_LIMIT: usize = 8 * 1024 * 1024;

#[derive(Clone)]
pub(super) struct Budget {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the OpenAPI-specific Budget, provider/generation/request timeouts, cancellation checks and timeout-driven cleanup. The provider is an ordinary invocation on a fresh ephemeral http-router instance; normal invocation admission/execution owns overload handling. It does not need a separate OpenAPI lifecycle.

Retained document-size limits and a spawn_blocking boundary for synchronous document processing. spawn_blocking avoids running CPU-bound parsing/validation/merge/serialization on an async runtime worker; it is not a timeout or provider-execution mechanism. The remaining bounded_json helpers enforce data-size bounds, not time budgets.

Implemented/reviewed in 71e9f29. Oracle review approved the final fixes. After the latest main merge, CI is green: https://github.com/golemcloud/golem/actions/runs/35634342722 (54 passed, 7 skipped).

// Pending entries cannot be evicted by completed-entry LRU pressure. Admission
// remains with the generation's CPU/cleanup tasks, even after invalidation.
#[derive(Default)]
pub(super) struct CacheState {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want you to use our Cache type from golem_common for all cache implementations.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done: replaced the bespoke OpenAPI cache with golem_common::Cache, using its spawned singleflight creation path for lazy document generation. Concurrent requests for the same snapshot share generation; cancellation of an individual waiter does not abandon that shared fill. Capacity remains bounded at 256 entries. Removed custom freshness counters, stale-delivery fencing/retry loops and negative caching.

Implemented/reviewed in 71e9f29. Oracle review approved the final fixes. After the latest main merge, CI is green: https://github.com/golemcloud/golem/actions/runs/35634342722 (54 passed, 7 skipped).

const GENERATION_CONCURRENCY: usize = 8;

pub struct OpenApiDocument {
pub json: Bytes,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did we support JSON before? If not and only yaml, then let's keep it that way

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed that both JSON and YAML OpenAPI endpoints existed before this PR. Kept both; this is not an added format requirement.

Implemented/reviewed in 71e9f29. Oracle review approved the final fixes. After the latest main merge, CI is green: https://github.com/golemcloud/golem/actions/runs/35634342722 (54 passed, 7 skipped).

use std::sync::atomic::{AtomicU64, Ordering};

#[derive(Clone)]
pub(crate) struct Freshness {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's this for? I think the generation and caching of OpenAPI specs got a bit over complicated in this PR. What I think we need is simply a cached openapi document per deployment, lazily generated on first request, and instead of just generating it from the http route metadata as before, it needs to optionally call the component's custom openapi fragment genreator and merge the two. How it calls it is the interesting part and can be completely orthogonal to the cache implementation

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented the simpler model: lazily generate a document from a captured immutable route snapshot, optionally invoke providers through the ordinary ephemeral invocation path, merge their fragments, and cache the result with golem_common::Cache. Provider invocation is independent of the cache implementation.

The cache key is the immutable route-snapshot UUID, so changed route/origin/security inputs use a distinct document identity. Removed OpenAPI-specific freshness generations, stale-delivery fences, retry loops and negative caching. An already-running fill for an older captured snapshot may finish, as agreed; new snapshots use their own keys. Tests cover singleflight generation and snapshot identity/invalidation behaviour.

Implemented/reviewed in 71e9f29. Oracle review approved the final fixes. After the latest main merge, CI is green: https://github.com/golemcloud/golem/actions/runs/35634342722 (54 passed, 7 skipped).

// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://license.golem.cloud/LICENSE

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this module related to the http_session module? It's confusing to me

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Separated the responsibilities: MountedDispatch owns mounted-backend selection/dependencies; RawHandler adapts the HTTP request/response envelope and bodies; http_session owns the private streaming-session protocol, transport and recovery. Restructured the session into driver/progress/transport modules with documentation rather than introducing another universal driver.

Also fixed the recovery inconsistencies we discussed, with regression tests: an ambiguous transport failure now retains the exact pending resume attempt ID so an accepted attempt can be replayed. Resume versus Takeover follows attachment state and changes only after an authoritative rejection, rather than unconditionally requesting Takeover or creating a fresh attempt on every retry.

Implemented/reviewed in 71e9f29. Oracle review approved the final fixes. After the latest main merge, CI is green: https://github.com/golemcloud/golem/actions/runs/35634342722 (54 passed, 7 skipped).

vigoo and others added 4 commits September 21, 2026 16:56
Integrate native filesystem work into common resident scheduling and normal lifecycle handling. Remove file-read admission policy and release ownership after bounded production.\n

Use ordinary ephemeral OpenAPI invocations and the shared snapshot-keyed cache without provider-specific deadlines or freshness fencing. Restructure HTTP session transport and preserve resume attempts across ambiguous failures.

Apply the agreed module, macro and body-schema changes, add recovery regressions, and align executor configuration and guidance.

Amp-Thread-ID: https://ampcode.com/threads/T-01a09fef-5b1e-75be-89e8-6a7c32655f65
Co-authored-by: Amp <amp@ampcode.com>
Prevent the first round from returning its semaphore permit and letting the next round cancel before the persisted-body gate. Assert that each round starts with its cancellation signal withheld.

Amp-Thread-ID: https://ampcode.com/threads/T-01a09fef-5b1e-75be-89e8-6a7c32655f65
Co-authored-by: Amp <amp@ampcode.com>
Preserve both HTTP router and local semantic retry documentation in the Rust SDK README.

Amp-Thread-ID: https://ampcode.com/threads/T-01a09fef-5b1e-75be-89e8-6a7c32655f65
Co-authored-by: Amp <amp@ampcode.com>
@vigoo
vigoo marked this pull request as ready for review September 22, 2026 11:03
@vigoo
vigoo requested a review from a team September 22, 2026 11:03
Comment on lines +1723 to +1730
if !needs_initialization && let Some(invocation) = queue.pop_front() {
return SelectedWork::Resident(invocation);
}
if !status.pending_updates.is_empty() {
return SelectedWork::ApplyPendingUpdate;
}
if let Some(pending) = status.pending_invocations.first() {
return SelectedWork::Durable(pending.clone());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

select_next_work drains every resident request before checking pending updates or durable invocations. Because filesystem requests enter an unbounded resident deque and this PR intentionally removes aggregate file-read admission, continuous live-file traffic can keep the resident queue non-empty forever, so an already accepted agent method or pending update never runs. This is stronger than merely observing the current state at an invocation boundary. Could we add a bounded fairness rule, plus a test that keeps enqueueing reads while proving a pending invocation and update still make progress?

Comment on lines +281 to +288
let finalized_routes: Vec<_> = finalized_routes.into_iter().map(Arc::new).collect();
let openapi_inputs = finalized_routes.iter().find_map(|route| {
if let RichRouteBehaviour::OpenApiSpec(behavior) = &route.behavior {
Some(Arc::new(OpenApiInputs {
key: OpenApiKey::fresh(),
public_origin: behavior.scheme.origin(domain),
routes: finalized_routes.clone(),
}))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The review thread describes one lazily generated OpenAPI document per deployment, but fetch_and_build_domain_api assigns a fresh random key whenever the domain router is rebuilt. With the default ten-minute router TTL, an unchanged deployment re-runs every provider periodically and leaves the previous document in the 256-entry LRU until eviction. Is that periodic refresh intentional? If not, could the key derive from stable deployment/route identity (including the origin and security inputs) and have a test for a router-cache refill with unchanged routes? If it is intentional, please document the refresh semantics because they differ from the thread resolution.

Comment thread cli/golem-cli/src/model/app_raw/mod.rs Outdated
Comment on lines +1162 to +1165
#[serde(default, skip_serializing_if = "Option::is_none")]
pub subdomain: Option<DeploymentSubdomain>,
#[serde(default)]
pub scheme: golem_common::model::http_api_deployment::HttpApiDeploymentScheme,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scheme is needed for a deterministic host-owned OpenAPI servers origin, but defaulting an omitted value to Https here happens before the deployment environment is resolved. Stock local manifests use plain HTTP (*.localhost:9006) and omit scheme, so their generated OpenAPI advertises an unreachable https://... server; the human manifest reference does not document the field either. Could the raw value remain optional and be resolved from the built-in target (HTTP for local, HTTPS for cloud), while retaining an explicit override for custom servers? Please also cover an omitted local value and document the field.

vigoo and others added 7 commits September 23, 2026 17:03
…corpus

Co-authored-by: Amp <amp@ampcode.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a0d203-35b0-704c-b220-436bda85b67c

# Conflicts:
#	golem-common/src/base_model/diff/mod.rs
#	golem-common/tests/goldenfiles/diff_model_fingerprint_v12.txt
#	golem-registry-service/src/api/error.rs
#	golem-registry-service/src/services/deployment/deployment_context.rs
#	golem-registry-service/src/services/deployment/write.rs
#	golem-worker-service/src/gateway_server/tests.rs
…corpus

Amp-Thread-ID: https://ampcode.com/threads/T-01a0d203-35b0-704c-b220-436bda85b67c
Co-authored-by: Amp <amp@ampcode.com>

# Conflicts:
#	golem-debugging-service/src/debug_context.rs
#	golem-service-base/src/service/initial_agent_files.rs
#	golem-worker-executor/src/worker/mod.rs
@vigoo
vigoo merged commit c2b31d2 into main Sep 24, 2026
178 of 193 checks passed
@vigoo
vigoo deleted the gol-554-http-handler-corpus branch September 24, 2026 10:03
@github-actions github-actions Bot locked and limited conversation to collaborators Sep 24, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants