microconfig

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Aug 7, 2026 License: MIT Imports: 15 Imported by: 0

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

Constants

This section is empty.

Variables

View Source
var ErrConfigExists = errors.New("appsettings for this microservice and environment already exist")
View Source
var ErrConfigNotFound = errors.New("config not found")
View Source
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.

View Source
var ErrEnvironmentExists = errors.New("environment with this name already exists")
View Source
var ErrEnvironmentInUse = errors.New("environment still has flag, appsettings or localization rows")
View Source
var ErrEnvironmentNotFound = errors.New("environment not found")
View Source
var ErrInvalidConfigID = errors.New("invalid config id")
View Source
var ErrInvalidEnvironmentID = errors.New("invalid environment id")
View Source
var ErrInvalidEnvironmentName = errors.New("invalid environment name")
View Source
var ErrInvalidMicroserviceID = errors.New("invalid microservice id")
View Source
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.

View Source
var ErrInvalidSettingsJSON = errors.New("invalid settings json")
View Source
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.

View Source
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.

View Source
var ErrMicroserviceNotFound = errors.New("microservice not found")
View Source
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

type AppSettingsFilter struct {
	Page
	MicroserviceID int64
	EnvironmentID  int64
}

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 NewHandler(service *Service) *Handler

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 Microservice struct {
	ID           int64     `json:"id"`
	Microservice string    `json:"name"`
	UpdatedAt    time.Time `json:"updatedAt"`
}

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

type Page struct {
	Limit  int
	Offset int
}

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 (s *Service) DeleteEnvironment(ctx context.Context, id int64) error

func (*Service) DeleteMicroservice

func (s *Service) DeleteMicroservice(ctx context.Context, id int64) error

func (*Service) DeleteMicroserviceConfig

func (s *Service) DeleteMicroserviceConfig(ctx context.Context, id int64) error

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 (s *Service) GetMicroserviceByID(ctx context.Context, id int64) (*Microservice, error)

func (*Service) GetMicroserviceConfigByID

func (s *Service) GetMicroserviceConfigByID(ctx context.Context, id int64) (*MicroserviceAppSettings, error)

func (*Service) ListEnvironments

func (s *Service) ListEnvironments(ctx context.Context, page Page) ([]Environment, error)

func (*Service) ListMicroserviceConfigs

func (s *Service) ListMicroserviceConfigs(ctx context.Context, filter AppSettingsFilter) ([]MicroserviceAppSettings, error)

func (*Service) ListMicroservices

func (s *Service) ListMicroservices(ctx context.Context, page Page) ([]Microservice, error)

func (*Service) UpdateMicroserviceConfig

func (s *Service) UpdateMicroserviceConfig(ctx context.Context, req MicroserviceAppSettings) (*MicroserviceAppSettings, error)

Jump to

Keyboard shortcuts

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