Skip to content
NeurundocsSign in

Search documentation

Jump to a page

Servers

The same build, kept up instead of invoked once. A server is an execution in serve mode, and callers reach its endpoints through the control plane.

v1stable

The shape

An app is executed, not hosted: a deployment produces a build, an execution invokes it once, and the process goes away. A server inverts the second half. The same execution, asked for with mode: serve, starts the same build and leaves it running: it binds a port, keeps the schedules it declared, and answers the paths it declared until you stop it.

There is no separate resource. A server is an execution — the same record, the same pinned build, the same logs, the same meter — which is why nothing here has its own list, its own identifiers or its own bill.

mode: run
One invocation, one result, then the process exits.
mode: serve
The process stays up and answers requests, until it is stopped.

Starting one

POST /v1/executions with {"app_id": "app_…", "mode": "serve"}. No input: a server is handed nothing, because each request it answers carries its own body. Add an optional environment_id to start it under a variable group, which is read as the process starts — so rotating a value means restarting the server, not rebuilding it.

An app has one server. Starting a second while one is queued or running is refused with app_already_serving, and an app that has never deployed is refused with build_not_ready — there is nothing to hold up.

Nothing records in advance whether a build can be served. The program is the only thing that knows what it declared, so asking it to serve is how anybody finds out — a build that declares no endpoint and no schedule fails the execution, and says so in the logs.

Calling it

/v1/apps/{app_id}/endpoint/{path}, any method. An app has one server, so the address is the app's rather than the execution's behind it — stop it, start it again on a new build, and it answers where it did before. Asking for a second server while one is up is refused.

The path is the app's own: everything the route adds is stripped before the request arrives, so a handler mounted at /webhook sees /webhookhowever it was reached. The status, the headers and the body are the app's.

The endpoint is published only once the process accepts on its port. Until then the execution is running with nowhere to route, and a call is refused rather than answered by a port nobody is holding.

The process listens on loopback and nothing outside the host learns the port — the control plane is the only way in, which is what makes your credential and its scopes the door. Your credential is stripped before the request reaches the app: it authenticated with the control plane, not with your handler.

Stopping it

POST /v1/executions/{execution_id}/stop. The record comes back still running: the ask is recorded, and the worker holding the process is what ends it. It then goes terminal like any other execution, and the record stays.

When a server is the right answer

When startup cost dwarfs the work: a crawler that holds a warm connection pool, a handler that loads a large model or ruleset once, anything fronting a latency budget an execution queue cannot meet. If your handler starts in milliseconds and runs on a schedule, run it — one execution per invocation is cheaper and leaves a better record.

content/collections/neurun/servers.mdx

Page feedback is not collected yet. Until it is, these are disabled rather than pretending to work — mail docs@neurun.dev.