Deus - Hosting Backends and Budget Controls
Appwrite-backed hosted execution: artifact packaging, function provisioning, variable injection, deployment lifecycle, and kill-switch/warm-capacity budget gates.
Overview
The hosting layer provisions, updates, and removes Appwrite-backed function deployments. A budget gate decides whether a new allocation can proceed based on kill-switch state and always-warm capacity limits.
Hosting Contract
Source: deus/internal/hosting/backend.go
DeployInput
| Property | Type | Description |
|---|---|---|
ServiceID | string | Service identifier |
ArtifactKey | string | Object storage key for the uploaded artifact |
Runtime | string | Runtime selector (currently node20) |
AlwaysWarm | bool | Requests dedicated warm resource profile |
Region | string | Region selector |
FunctionName | string | Optional explicit function name |
Env | map[string]string | Per-service environment variables |
DeployResult
| Property | Type | Description |
|---|---|---|
FunctionID | string | Appwrite function identifier |
DeploymentID | string | Appwrite deployment identifier |
ExecEndpoint | string | Synchronous execution URL |
Backend interface
type Backend interface {
Deploy(ctx context.Context, in DeployInput) (DeployResult, error)
Delete(ctx context.Context, functionID string) error
}
Appwrite Backend
Source: deus/internal/hosting/appwrite.go
The Appwrite backend validates configuration, reads the artifact from object storage, creates an Appwrite function, pushes variables, uploads the code bundle, and returns the execution endpoint.
Deploy flow
- Validate
Endpoint,ProjectID,APIKeyare set - Load artifact bytes from
BlobReader.Get - Package as
code.tar.gz(gzip passthrough if already gzipped) POST /functionswith{name, runtime: "node-20.0", execute: ["any"], enabled: true, entrypoint: "src/main.js", commands: "npm install"}- If
AlwaysWarm, addspecification: "s-1vcpu-512mb" POST /variablesone at a time in deterministic key orderPOST /deploymentsas multipart form data withactivate: true- Return
{FunctionID, DeploymentID, ExecEndpoint}
Key parameters
| Parameter | Value |
|---|---|
| HTTP timeout | 120 seconds |
| Default function timeout | 30000ms (clamped to at least 1s) |
| Max response bytes | 262144 (pushed as DEUS_MAX_RESPONSE_BYTES) |
| Warm specification | s-1vcpu-512mb |
| Artifact name | code.tar.gz |
Hosted service HTTP routes
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /v1/services/{id}/artifacts | Developer (owner) | Upload artifact (multipart, 12 MB max) |
| POST | /v1/services/{id}/deploy | Developer (owner) | Deploy to Appwrite |
| POST | /v1/services/{id}/redeploy | Developer (owner) | Redeploy service |
| GET | /v1/services/{id}/deployments | Developer (owner) | List deployments |
| GET | /v1/services/{id}/deployments/{did} | Developer (owner) | Get deployment detail |
Orchestrator
The Orchestrator ties the Backend, Budget, and Store together. The Deploy method:
- Checks budget via
Budget.AllowNewDeployment(alwaysWarm) - Calls
Backend.Deploy - Records the deployment in the store
Budget Controls
Source: deus/internal/hosting/budget.go
Budget gate flow
AllowNewDeployment(alwaysWarm)
├── alwaysWarm=true → AllowAlwaysWarm
│ ├── KillSwitch active? → reject
│ ├── CountAlwaysWarmDeployments >= MaxAlwaysWarm? → reject
│ └── allow
└── alwaysWarm=false
├── KillSwitch active? → reject
└── allow
The kill-switch short-circuits before any store lookup. BudgetWei parses limits.BudgetPAXWei as base-10 text.
Error cases
| Condition | Error |
|---|---|
| Kill switch active (all deploys) | hosting_budget_exceeded |
| Kill switch active (always-warm) | hosting_budget_exceeded |
| Always-warm capacity exhausted | hosting_budget_exceeded |
Handler error mapping
| Error pattern | HTTP status | Code |
|---|---|---|
not found | 404 | not_found |
budget, kill-switch | 409 | hosting_budget_exceeded |
not hosted | 400 | invalid_request |
| Other | 500 | internal_error |
