Documentation
¶
Overview ¶
Package microconfig owns per-service appsettings: one JSON tree per microservice and environment, published to the MICROCONFIG KV bucket at key "{envID}.{microserviceID}". The same concept is /configs on the API and SETTINGS_JSON in the database.
It also owns the two reference tables the other domains point at — environments and microservices — which is why the delete paths here refuse to remove a row that flags, appsettings or localization still reference rather than cascading. Losing an environment by accident would take its configuration with it.
Settings size is checked against the KV value limit before the database write, so an oversized tree cannot be committed as a row that no consumer will ever receive.
Index ¶
- Variables
- type AppSettingsFilter
- type Environment
- type Handler
- func (h *Handler) CreateEnvironment(w http.ResponseWriter, r *http.Request)
- func (h *Handler) CreateMicroservice(w http.ResponseWriter, r *http.Request)
- func (h *Handler) CreateMicroserviceConfig(w http.ResponseWriter, r *http.Request)
- func (h *Handler) DeleteEnvironment(w http.ResponseWriter, r *http.Request)
- func (h *Handler) DeleteMicroservice(w http.ResponseWriter, r *http.Request)
- func (h *Handler) DeleteMicroserviceConfig(w http.ResponseWriter, r *http.Request)
- func (h *Handler) GetMicroservice(w http.ResponseWriter, r *http.Request)
- func (h *Handler) GetMicroserviceConfig(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ListEnvironments(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ListMicroserviceConfigs(w http.ResponseWriter, r *http.Request)
- func (h *Handler) ListMicroservices(w http.ResponseWriter, r *http.Request)
- func (h *Handler) UpdateMicroserviceConfig(w http.ResponseWriter, r *http.Request)
- type Microservice
- type MicroserviceAppSettings
- type Page
- type PostgresRepository
- func (r *PostgresRepository) CreateEnvironment(ctx context.Context, name string) (*Environment, error)
- func (r *PostgresRepository) CreateMicroservice(ctx context.Context, name string) (*Microservice, error)
- func (r *PostgresRepository) CreateMicroserviceConfig(ctx context.Context, input MicroserviceAppSettings) (*MicroserviceAppSettings, error)
- func (r *PostgresRepository) DeleteEnvironment(ctx context.Context, id int64) error
- func (r *PostgresRepository) DeleteMicroservice(ctx context.Context, id int64) error
- func (r *PostgresRepository) DeleteMicroserviceConfig(ctx context.Context, id int64) (*MicroserviceAppSettings, error)
- func (r *PostgresRepository) GetMicroserviceByID(ctx context.Context, id int64) (*Microservice, error)
- func (r *PostgresRepository) GetMicroserviceConfigByID(ctx context.Context, id int64) (*MicroserviceAppSettings, error)
- func (r *PostgresRepository) ListAllForReconcile(ctx context.Context, since time.Time) ([]MicroserviceAppSettings, error)
- func (r *PostgresRepository) ListEnvironments(ctx context.Context, page Page) ([]Environment, error)
- func (r *PostgresRepository) ListMicroserviceConfigs(ctx context.Context, filter AppSettingsFilter) ([]MicroserviceAppSettings, error)
- func (r *PostgresRepository) ListMicroservices(ctx context.Context, page Page) ([]Microservice, error)
- func (r *PostgresRepository) UpdateMicroserviceConfig(ctx context.Context, input MicroserviceAppSettings) (*MicroserviceAppSettings, error)
- type Repository
- type SQLiteRepository
- func (r *SQLiteRepository) CreateEnvironment(ctx context.Context, name string) (*Environment, error)
- func (r *SQLiteRepository) CreateMicroservice(ctx context.Context, name string) (*Microservice, error)
- func (r *SQLiteRepository) CreateMicroserviceConfig(ctx context.Context, input MicroserviceAppSettings) (*MicroserviceAppSettings, error)
- func (r *SQLiteRepository) DeleteEnvironment(ctx context.Context, id int64) error
- func (r *SQLiteRepository) DeleteMicroservice(ctx context.Context, id int64) error
- func (r *SQLiteRepository) DeleteMicroserviceConfig(ctx context.Context, id int64) (*MicroserviceAppSettings, error)
- func (r *SQLiteRepository) GetMicroserviceByID(ctx context.Context, id int64) (*Microservice, error)
- func (r *SQLiteRepository) GetMicroserviceConfigByID(ctx context.Context, id int64) (*MicroserviceAppSettings, error)
- func (r *SQLiteRepository) ListAllForReconcile(ctx context.Context, since time.Time) ([]MicroserviceAppSettings, error)
- func (r *SQLiteRepository) ListEnvironments(ctx context.Context, page Page) ([]Environment, error)
- func (r *SQLiteRepository) ListMicroserviceConfigs(ctx context.Context, filter AppSettingsFilter) ([]MicroserviceAppSettings, error)
- func (r *SQLiteRepository) ListMicroservices(ctx context.Context, page Page) ([]Microservice, error)
- func (r *SQLiteRepository) UpdateMicroserviceConfig(ctx context.Context, input MicroserviceAppSettings) (*MicroserviceAppSettings, error)
- type Service
- func (s *Service) CreateEnvironment(ctx context.Context, req Environment) (*Environment, error)
- func (s *Service) CreateMicroservice(ctx context.Context, req Microservice) (*Microservice, error)
- func (s *Service) CreateMicroserviceConfig(ctx context.Context, req MicroserviceAppSettings) (*MicroserviceAppSettings, error)
- func (s *Service) DeleteEnvironment(ctx context.Context, id int64) error
- func (s *Service) DeleteMicroservice(ctx context.Context, id int64) error
- func (s *Service) DeleteMicroserviceConfig(ctx context.Context, id int64) error
- func (s *Service) GetMicroserviceByID(ctx context.Context, id int64) (*Microservice, error)
- func (s *Service) GetMicroserviceConfigByID(ctx context.Context, id int64) (*MicroserviceAppSettings, error)
- func (s *Service) ListEnvironments(ctx context.Context, page Page) ([]Environment, error)
- func (s *Service) ListMicroserviceConfigs(ctx context.Context, filter AppSettingsFilter) ([]MicroserviceAppSettings, error)
- func (s *Service) ListMicroservices(ctx context.Context, page Page) ([]Microservice, error)
- func (s *Service) UpdateMicroserviceConfig(ctx context.Context, req MicroserviceAppSettings) (*MicroserviceAppSettings, error)
Constants ¶
This section is empty.
Variables ¶
var ErrConfigExists = errors.New("appsettings for this microservice and environment already exist")
var ErrConfigNotFound = errors.New("config not found")
var ErrConflict = errors.New("config was modified by someone else")
ErrConflict is returned when an update carried an expected UPDATED_AT that no longer matches the stored row: somebody else edited it first. Distinct so a handler can map it to HTTP 409.
var ErrEnvironmentExists = errors.New("environment with this name already exists")
var ErrEnvironmentInUse = errors.New("environment still has flag, appsettings or localization rows")
var ErrEnvironmentNotFound = errors.New("environment not found")
var ErrInvalidConfigID = errors.New("invalid config id")
var ErrInvalidEnvironmentID = errors.New("invalid environment id")
var ErrInvalidEnvironmentName = errors.New("invalid environment name")
var ErrInvalidMicroserviceID = errors.New("invalid microservice id")
var ErrInvalidMicroserviceName = errors.New("invalid microservice name")
Names are the natural keys of the two reference tables and they end up in log lines and admin UIs, so they are bounded and non-empty.
var ErrInvalidSettingsJSON = errors.New("invalid settings json")
var ErrMicroserviceExists = errors.New("microservice with this name already exists")
Creation collides with the natural unique keys: MICROSERVICE, ENVIRONMENT, and (MICROSERVICE_ID, ENVIRONMENT_ID) on the appsettings table. Distinct so a handler can map them to HTTP 409.
var ErrMicroserviceInUse = errors.New("microservice still has appsettings or localization rows")
Deleting a reference row that something still points at would orphan the pointing rows, so it is refused rather than cascaded: an environment or a microservice is not the kind of thing to remove by accident.
var ErrMicroserviceNotFound = errors.New("microservice not found")
var ErrSettingsTooLarge = errors.New("settings json exceeds the maximum value size")
ErrSettingsTooLarge rejects a tree bigger than a KV value may be. Accepting it would return a 201 for a row that can never be published, so the write would look successful while consumers never saw it.
Functions ¶
This section is empty.
Types ¶
type AppSettingsFilter ¶
AppSettingsFilter narrows the appsettings list. Zero ids match everything.
type Environment ¶
type Environment struct {
ID int64 `json:"id"`
Environment string `json:"name"`
UpdatedAt time.Time `json:"updatedAt"`
}
Environment is the other reference table every domain keys off. It lives here rather than in its own package because this is where the reference tables are already served from, and a separate package would buy nothing but wiring.
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
func NewHandler ¶
func (*Handler) CreateEnvironment ¶
func (h *Handler) CreateEnvironment(w http.ResponseWriter, r *http.Request)
POST /environments
func (*Handler) CreateMicroservice ¶
func (h *Handler) CreateMicroservice(w http.ResponseWriter, r *http.Request)
POST /microservices
func (*Handler) CreateMicroserviceConfig ¶
func (h *Handler) CreateMicroserviceConfig(w http.ResponseWriter, r *http.Request)
POST /configs/values
func (*Handler) DeleteEnvironment ¶
func (h *Handler) DeleteEnvironment(w http.ResponseWriter, r *http.Request)
DELETE /environments/{id}
func (*Handler) DeleteMicroservice ¶
func (h *Handler) DeleteMicroservice(w http.ResponseWriter, r *http.Request)
DELETE /microservices/{id}
func (*Handler) DeleteMicroserviceConfig ¶
func (h *Handler) DeleteMicroserviceConfig(w http.ResponseWriter, r *http.Request)
DELETE /configs/values/{id}
func (*Handler) GetMicroservice ¶
func (h *Handler) GetMicroservice(w http.ResponseWriter, r *http.Request)
GET /configs/{id}
func (*Handler) GetMicroserviceConfig ¶
func (h *Handler) GetMicroserviceConfig(w http.ResponseWriter, r *http.Request)
GET /configs/values/{id}
func (*Handler) ListEnvironments ¶
func (h *Handler) ListEnvironments(w http.ResponseWriter, r *http.Request)
GET /environments?limit=&offset=
func (*Handler) ListMicroserviceConfigs ¶
func (h *Handler) ListMicroserviceConfigs(w http.ResponseWriter, r *http.Request)
GET /configs/values?microserviceId=&environmentId=&limit=&offset=
func (*Handler) ListMicroservices ¶
func (h *Handler) ListMicroservices(w http.ResponseWriter, r *http.Request)
GET /microservices?limit=&offset=
func (*Handler) UpdateMicroserviceConfig ¶
func (h *Handler) UpdateMicroserviceConfig(w http.ResponseWriter, r *http.Request)
PUT /configs/values
type Microservice ¶
type MicroserviceAppSettings ¶
type MicroserviceAppSettings struct {
ID int64 `json:"id"`
MicroserviceID int64 `json:"microserviceId"`
EnvironmentID int64 `json:"environmentId"`
SettingsJSON json.RawMessage `json:"settingsJson"`
UpdatedAt time.Time `json:"updatedAt"`
// ExpectedUpdatedAt opts an update into optimistic concurrency: the write
// only applies while the stored row still carries this timestamp, so two
// admins editing the same config no longer silently overwrite each other.
// Absent (nil) keeps the original last-write-wins behaviour.
ExpectedUpdatedAt *time.Time `json:"expectedUpdatedAt,omitempty"`
}
type Page ¶
Page bounds a list query. The service normalises it, so a repository can bind both values as given.
type PostgresRepository ¶
type PostgresRepository struct {
// contains filtered or unexported fields
}
func NewPostgresRepository ¶
func NewPostgresRepository(db *sql.DB) *PostgresRepository
func (*PostgresRepository) CreateEnvironment ¶
func (r *PostgresRepository) CreateEnvironment(ctx context.Context, name string) (*Environment, error)
func (*PostgresRepository) CreateMicroservice ¶
func (r *PostgresRepository) CreateMicroservice(ctx context.Context, name string) (*Microservice, error)
func (*PostgresRepository) CreateMicroserviceConfig ¶
func (r *PostgresRepository) CreateMicroserviceConfig(ctx context.Context, input MicroserviceAppSettings) (*MicroserviceAppSettings, error)
func (*PostgresRepository) DeleteEnvironment ¶
func (r *PostgresRepository) DeleteEnvironment(ctx context.Context, id int64) error
DeleteEnvironment refuses to orphan the rows that point at it. An environment is the widest blast radius in the schema — cascading it would wipe every flag value, appsettings row and bundle for a whole stage.
func (*PostgresRepository) DeleteMicroservice ¶
func (r *PostgresRepository) DeleteMicroservice(ctx context.Context, id int64) error
DeleteMicroservice refuses to orphan the rows that point at it. Cascading would silently delete that service's appsettings and translations in every environment.
func (*PostgresRepository) DeleteMicroserviceConfig ¶
func (r *PostgresRepository) DeleteMicroserviceConfig(ctx context.Context, id int64) (*MicroserviceAppSettings, error)
func (*PostgresRepository) GetMicroserviceByID ¶
func (r *PostgresRepository) GetMicroserviceByID(ctx context.Context, id int64) (*Microservice, error)
func (*PostgresRepository) GetMicroserviceConfigByID ¶
func (r *PostgresRepository) GetMicroserviceConfigByID(ctx context.Context, id int64) (*MicroserviceAppSettings, error)
func (*PostgresRepository) ListAllForReconcile ¶
func (r *PostgresRepository) ListAllForReconcile(ctx context.Context, since time.Time) ([]MicroserviceAppSettings, error)
ListAllForReconcile returns appsettings rows to republish to KV. A zero `since` sweeps every row; otherwise only rows changed at or after `since`.
func (*PostgresRepository) ListEnvironments ¶
func (r *PostgresRepository) ListEnvironments(ctx context.Context, page Page) ([]Environment, error)
func (*PostgresRepository) ListMicroserviceConfigs ¶
func (r *PostgresRepository) ListMicroserviceConfigs(ctx context.Context, filter AppSettingsFilter) ([]MicroserviceAppSettings, error)
func (*PostgresRepository) ListMicroservices ¶
func (r *PostgresRepository) ListMicroservices(ctx context.Context, page Page) ([]Microservice, error)
func (*PostgresRepository) UpdateMicroserviceConfig ¶
func (r *PostgresRepository) UpdateMicroserviceConfig(ctx context.Context, input MicroserviceAppSettings) (*MicroserviceAppSettings, error)
type Repository ¶
type Repository interface {
GetMicroserviceConfigByID(ctx context.Context, id int64) (*MicroserviceAppSettings, error)
UpdateMicroserviceConfig(ctx context.Context, input MicroserviceAppSettings) (*MicroserviceAppSettings, error)
GetMicroserviceByID(ctx context.Context, id int64) (*Microservice, error)
ListMicroserviceConfigs(ctx context.Context, filter AppSettingsFilter) ([]MicroserviceAppSettings, error)
CreateMicroserviceConfig(ctx context.Context, input MicroserviceAppSettings) (*MicroserviceAppSettings, error)
// DeleteMicroserviceConfig returns the row it removed, so the caller can
// derive the KV key it has to purge.
DeleteMicroserviceConfig(ctx context.Context, id int64) (*MicroserviceAppSettings, error)
ListMicroservices(ctx context.Context, page Page) ([]Microservice, error)
CreateMicroservice(ctx context.Context, name string) (*Microservice, error)
DeleteMicroservice(ctx context.Context, id int64) error
ListEnvironments(ctx context.Context, page Page) ([]Environment, error)
CreateEnvironment(ctx context.Context, name string) (*Environment, error)
DeleteEnvironment(ctx context.Context, id int64) error
}
type SQLiteRepository ¶
type SQLiteRepository struct {
// contains filtered or unexported fields
}
SQLiteRepository backs the local test stack (see internal/database/sqlite.go). Same tables and columns as PostgreSQL; only the bind syntax differs (? vs $1).
func NewSQLiteRepository ¶
func NewSQLiteRepository(db *sql.DB) *SQLiteRepository
func (*SQLiteRepository) CreateEnvironment ¶
func (r *SQLiteRepository) CreateEnvironment(ctx context.Context, name string) (*Environment, error)
func (*SQLiteRepository) CreateMicroservice ¶
func (r *SQLiteRepository) CreateMicroservice(ctx context.Context, name string) (*Microservice, error)
func (*SQLiteRepository) CreateMicroserviceConfig ¶
func (r *SQLiteRepository) CreateMicroserviceConfig(ctx context.Context, input MicroserviceAppSettings) (*MicroserviceAppSettings, error)
func (*SQLiteRepository) DeleteEnvironment ¶
func (r *SQLiteRepository) DeleteEnvironment(ctx context.Context, id int64) error
func (*SQLiteRepository) DeleteMicroservice ¶
func (r *SQLiteRepository) DeleteMicroservice(ctx context.Context, id int64) error
func (*SQLiteRepository) DeleteMicroserviceConfig ¶
func (r *SQLiteRepository) DeleteMicroserviceConfig(ctx context.Context, id int64) (*MicroserviceAppSettings, error)
func (*SQLiteRepository) GetMicroserviceByID ¶
func (r *SQLiteRepository) GetMicroserviceByID(ctx context.Context, id int64) (*Microservice, error)
func (*SQLiteRepository) GetMicroserviceConfigByID ¶
func (r *SQLiteRepository) GetMicroserviceConfigByID(ctx context.Context, id int64) (*MicroserviceAppSettings, error)
func (*SQLiteRepository) ListAllForReconcile ¶
func (r *SQLiteRepository) ListAllForReconcile(ctx context.Context, since time.Time) ([]MicroserviceAppSettings, error)
func (*SQLiteRepository) ListEnvironments ¶
func (r *SQLiteRepository) ListEnvironments(ctx context.Context, page Page) ([]Environment, error)
func (*SQLiteRepository) ListMicroserviceConfigs ¶
func (r *SQLiteRepository) ListMicroserviceConfigs(ctx context.Context, filter AppSettingsFilter) ([]MicroserviceAppSettings, error)
func (*SQLiteRepository) ListMicroservices ¶
func (r *SQLiteRepository) ListMicroservices(ctx context.Context, page Page) ([]Microservice, error)
func (*SQLiteRepository) UpdateMicroserviceConfig ¶
func (r *SQLiteRepository) UpdateMicroserviceConfig(ctx context.Context, input MicroserviceAppSettings) (*MicroserviceAppSettings, error)
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
func NewService ¶
func NewService(repo Repository, pub messaging.ConfigPublisher) *Service
func (*Service) CreateEnvironment ¶
func (s *Service) CreateEnvironment(ctx context.Context, req Environment) (*Environment, error)
func (*Service) CreateMicroservice ¶
func (s *Service) CreateMicroservice(ctx context.Context, req Microservice) (*Microservice, error)
func (*Service) CreateMicroserviceConfig ¶
func (s *Service) CreateMicroserviceConfig(ctx context.Context, req MicroserviceAppSettings) (*MicroserviceAppSettings, error)
func (*Service) DeleteEnvironment ¶
func (*Service) DeleteMicroservice ¶
func (*Service) DeleteMicroserviceConfig ¶
DeleteMicroserviceConfig removes the row and the KV key it fed. Waiting for the next full reconcile to prune the key would leave consumers serving deleted settings for up to a whole interval.
func (*Service) GetMicroserviceByID ¶
func (*Service) GetMicroserviceConfigByID ¶
func (*Service) ListEnvironments ¶
func (*Service) ListMicroserviceConfigs ¶
func (s *Service) ListMicroserviceConfigs(ctx context.Context, filter AppSettingsFilter) ([]MicroserviceAppSettings, error)
func (*Service) ListMicroservices ¶
func (*Service) UpdateMicroserviceConfig ¶
func (s *Service) UpdateMicroserviceConfig(ctx context.Context, req MicroserviceAppSettings) (*MicroserviceAppSettings, error)