release

package
v1.801.490 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 6, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package release is the console's bytes: the ACTIVE release of a published site, held in memory and kept current.

The console used to be //go:embed'd into this binary, which welded the frontend's lifecycle to the backend's — a CSS fix cost a ~22-minute cloud build and a `strategy: Recreate` rollout that took api.hanzo.ai down for 2m15s. The console is now published like any other site (apps/projects → apps/sites): a publish is under a second, a rollback is faster, and neither builds or restarts anything.

It is the SAME release, read from the SAME store, resolved through the SAME registry the site edge uses (sites.CurrentResolver) — not a second copy of any of it. What differs is only where the bytes go: the edge STREAMS them for a site host, and this loads them once and hands webui an fs.FS, because console.hanzo.ai is deliberately NOT a site host (it must keep answering /v1 on the same origin, or the console's first-party session cookie stops working).

A leaf, like webui itself: apps/sites + apps/s3admin + stdlib, never package cloud — both composition roots import it.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func FS

func FS(s *Source) fs.FS

FS presents a Source as the fs.FS webui.Mount takes, INCLUDING the nil case.

A nil *Source assigned straight to an fs.FS is a non-nil interface holding a nil pointer — Go's oldest trap — and here it would turn "this process mounted no console" into a nil dereference on the first request instead of the 503 webui is written to answer. One conversion, so neither composition root can spell it wrong.

Types

type Config

type Config struct {
	// Org owns the console site. Resolution is PINNED to it — never
	// unique-across-orgs — so a customer project of the same name can never be
	// served as our console.
	Org string
	// Slug is the console site's project slug.
	Slug string
	// Poll is how long a published release waits before it is live everywhere.
	Poll time.Duration
}

Config names the site whose active release IS the console, and how often to look for a new one.

func ConfigFromEnv

func ConfigFromEnv() Config

The ONE resolution of the console-source configuration, for the same reason apps/sites owns its own (env.go there): TWO processes mount the console — the light router that owns the public port (cmd/cloud) and cloud.Listen in every per-app child — and a key spelled at each call site is a key the two can disagree about. It happened already with CLOUD_SITES_FIRSTPARTY_* against CLOUD_SITES_FIRST_PARTY_*, where which policy applied depended on which process a request reached.

CLOUD_CONSOLE_SITE   the console site's slug          (default hanzo-console)
CLOUD_CONSOLE_ORG    the org that owns it             (default: the sites
                     first-party org, CLOUD_SITES_FIRSTPARTY_ORG, itself
                     defaulting to hanzo)
CLOUD_CONSOLE_POLL   how often to re-read the active-release pointer
                     (default 30s; anything Go's time.ParseDuration accepts)

The org DEFAULT is not a second literal "hanzo": the console is a first-party site, and which org holds our first-party sites is already stated once, in apps/sites. A white-label deployment that moves it moves the console with it.

type Source

type Source struct {
	// contains filtered or unexported fields
}

Source is a live fs.FS over one site's active release.

The pointer to the loaded bundle is swapped ATOMICALLY, never mutated: a request that started against the old release finishes against it, and the next one gets the new. There is no window in which a shell from one release is served beside chunks from another.

func Load

func Load(ctx context.Context, cfg Config, log luxlog.Logger) (*Source, error)

Load reads the configured site's active release and returns it as an fs.FS.

It FAILS rather than degrading. A console that came up empty, or on a placeholder shell, would be a front door serving a page that looks like the product and is not — and it would do so silently, which is how a broken deploy becomes a mystery instead of an alert. Every failure below names what could not be reached, so the log line is the diagnosis.

The resolver must already be installed: the site edge is mounted before the console in both composition roots (cmd/cloud's TestSitesEdgeIsMountedInTheRouter pins that order for the front door), so "no resolver" means a caller mounted them backwards.

func (*Source) Open

func (s *Source) Open(name string) (fs.File, error)

Open implements fs.FS against the currently mounted release.

func (*Source) Release

func (s *Source) Release() string

Release is the S3 prefix of the mounted release — the release id is its last segment. Reported at boot and on every swap so "which console is live" is a question the logs answer.

func (*Source) Watch

func (s *Source) Watch(ctx context.Context)

Watch keeps the console current with what was published, and is the whole reason this indirection exists: a `hanzo sites publish` reaches users through THIS loop, in one poll interval, instead of through a cloud build and a rollout.

The steady state costs one resolver call per interval and nothing else — the bytes are re-read only when the active-release pointer actually moves. A failed poll is logged and the mounted release keeps serving: the bundle in memory is already complete, so there is nothing to fall back to and nothing to gain by tearing it down.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL