studio

package
v2.2.1 Latest Latest
Warning

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

Go to latest
Published: Oct 2, 2026 License: AGPL-3.0 Imports: 53 Imported by: 0

README

pkg/studio

Runs Tyk AI Studio inside another Go process. The standalone binary (main.go) is a thin wrapper over this package.

import (
	"github.com/TykTechnologies/midsommar/v2/config"
	"github.com/TykTechnologies/midsommar/v2/pkg/studio"
)

conf := config.LoadFrom(func(key string) string { return hostSettings[key] })
conf.BasePath = "/ai-studio"
conf.SiteURL = "https://control.example.com/ai-studio" // includes the base path

// Studio's own database or schema (DatabaseType/DatabaseURL in conf).
studioDB, err := studio.OpenDatabase(conf)
if err != nil {
	return err
}

s, err := studio.New(studio.Options{
	Config:  conf,
	DB:      studioDB, // the host closes it after Stop
	Version: hostVersion,
	Logger:  &hostLogger,
	TracerProvider: hostTracerProvider,
	MeterProvider:  hostMeterProvider,
	OnLicenceInvalid: func(err error) { /* alert, degrade, or stop Studio */ },
	// Enterprise: the AI Studio licence from the host's own settings (read at
	// start and at every check; s.ReloadLicense() applies a renewal at once).
	License: func() string { return hostSettings.AIStudioLicence() },

	// The host signs users in; Studio provisions and authorises them.
	Auth:      hostAuthenticator, // Authenticate(*http.Request) (*studio.Identity, error)
	LoginURL:  "/login?next={return_to}", // {return_to}: the page to come back to
	LogoutURL: "/logout",
	CSRF:      hostCSRFMiddleware, // optional; Studio's own otherwise
})
if err != nil {
	return err
}
defer s.Stop(ctx)

mux.Handle("/ai-studio/", s.HTTPHandler()) // with conf.BasePath = "/ai-studio"
mux.Handle("/.well-known/oauth-authorization-server/ai-studio", s.OAuthMetadataHandler())
go s.StartProxy()                      // AI gateway on Config.ProxyPort
go s.StartGRPC(edgeListener)           // edge control plane, when GatewayMode is "control"

Lifecycle

  • New migrates the database, seeds defaults, starts background services and builds the API, gateway and (in control mode) gRPC control server. It returns an error rather than exiting; nothing listens yet.
  • HTTPHandler is the admin API and UI, served under Config.BasePath; it strips the prefix itself. Session and CSRF cookies are scoped to the base path, and logout leaves the host's cookies alone. The console follows the base path and, with Auth, sends signed-out users to LoginURL. A {return_to} placeholder in LoginURL is replaced with the page they asked for (URL-encoded path under the base path, with query and hash), so the host can bring them back to it; validate it as a local path before redirecting. Without the placeholder, LoginURL is used as it is.
  • Chromeless renders pages only, without Studio's top bar and navigation drawers, for a host that draws its own navigation and links to Studio's routes under the base path. GET <base>/common/nav returns the surfaces and the admin, portal and chat menus the signed-in user may open, to build that navigation from.
  • With Auth, every request is offered to the host first. The identity it returns (subject, email, name, admin, optional group names) becomes a Studio user on first sight and is kept in step after that; Studio's own RBAC then decides what the user may do. Studio's password login, registration and SSO are switched off; its API keys still work.
  • CSRF replaces Studio's CSRF check for cookie-authenticated writes with the host's.
  • OAuthMetadataHandler serves the OAuth authorization server metadata for MCP clients; with a base path, mount it at /.well-known/oauth-authorization-server<base path> on the host root.
  • ListenAndServe, StartProxy and StartGRPC block until Stop or a serving error. StartProxy returns ErrGatewayNotLicensed at once without the gateway entitlement; StartGRPC returns ErrNotControlPlane outside control mode. ProxyHandler exposes the gateway for a host that serves it itself, but StartProxy is still needed: the gateway's /ai/ routes hop to its own listener.
  • Stop shuts everything down in dependency order, leaves the database open, and may be called more than once.
  • Options.GRPCTLSConfig serves edges with the host's *tls.Config instead of the certificate and key files in Config.
  • Options.HostTykConnection (Enterprise) gives Studio the host's Tyk Dashboard for the Tyk Dashboard MCP integration: URL, OrgID, Mode, GatewayURL and Token func() string. Studio keeps one host-managed connection for it (every replica upserts the same one), probes the Dashboard and activates it without an administrator, retrying in the background until the Dashboard answers. Those fields are read-only in Studio's UI, and Token is called for every Dashboard request and never stored, so key rotation stays with the host. New rejects an invalid one; a Community Edition build logs that it is ignored.

Headless control plane

NewControlPlane(ControlPlaneOptions) runs only the edge control plane (gRPC control server, push delivery, cluster membership and relay, analytics from edges) on a Postgres database a full Studio migrates, for a product that holds edge connections next to the full Studio (MDCB). It checks the schema with CheckSchema and never changes it, never takes the leader lease, and runs no API, UI, gateway, plugins, marketplace, scheduler or telemetry. Serve(listener) serves edges; Stop(ctx) shuts down in reverse order. It shares the one-instance-per-process rule with New. See features/Embedding.md, "Headless control plane".

Constraints

  • One instance per process. Configuration, the analytics recorder and the secrets key are process-wide; New returns ErrAlreadyRunning until the running Studio is stopped.
  • Frontend assets. Package ui embeds ui/admin-frontend/build, which is not committed, so a module download of Studio has no frontend to embed. Build with -tags studio_noui (package ui then embeds only a placeholder page) and pass the release's assets: every release tag carries tyk-ai-studio-ui-<tag>.tar.gz (and a .sha256) on its GitHub release. Unpack it and set Options.UIAssets to os.DirFS(dir), or embed the directory in the host's own binary. In this repository, npm run build in ui/admin-frontend and the default build tags embed it as before.
  • Telemetry globals. Pass TracerProvider and MeterProvider to keep Studio off the OpenTelemetry globals. Without them Studio configures tracing and metrics from Config the way the standalone binary does, which installs a global tracer provider and propagator.
  • Analytics. Studio always writes analytics to its own database, since budgets and spend are computed from it. To also ship records into the host's pipeline, pass AnalyticsSinks: each sink gets a copy of every record through its own bounded queue, and records a slow sink cannot take are dropped (and logged) rather than slowing requests.
  • Replace directives. Go ignores replace directives in dependencies, and a host needs to copy none of this repository's. The only one left, ./enterprise, points this repository's own builds at the submodule; an enterprise host requires the enterprise module itself (below). langchaingo is in tree, under third_party/langchaingo, and the gateway plugin SDK Studio uses lives in pkg/gatewayplugin and proto/microgateway_management, so the microgateway module is not needed.
  • Sharing a Postgres database. Set conf.DatabaseSchema (DATABASE_SCHEMA) to keep Studio's tables in a schema of their own inside the host's database; OpenDatabase creates it. Replicas may share it: New migrates and seeds under a Postgres advisory lock.
  • Databases and cgo. OpenDatabase opens Postgres. SQLite needs cgo, so it is in pkg/studio/sqlitedb: import that package for its side effect to use DatabaseType sqlite. Studio builds with CGO_ENABLED=0, but Chroma datasources are then unavailable: creating one (or switching one to Chroma) is refused with a 400, New logs a warning naming any existing ones, and a search across several datasources skips them. See "Building without cgo" in features/Embedding.md.
  • Configuration from the host. config.LoadFrom applies the same defaults as the environment loader but does not log the "environment variable is not set" notices. The documentation site server runs only in the standalone binary, so a LoadFrom configuration has no docs link (DocsURL empty) unless the host sets DOCS_URL_OVERRIDE.
  • Enterprise edition. The enterprise module is the private repository github.com/TykTechnologies/ai-studio-enterprise (module path github.com/TykTechnologies/ai-studio-enterprise/v2, tagged with the same versions as Studio). Set GOPRIVATE=github.com/TykTechnologies/ai-studio-enterprise with read access to it, require both modules at the same version, build with -tags enterprise, and import github.com/TykTechnologies/ai-studio-enterprise/v2/all for its side effects. New fails if an enterprise feature is missing. A Community Edition host needs none of this: no public package imports the enterprise module (make enterprise-import-guard checks it), so it is never fetched.

Example

examples/embed-host is a small runnable host: go run ./examples/embed-host (after building the frontend), then open http://localhost:8090/. For the Enterprise Edition, run it with -tags enterprise and TYK_AI_LICENSE set (examples/embed-host/main_enterprise.go imports enterprise/all and passes the licence as Options.License). -proxy-port (or EMBED_HOST_PROXY_PORT) moves the AI gateway off its default port 9095.

Documentation

Overview

Package studio runs Tyk AI Studio inside another Go process. A host builds a Studio with New, serves its HTTP handler, optionally starts the embedded AI gateway and the gRPC control server, and calls Stop on shutdown. The standalone binary is a thin wrapper over the same package.

Only one Studio may run in a process at a time: several packages keep process-wide state (the configuration, the analytics recorder, the secrets key). New refuses a second instance until the first is stopped.

Index

Constants

View Source
const (
	DefaultNodeLabel         = "studio"
	DefaultControlPlaneLabel = "control-plane"
)

Labels a replica gets when its host names none.

Variables

View Source
var (
	// ErrSchemaMissing: no Studio schema version is recorded. No Studio
	// has migrated the database, or the one that did predates schema
	// versions.
	ErrSchemaMissing = models.ErrSchemaMissing
	// ErrSchemaTooOld: the database was migrated by an older Studio than
	// this build needs; upgrade the Studio that migrates it first.
	ErrSchemaTooOld = models.ErrSchemaTooOld
	// ErrSchemaTooNew: a newer Studio migrated the database in a way this
	// build cannot read; upgrade this build.
	ErrSchemaTooNew = models.ErrSchemaTooNew
)

The errors CheckSchema wraps.

View Source
var ErrAlreadyRunning = errors.New("studio: another instance is already running in this process")

ErrAlreadyRunning is returned by New while another Studio is running in the process.

View Source
var ErrControlPlaneNeedsPostgres = errors.New("studio: a headless control plane needs a Postgres database shared with a full Studio")

ErrControlPlaneNeedsPostgres is returned by NewControlPlane for a database other than Postgres: a headless control plane shares a full Studio's database, and replicas coordinate only through Postgres.

View Source
var ErrGatewayNotLicensed = errors.New("studio: feature_gateway is not in the licence entitlements")

ErrGatewayNotLicensed is returned by StartProxy when the licence does not include the gateway.

View Source
var ErrNotControlPlane = errors.New(`studio: the gRPC control server runs only when GatewayMode is "control"`)

ErrNotControlPlane is returned by StartGRPC unless Config.GatewayMode is "control".

Functions

func CheckSchema

func CheckSchema(ctx context.Context, db *gorm.DB) error

CheckSchema reports whether this build of Studio can use db, as a full Studio (New) left it, without migrating it. It only reads: it creates and alters nothing, so it is safe against a database another process owns. New records the schema version after its migrations; a newer Studio's schema is accepted as long as it still declares this build a reader (see models.SchemaVersion). The error wraps ErrSchemaMissing, ErrSchemaTooOld or ErrSchemaTooNew, or is the database's own.

func OpenDatabase

func OpenDatabase(conf *config.AppConf) (*gorm.DB, error)

OpenDatabase connects to the database conf names (DatabaseType "postgres", or "sqlite" once pkg/studio/sqlitedb is imported, at DatabaseURL) and checks it responds. With DatabaseSchema set (postgres only) Studio's tables live in that schema: OpenDatabase creates it when missing and pins every connection's search_path to it alone. The result is what Options.DB takes. A host opens Studio's database with it rather than with gorm itself: Studio builds with its own copy of gorm (third_party/gorm.io), which the host's gorm cannot stand in for. The caller closes it after Stop, through DB().

func RegisterDatabaseDriver

func RegisterDatabaseDriver(name string, open func(dsn string) gorm.Dialector)

RegisterDatabaseDriver makes OpenDatabase accept DatabaseType name, opening it with open. Call it from an init function, as pkg/studio/sqlitedb does.

Types

type Authenticator

type Authenticator = auth.Authenticator

Authenticator authenticates a request on the host's behalf. It returns nil and no error when the request carries no host identity, and an error to reject the request.

type ControlPlane

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

ControlPlane is a headless AI Studio control plane: a replica that holds edge (microgateway) gRPC streams next to a full Studio sharing its database. It serves edges their configuration snapshots, delivers pushes to the edges whose streams it holds, records the analytics they send, and relays events between its edges and the other replicas. It runs no API, UI, gateway, plugins, marketplace, scheduler or telemetry, never migrates the database, and never takes the leader lease, so singleton work (budget blocks and budget.sync, marketplace sync, telemetry) stays with the full Studio and reaches this replica's edges through the relay.

Only one ControlPlane or Studio may run in a process at a time.

func NewControlPlane

func NewControlPlane(opts ControlPlaneOptions) (_ *ControlPlane, err error)

NewControlPlane starts a headless control plane on a database a full Studio has migrated. It refuses a schema this build does not understand (CheckSchema), joins the cluster as a replica that never leads, and builds the gRPC control server; nothing listens until Serve.

func (*ControlPlane) NodeID

func (c *ControlPlane) NodeID() string

NodeID is this replica's ID in the cluster registry.

func (*ControlPlane) Serve

func (c *ControlPlane) Serve(listener net.Listener) error

Serve serves the gRPC control server for edge gateways on listener, or on Config.GRPCHost:GRPCPort when listener is nil. It blocks until Stop is called or serving fails.

func (*ControlPlane) Stop

func (c *ControlPlane) Stop(ctx context.Context) error

Stop shuts the control plane down in reverse order: edge streams (their unanswered pushes go back to pending for the replica each edge reconnects to), push delivery, the cluster membership, analytics, licensing. It leaves the database open for its owner to close. Stop is safe to call more than once; after it returns, NewControlPlane or New may start another instance.

type ControlPlaneOptions

type ControlPlaneOptions struct {
	// Config is Studio's configuration (config.Load or config.LoadFrom).
	// The control plane reads the gRPC settings (GRPCHost, GRPCPort,
	// GRPCAuthToken, GRPCNextAuthToken, the TLS files unless TLSConfig is
	// set, BudgetSyncInterval), MicrogatewayEncryptionKey, SecretKey,
	// LicenseKey, AnalyticsBufferSize and LogLevel. NewControlPlane installs
	// it as the process-wide configuration.
	Config *config.AppConf

	// DB is the database a full Studio (New) migrates and runs on: Postgres
	// only, since the replicas coordinate through it. The control plane
	// never changes its schema (see CheckSchema) and the caller closes it
	// after Stop.
	DB *gorm.DB

	// Version is recorded with this replica in the cluster registry.
	Version string

	// Logger receives the control plane's logging. Nil logs JSON to stderr
	// at Config.LogLevel (info when empty).
	Logger *zerolog.Logger

	// License supplies the AI Studio Enterprise licence, as for New; nil uses
	// Config.LicenseKey. OnLicenceInvalid is called when it fails its
	// periodic re-check; nil exits the process. The control plane sends no
	// licence telemetry: the full Studio does.
	License          func() string
	OnLicenceInvalid func(error)

	// TLSConfig, when set, is the TLS configuration edges are served with,
	// in place of Config's certificate and key files.
	TLSConfig *tls.Config

	// NodeID identifies this replica in the cluster registry (pkg/cluster)
	// and as the owner of the edge streams it holds. Empty means a fresh ID
	// per process.
	NodeID string

	// NodeLabel names this replica on the cluster status and the Edge
	// Gateways page, where operators see which edges it holds (at most 64
	// letters, digits, spaces and . _ - : / ( ), e.g. "mdcb-eu-1"). Empty
	// means DefaultControlPlaneLabel.
	NodeLabel string

	// TracerProvider, Propagator and MeterProvider are the host's; when nil
	// the control plane records no spans or metrics of its own. It never
	// starts an exporter or serves a metrics endpoint.
	TracerProvider trace.TracerProvider
	Propagator     propagation.TextMapPropagator
	MeterProvider  metric.MeterProvider

	// AnalyticsSinks receive a copy of every analytics record edges send
	// (as for New), besides the shared database.
	AnalyticsSinks []analytics.AnalyticsHandler
}

ControlPlaneOptions configures a headless control plane. Config and DB are required.

type HostTykConnection

type HostTykConnection = tykmcp.HostConnection

HostTykConnection is the Tyk Dashboard connection the host provides (see Options.HostTykConnection).

type Identity

type Identity = services.HostIdentity

Identity is a user as the host has authenticated them. Subject and Email are required; Studio keeps the user's name, email, administrator status and, when Groups is not nil, group memberships in step with it.

type LicenseStatus

type LicenseStatus struct {
	Enterprise bool      // an Enterprise build (Community Edition has no licence)
	Valid      bool      // the licence is valid now
	ExpiresAt  time.Time // zero without a licence
	DaysLeft   int       // -1 without a licence
	// Entitlements are the licence's feature names.
	Entitlements []string
}

LicenseStatus is the Enterprise licence as Studio holds it, for a host to show next to its own licence.

type Options

type Options struct {
	// Config is Studio's configuration, typically from config.Load or
	// config.LoadFrom. New installs it as the process-wide configuration.
	Config *config.AppConf

	// DB is Studio's own database or schema. New migrates it; the caller
	// owns it and closes it after Stop.
	DB *gorm.DB

	// Version, BuildHash and BuildTime are reported by /common/system and in
	// telemetry and webhooks.
	Version, BuildHash, BuildTime string

	// Logger receives Studio's own logging. Nil keeps the logger package's
	// current logger (logger.Init sets it up for the standalone binary).
	// Packages that log through zerolog's global logger keep doing so.
	Logger *zerolog.Logger

	// TracerProvider and Propagator are used for Studio's spans and for
	// carrying trace context to upstream providers. When TracerProvider is
	// nil, Studio configures tracing from Config and installs it as the
	// OpenTelemetry global, as the standalone binary does.
	TracerProvider trace.TracerProvider
	Propagator     propagation.TextMapPropagator

	// MeterProvider receives Studio's metrics, which the host then exports;
	// Studio serves no metrics endpoint of its own. When nil and
	// Config.MetricsEnabled is set, Studio serves Prometheus metrics at
	// Config.MetricsPath.
	MeterProvider metric.MeterProvider

	// AnalyticsSinks receive a copy of every analytics record (chat
	// records, proxy logs, tool calls, compliance events, batches from
	// edges) besides Studio's own database, which budgets and spend are
	// computed from. Each sink has its own bounded queue: a slow sink loses
	// records (counted and logged) rather than slowing requests.
	AnalyticsSinks []analytics.AnalyticsHandler

	// OnLicenceInvalid is called when an Enterprise licence fails its
	// periodic re-check. Nil exits the process.
	OnLicenceInvalid func(error)

	// License supplies the AI Studio Enterprise licence (the same JWT as
	// TYK_AI_LICENSE, validated the same way) from the host's own
	// settings. It is read at start and at every validity check, so a
	// renewed licence takes effect without a restart; call ReloadLicense to
	// apply one at once. Nil uses Config.LicenseKey.
	License func() string

	// UIAssets is the built admin frontend, rooted at its build directory
	// (for example os.DirFS over the unpacked tyk-ai-studio-ui release
	// tarball). Nil uses the frontend embedded in package ui, which a build
	// with the studio_noui tag leaves out.
	UIAssets fs.FS

	// NodeID identifies this replica among the Studio replicas sharing the
	// database (pkg/cluster): it is recorded as the owner of the edge streams
	// this replica holds and of the work it claims. Empty means a fresh ID
	// (hostname, pid and a random suffix) per process, which is what a
	// replica restart needs: it must not inherit its predecessor's claims.
	NodeID string

	// NodeLabel names this replica on the cluster status and the Edge
	// Gateways page (at most 64 letters, digits, spaces and . _ - : / ( ),
	// e.g. "dashboard"). Empty means DefaultNodeLabel.
	NodeLabel string

	// SkipLLMDefaults skips seeding the default LLM configurations and
	// their secrets.
	SkipLLMDefaults bool

	// Auth, when set, authenticates every request on the host's behalf:
	// Studio provisions a user for each identity it returns (see Identity)
	// and switches off its own password login, registration and SSO. API
	// keys still authenticate requests Auth has no identity for.
	Auth Authenticator
	// LoginURL and LogoutURL are where the console sends a user to sign in
	// or out when Auth is set. The console replaces "{return_to}" anywhere
	// in LoginURL (e.g. "/login?next={return_to}") with the page the user
	// asked for, URL-encoded: a path on Studio's origin under the base path,
	// with its query and hash. The host validates it and returns the user
	// there after signing in. A LoginURL without it is used as it is.
	LoginURL, LogoutURL string

	// CSRF, when set, replaces Studio's CSRF protection for
	// cookie-authenticated requests with the host's. It must call the
	// handler it wraps only for requests that pass. CSRFTokenHeader and
	// CSRFTokenURL tell the console how to obtain and present the token.
	CSRF            func(http.Handler) http.Handler
	CSRFTokenHeader string
	CSRFTokenURL    string

	// GRPCTLSConfig, when set, is the TLS configuration the gRPC control
	// server serves edges with, in place of Config's certificate and key
	// files (Config.GRPCTLSCertPath, GRPCTLSKeyPath): a host with its own
	// certificate store, cipher suites or minimum version passes its own.
	GRPCTLSConfig *tls.Config

	// Chromeless makes the console render pages only: no top bar (the
	// Admin / Portal / Chat switch and the user menu) and no navigation
	// drawers, because the host draws its own. Sticky page headers then sit
	// at the top of the page instead of below Studio's 64px bar.
	Chromeless bool

	// HostTykConnection, when set, is the Tyk Dashboard the host is (or
	// fronts), for the Tyk Dashboard MCP integration (Enterprise). Studio
	// keeps one host-managed connection for it under a stable key, so
	// replicas sharing the database upsert the same one; it probes the
	// Dashboard and activates the connection itself, since the host is
	// trusted, retrying in the background until the Dashboard answers. The
	// host's fields are read-only in Studio's administration, and Studio
	// asks Token for the Dashboard key on every request, so rotating it is
	// the host's business. An administrator may still disable the
	// connection; Studio then leaves it disabled.
	HostTykConnection *HostTykConnection
}

Options configures a Studio. Config and DB are required.

type Studio

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

Studio is a running AI Studio instance.

func New

func New(opts Options) (_ *Studio, err error)

New builds a Studio: it migrates the database, seeds defaults, starts the background services and builds the HTTP API, the gateway and (in control mode) the gRPC control server. Nothing listens until the caller serves HTTPHandler or calls ListenAndServe, StartProxy or StartGRPC.

func (*Studio) HTTPHandler

func (s *Studio) HTTPHandler() http.Handler

HTTPHandler returns the admin API and UI handler: the portal, chat, management API and admin interface. Mount it at Config.BasePath (or the root when that is empty); it strips the base path itself, so the host passes requests through unchanged.

func (*Studio) LicenseStatus

func (s *Studio) LicenseStatus() LicenseStatus

LicenseStatus reports the licence Studio holds.

func (*Studio) ListenAndServe

func (s *Studio) ListenAndServe(addr, certFile, keyFile string) error

ListenAndServe serves HTTPHandler on addr, with TLS when certFile and keyFile are set. It blocks until Stop is called, returning http.ErrServerClosed, or until serving fails.

func (*Studio) OAuthMetadataHandler

func (s *Studio) OAuthMetadataHandler() http.Handler

OAuthMetadataHandler serves Studio's OAuth authorization server metadata for MCP clients. With a base path, RFC 8414 discovery happens outside it, at /.well-known/oauth-authorization-server followed by the base path, so the host mounts this handler there.

func (*Studio) ProxyHandler

func (s *Studio) ProxyHandler() http.Handler

ProxyHandler returns the embedded AI gateway's handler for a host that serves it itself. Call StartProxy as well: the gateway's /ai/ routes hop to its own listener on Config.ProxyPort.

func (*Studio) ReloadLicense

func (s *Studio) ReloadLicense() error

ReloadLicense re-reads the licence (Options.License, or Config.LicenseKey) and validates it now, for a host that has just stored a renewed one. Community Edition has no licence and returns nil. An error leaves the licence Studio already holds in place; the host can show it.

func (*Studio) StartGRPC

func (s *Studio) StartGRPC(listener net.Listener) error

StartGRPC serves the gRPC control server for edge gateways on listener, or on Config.GRPCHost:GRPCPort when listener is nil. It blocks until Stop is called or serving fails, and returns ErrNotControlPlane unless Config.GatewayMode is "control".

func (*Studio) StartProxy

func (s *Studio) StartProxy() error

StartProxy serves the embedded AI gateway on Config.ProxyPort. It blocks until Stop is called, returning http.ErrServerClosed, or until serving fails. It returns ErrGatewayNotLicensed at once when the licence does not include the gateway.

func (*Studio) Stop

func (s *Studio) Stop(ctx context.Context) error

Stop shuts Studio down: the HTTP API, the gateway, the gRPC control server, plugins and background workers, then licensing. It leaves the database open for its owner to close. ctx bounds the HTTP servers' graceful shutdown. Stop is safe to call more than once; after it returns, New may build another Studio.

Directories

Path Synopsis
Package sqlitedb adds SQLite to studio.OpenDatabase.
Package sqlitedb adds SQLite to studio.OpenDatabase.

Jump to

Keyboard shortcuts

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