Documentation
¶
Overview ¶
Package api exposes Brevis's HTTP interface.
It uses plain net/http. ServeMux's method-and-path routing (Go 1.22+) covers what is needed, and the rule is to avoid a framework when the stdlib does the job. This system's hard work is in the queue, in the scheduler and in the state machine — not in the HTTP.
Index ¶
- func CachedInFlight(read func(context.Context) (int, error), ttl time.Duration, ...) func(context.Context) (int, error)
- type Actions
- type AlertsReader
- type CatalogReader
- type Checker
- type Definitions
- type EndpointCaller
- type EndpointsReader
- type EventsReader
- type FailingReader
- type Leitura
- type RunsChart
- type Server
- type UI
- func (u *UI) Registrar(mux *http.ServeMux)
- func (u *UI) RegistrarLogin(mux *http.ServeMux, gate *auth.Gate)
- func (u *UI) WithEndpointCalls(c EndpointCaller, console auth.Credential) *UI
- func (u *UI) WithEndpoints(r EndpointsReader) *UI
- func (u *UI) WithEvents(r EventsReader) *UI
- func (u *UI) WithFailing(r FailingReader) *UI
- func (u *UI) WithGallery(on bool) *UI
- func (u *UI) WithPreview(c *sqlserve.Client, console auth.Credential) *UI
- func (u *UI) WithVersion(current string, src UpdateSource) *UI
- type UpdateSource
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CachedInFlight ¶
func CachedInFlight(read func(context.Context) (int, error), ttl time.Duration, now func() time.Time) func(context.Context) (int, error)
CachedInFlight keeps read's answer for ttl, as CachedFailing does for the failing list: the badge is drawn on every page and polled by every open tab, and a count a few seconds old says the same thing.
An error is not kept: the next page asks again.
Types ¶
type Actions ¶
type Actions interface {
// Toggle pauses or resumes; actor is who pressed it, for the events feed.
Toggle(ctx context.Context, slug, actor string) (bool, error)
// Disparar runs a workflow now; with a slot, that past slot of its
// schedule.
Disparar(ctx context.Context, slug string, now time.Time, params map[string]string, slot *time.Time) (uuid.UUID, error)
// Cancel stops a run, or asks the dispatcher holding it to; actor is who
// pressed it.
Cancel(ctx context.Context, id uuid.UUID, actor string) (postgres.CancelResult, error)
}
Actions are the three effects the screen triggers. A small interface on purpose: the UI must not be able to do anything more to the system than pause a schedule, ask for a run now, and stop one.
type AlertsReader ¶
type AlertsReader interface {
ForRun(ctx context.Context, runID uuid.UUID) ([]alerts.Record, error)
}
AlertsReader lists a run's alerts. It is a CONSTRUCTOR argument and not a settable field, so that forgetting to wire it is a compile error rather than a screen that quietly stops showing alerts. Two features shipped switched off in one week because nothing outside a test ever set the field they needed.
nil is still allowed, for a process that renders no pages.
type CatalogReader ¶
type CatalogReader interface {
Catalog(ctx context.Context) ([]postgres.CatalogEntry, error)
CatalogTarget(ctx context.Context, target string) (*postgres.TargetDetail, error)
StreamConfigs(ctx context.Context) (map[postgres.StreamKey]*postgres.WriterConfig, error)
StepConfigs(ctx context.Context) (map[postgres.StepKey]*postgres.WriterConfig, error)
}
CatalogReader lists the destinations the ecosystem writes, for /data. A constructor argument for AlertsReader's reason: forgetting to wire it is a compile error, not a catalog that quietly shows nothing. nil is allowed for a process that renders no pages.
type Checker ¶
Checker is a dependency readiness consults. A small interface on purpose (rule 5): postgres.Pool already satisfies it with no adapter.
type Definitions ¶
type Definitions interface {
Definition(ctx context.Context, slug string) (wf.Workflow, error)
// Definitions is every published definition by slug, in one read: what
// a page with many workflows uses for their logos.
Definitions(ctx context.Context) (map[string]wf.Workflow, error)
}
Definitions reads a workflow's published definition. Kept apart from `Leitura` because it returns the domain, not a screen projection.
type EndpointCaller ¶
type EndpointCaller interface {
Configured(api string) bool
Call(ctx context.Context, api, path string, params url.Values) (endpointcall.Answer, error)
}
EndpointCaller runs a published endpoint for Try it.
type EndpointsReader ¶
type EndpointsReader interface {
List(ctx context.Context) ([]postgres.PublishedEndpoint, error)
Get(ctx context.Context, api, name string) (postgres.PublishedEndpoint, bool, error)
Reading(ctx context.Context, target string) ([]postgres.PublishedEndpoint, error)
}
WithPreview points the console at a SQL service, and says whether this console has a login.
A SETTER AND NOT AN ARGUMENT, because NewUI already takes eight: this one is optional in a way the others are not -- a console with no SQL service is a console that works, and every caller would otherwise pass nil.
THE CREDENTIAL ITSELF AND NOT A BOOLEAN, so that nobody can answer this question wrongly by writing `true`. The only way to get the tabs is to hand over the console's real credential and have it be one; a bool would make "we are protected" something a caller could simply assert.
An ARGUMENT and not a second setter, so forgetting it is a compile error rather than an open console with a warehouse on it. EndpointsReader is what Data → Endpoints reads: what each brevis-sql-api was published with. Never its traffic, which is on the API's /metrics.
type EventsReader ¶
type EventsReader interface {
RecentEvents(ctx context.Context, q postgres.EventQuery) ([]postgres.Event, string, error)
}
EventsReader reads the event log: what the installation did, newest first.
type FailingReader ¶
type FailingReader interface {
FailingWorkflows(ctx context.Context) ([]postgres.FailingWorkflow, error)
// FailureStreak is how many times in a row a workflow failed, for the
// open run's "why it failed".
FailureStreak(ctx context.Context, slug string) (int, error)
}
FailingReader is the workflows whose last finished run failed.
func CachedFailing ¶
func CachedFailing(r FailingReader, ttl time.Duration, now func() time.Time) FailingReader
CachedFailing keeps r's answer for ttl. The badge is drawn on every page, and the list costs ~6 ms with a thousand workflows and fifty thousand runs (measured for run-diagnosis); a count that is fifteen seconds old says the same thing to whoever reads it.
An error is not kept: the next page asks again.
type Leitura ¶
type Leitura interface {
Indicators(ctx context.Context, window time.Duration) (postgres.Indicators, error)
IndicatorsFor(ctx context.Context, window time.Duration, workflow string) (postgres.Indicators, error)
RunsPerDay(ctx context.Context, workflow string, days int) ([]postgres.Day, error)
LoadTrend(ctx context.Context, workflow string, days int) ([]postgres.LoadDay, error)
RunsPer(ctx context.Context, g postgres.Grain, n int) ([]postgres.Bucket, error)
InFlight(ctx context.Context, limite int) ([]postgres.RunSummary, error)
LatestRuns(ctx context.Context, limite int) ([]postgres.RunSummary, error)
Runs(ctx context.Context, f postgres.RunFilter) ([]postgres.RunSummary, error)
CountRuns(ctx context.Context, f postgres.RunFilter) (int, error)
CountRunsByState(ctx context.Context, f postgres.RunFilter) (map[string]int, error)
// CountRunsInFlight is the sidebar badge's number; it must stay cheap.
CountRunsInFlight(ctx context.Context) (int, error)
// WorkflowHistory is a workflow's runs with their params, newest first;
// with a day, that UTC day's.
WorkflowHistory(ctx context.Context, slug string, day *time.Time, limit int) ([]postgres.RunSummary, error)
Workflows(ctx context.Context) ([]postgres.WorkflowSummary, error)
// Connects is the schemes each workflow's runs wrote since a moment.
Connects(ctx context.Context, since time.Time) (map[string][]string, error)
// LastStepRuns is how each step of a workflow went the last time it ran;
// StepConnects what each step wrote since a moment.
LastStepRuns(ctx context.Context, slug string) (map[string]postgres.StepRun, error)
StepConnects(ctx context.Context, slug string, since time.Time) (map[string][]string, error)
RecentStates(ctx context.Context, slugs []string, n int) (map[string][]postgres.RecentRun, error)
Schedules(ctx context.Context) ([]postgres.ScheduleSummary, error)
Projects(ctx context.Context) ([]postgres.ProjectSummary, error)
QueueDepth(ctx context.Context) (int, int, error)
}
Leitura is what the UI needs from the database. The interface is declared here, in the consumer.
type RunsChart ¶
type RunsChart interface {
Get(ctx context.Context, id uuid.UUID) (run.Run, error)
NodeStates(ctx context.Context, id uuid.UUID) (map[string]postgres.NodeState, error)
LogsDaRun(ctx context.Context, id uuid.UUID) ([]postgres.StepLog, error)
// WaitingOn says what concurrency limit holds a queued run, if one does.
WaitingOn(ctx context.Context, id uuid.UUID) (*postgres.Wait, error)
}
RunsChart reads a Run and the state of its steps.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server carries the router and the dependencies readiness consults.
func NewServer ¶
NewServer builds the router. The checkers are named so that /ready says WHICH dependency failed, and not merely that something did.
`ui` may be nil: a process that only serves health checks does not need the pages, and requiring them would couple the server to the database for no reason.
func NewServerAutenticado ¶
func NewServerAutenticado(log *slog.Logger, checkers map[string]Checker, ui *UI, cred auth.Credential, inseguro bool, ) *Server
NewServerAutenticado is the same, requiring a session when the credential is configured. `inseguro` sends the cookie without the Secure flag — needed only for plain http in development, because a Secure cookie never comes back over http and the login would look simply broken.
func (*Server) HTTPServer ¶
HTTPServer returns the configured server. The timeouts exist because net/http's default is none: without them, a slow connection holds a handler indefinitely.
type UI ¶
type UI struct {
// contains filtered or unexported fields
}
UI registers the server-rendered pages and the JSON the React island consumes.
func NewUI ¶
func NewUI(l Leitura, d Definitions, e RunsChart, a Actions, al AlertsReader, c CatalogReader, m branding.Brand, log *slog.Logger, ) *UI
func (*UI) RegistrarLogin ¶
RegistrarLogin wires the session routes. It is kept apart from Registrar because it only exists when there is a credential: without one, a login screen that always accepts would be worse than none.
func (*UI) WithEndpointCalls ¶
func (u *UI) WithEndpointCalls(c EndpointCaller, console auth.Credential) *UI
WithEndpointCalls turns on Try it, for the APIs the caller has an address for, AND ONLY ON A CONSOLE THAT ASKS WHO YOU ARE: the console's key is one tenant's for every login, and an open console would hand that tenant's rows to whoever found the address -- the SQL tabs' rule, for their reason.
func (*UI) WithEndpoints ¶
func (u *UI) WithEndpoints(r EndpointsReader) *UI
WithEndpoints turns on Data → Endpoints and the "Read by" of a model's page.
func (*UI) WithEvents ¶
func (u *UI) WithEvents(r EventsReader) *UI
WithEvents turns on the Overview's event log. Without it the tab is empty.
func (*UI) WithFailing ¶
func (u *UI) WithFailing(r FailingReader) *UI
WithFailing turns on the list of failing workflows.
func (*UI) WithGallery ¶
WithGallery serves /_components: every component the screens are built from, with sample data, in one page. For somebody building the console -- the caller turns it on with BREVIS_ENV=local and nowhere else. Off, the route is not registered at all, so it is a 404 rather than a page that explains itself.
func (*UI) WithPreview ¶
func (*UI) WithVersion ¶
func (u *UI) WithVersion(current string, src UpdateSource) *UI
WithVersion shows the running version in the account menu and, when src knows a newer release, an update icon and a notice. A nil src is the version alone.
type UpdateSource ¶
UpdateSource knows the newest Brevis released and whether it is newer than the one running.