config

package
v1.19.0 Latest Latest
Warning

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

Go to latest
Published: Aug 18, 2026 License: MIT Imports: 23 Imported by: 3

Documentation

Index

Constants

View Source
const (
	EnvDevelopment = "dev"
	EnvProduction  = "prod"

	ModeHttp = "http"
	ModeCli  = "cli"

	RoleWeb    = "web"
	RoleWorker = "worker"
	RoleAll    = "all"

	DefaultModeKey                   = "MELODY_DEFAULT_MODE"
	ProcessRoleKey                   = "MELODY_PROCESS_ROLE"
	EnvKey                           = "MELODY_ENV"
	HttpAddressKey                   = "MELODY_HTTP_ADDRESS"
	HttpMaxRequestBodyBytesKey       = "MELODY_HTTP_MAX_REQUEST_BODY_BYTES"
	HttpSessionTtlKey                = "MELODY_HTTP_SESSION_TTL"
	HttpSessionTombstoneRetentionKey = "MELODY_HTTP_SESSION_TOMBSTONE_RETENTION"
	HttpShutdownTimeoutKey           = "MELODY_HTTP_SHUTDOWN_TIMEOUT"
	CliNameKey                       = "MELODY_CLI_NAME"
	CliDescriptionKey                = "MELODY_CLI_DESCRIPTION"
	LogPathKey                       = "MELODY_LOG_PATH"
	LogLevelKey                      = "MELODY_LOG_LEVEL"
	DefaultLocaleKey                 = "MELODY_DEFAULT_LOCALE"
	PublicDirKey                     = "MELODY_PUBLIC_DIR"
	StaticIndexFileKey               = "MELODY_STATIC_INDEX_FILE"
	StaticEnableCacheKey             = "MELODY_STATIC_ENABLE_CACHE"
	StaticCacheMaxAgeKey             = "MELODY_STATIC_CACHE_MAX_AGE"
	StaticExcludedPathsKey           = "MELODY_STATIC_EXCLUDED_PATHS"

	KernelDefaultMode                   = "kernel.default_mode"
	KernelProcessRole                   = "kernel.process_role"
	KernelEnv                           = "kernel.environment"
	KernelHttpAddress                   = "kernel.http_address"
	KernelHttpMaxRequestBodyBytes       = "kernel.http.max_request_body_bytes"
	KernelHttpSessionTtl                = "kernel.http.session_ttl"
	KernelHttpSessionTombstoneRetention = "kernel.http.session_tombstone_retention"
	KernelHttpShutdownTimeout           = "kernel.http.shutdown_timeout"
	KernelCliName                       = "kernel.cli_name"
	KernelCliDescription                = "kernel.cli_description"
	KernelLogPath                       = "kernel.log_path"
	KernelLogLevel                      = "kernel.log_level"
	KernelDefaultLocale                 = "kernel.default_locale"
	KernelPublicDir                     = "kernel.public_dir"
	KernelStaticIndexFile               = "kernel.static.index_file"
	KernelStaticEnableCache             = "kernel.static.enable_cache"
	KernelStaticCacheMaxAge             = "kernel.static.cache_max_age"
	KernelStaticExcludedPaths           = "kernel.static.excluded_paths"

	KernelProjectDir = "kernel.project_dir"
	KernelLogsDir    = "kernel.logs_dir"
	KernelCacheDir   = "kernel.cache_dir"
)
View Source
const DefaultHttpShutdownTimeout = 5 * time.Second

DefaultHttpShutdownTimeout is how long a stopping http server waits for the requests already admitted when MELODY_HTTP_SHUTDOWN_TIMEOUT says nothing. Five seconds is deliberately far below the thirty the write timeout promises each request: a deployment whose supervisor grants a longer termination grace raises this to match, and one that leaves both at their defaults trades the tail of the slowest requests for a process that is gone before the supervisor escalates.

View Source
const DefaultSessionTombstoneRetention = 5 * time.Minute

DefaultSessionTombstoneRetention is how long a deleted session id keeps refusing a write-back when MELODY_HTTP_SESSION_TOMBSTONE_RETENTION says nothing. The window has to cover the longest a request of the deployment can still be holding a session snapshot loaded before the delete — nothing in the chain bounds a handler's lifetime, the server's socket timeouts cut the connection but not the goroutine — so a deployment whose slowest legitimate request outlives five minutes raises this to match, at the cost of one remembered entry per deletion within the window. The record lives in the manager, per process.

View Source
const DefaultSessionTtl = 0 * time.Second
DefaultSessionTtl is the lifetime a stored session gets when MELODY_HTTP_SESSION_TTL says nothing. It is zero — no expiry — which is what every deployment that predates the setting already had, so upgrading does not start logging users out at a lifetime nobody chose.

Zero is not free of hazard, and the hazard is worth naming here rather than discovering in a memory graph: melody mints a session for every request that arrives without a session cookie, so once an application writes to a session on a public path — a csrf token, a flash message, a locale — an unbounded lifetime turns every cookie-less request into a permanent entry. That is survivable in a shared store an operator can expire, and it is not in the default in-memory one, which is why the application warns at boot when it finds both together rather than quietly picking a lifetime on the deployment's behalf. Set this to what the deployment actually wants.

View Source
const MinimumSessionTtl = time.Second

MinimumSessionTtl is the shortest session lifetime that can still describe a session. Below it the value is not a short session, it is a broken one: the write succeeds, but the entry lapses before the response reaches the client and the client comes back with the cookie — a login that answers "welcome" and leaves the user logged out — and a second is the finest unit http itself dates anything in. Zero keeps its own meaning of "no expiry" and is not affected.

View Source
const (
	ServiceConfig = "service.config"
)

Variables

This section is empty.

Functions

func ConfigMustFromContainer

func ConfigMustFromContainer(serviceContainer containercontract.Container) configcontract.Configuration

func ConfigMustFromResolver added in v1.1.0

func ConfigMustFromResolver(resolver containercontract.Resolver) configcontract.Configuration

func IntWithDefault added in v1.4.0

func IntWithDefault(configParameter configcontract.Parameter, defaultValue int) int

IntWithDefault answers the default only for a parameter that is absent: a parameter that exists but does not parse panics instead of silently becoming the default, because a mistyped value that quietly turns into a number nobody wrote is a misconfiguration running in disguise.

func RoleAllowsBackgroundWork added in v1.16.0

func RoleAllowsBackgroundWork(role string) bool

RoleAllowsBackgroundWork reports whether a process with the given role should start background services such as outbox relays and message consumers; the default RoleAll preserves the single-process behavior where one binary does everything. Melody itself gates nothing on the role — it is declared intent for application wiring and long-running runners to query.

func RoleAllowsHttp added in v1.16.0

func RoleAllowsHttp(role string) bool

RoleAllowsHttp reports whether a process with the given role is meant to serve web traffic; informational — the runtime mode, not the role, decides whether the http kernel starts.

Types

type Configuration

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

func NewConfiguration

func NewConfiguration(
	environment *Environment,
	projectDirectory string,
) (*Configuration, error)

func (*Configuration) Cli

func (*Configuration) EnvironmentKeyCount added in v1.19.0

func (instance *Configuration) EnvironmentKeyCount() int

EnvironmentKeyCount reports how many keys the .env artifacts contributed. Zero almost always means the files were not found rather than deliberately empty (the warning in applyEnvironmentOverrides names the same condition); the count is exposed so the application can refuse to serve http on nothing but development defaults instead of merely warning.

func (*Configuration) Get

func (instance *Configuration) Get(name string) configcontract.Parameter

func (*Configuration) Http

func (*Configuration) Kernel

func (*Configuration) MarkSecret added in v1.18.0

func (instance *Configuration) MarkSecret(name string) bool
MarkSecret marks an already registered parameter as holding a credential. The parameters melody registers automatically from the .env artifacts are the ones most likely to hold one, and they exist before any module runs, so marking them is separate from declaring them.

An absent parameter is left alone rather than reported: an environment key is legitimately undefined in some environments, and refusing to boot over one would make the marking unusable exactly where it matters. The secret column of debug:parameters is what confirms a marking took effect.

func (*Configuration) MarkServing added in v1.19.0

func (instance *Configuration) MarkServing()

MarkServing records that the wiring phase is over and the application has started running. From that point Resolve is refused: services built during boot hold the values they read, so re-resolving reconfigures nothing and only rewrites the parameter store under readers that expect it settled. Registering a parameter still works — it resolves itself on registration — which is what keeps a late module functioning.

func (*Configuration) MustGet

func (instance *Configuration) MustGet(name string) configcontract.Parameter

func (*Configuration) Names

func (instance *Configuration) Names() []string

func (*Configuration) Parameters

func (instance *Configuration) Parameters() ParameterMap

func (*Configuration) RegisterRuntime

func (instance *Configuration) RegisterRuntime(name string, value any)

func (*Configuration) RegisterRuntimeSecret added in v1.18.0

func (instance *Configuration) RegisterRuntimeSecret(name string, value any)

RegisterRuntimeSecret registers a parameter that holds a credential, so that the commands which render the configuration redact it. The value is stored and resolved like any other: the marking governs display, not storage, and it travels to every parameter whose template reads this one. It does not travel backwards: the parameter melody auto-registered from the environment key this template reads holds the same credential and needs its own MarkSecret.

func (*Configuration) Resolve

func (instance *Configuration) Resolve() error

Resolve resolves every parameter's template in one order-independent batch and settles the ones the constructor's tolerant pass deferred; a reference that is still undefined here is the error that pass postponed.

type Environment

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

func NewEnvironment

func NewEnvironment(source configcontract.EnvironmentSource) (*Environment, error)

func (*Environment) All

func (instance *Environment) All() map[string]string

func (*Environment) Get

func (instance *Environment) Get(key string) (string, bool)

type EnvironmentSource

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

func NewEnvironmentSource

func NewEnvironmentSource(
	fileSystem fs.FS,
	baseDir string,
) *EnvironmentSource

func (*EnvironmentSource) Load

func (instance *EnvironmentSource) Load() (map[string]string, error)

type Parameter

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

func NewParameter

func NewParameter(environmentKey string, environmentValue any, value any, isDefault bool) *Parameter

func (*Parameter) Bool

func (instance *Parameter) Bool() (bool, error)

Bool reads the value through the same parser its sibling accessors use, the last typed door that used to carry a grammar of its own. What it accepts and refuses is unchanged — the hand-written branches recognised exactly the shapes internal.Bool recognises — and what changes is what a refusal SAYS: a parameter holding a number, which is what RegisterRuntime("feature.flag", 1) hands over, was refused with a nil cause and a context carrying only the key, so the operator learned that something failed and nothing about what, while every sibling answered with a ParseError naming the parameter, the target type and the value.

func (*Parameter) Duration added in v1.18.0

func (instance *Parameter) Duration() (time.Duration, error)

func (*Parameter) EnvironmentKey

func (instance *Parameter) EnvironmentKey() string

func (*Parameter) EnvironmentValue

func (instance *Parameter) EnvironmentValue() any

func (*Parameter) Float added in v1.18.0

func (instance *Parameter) Float() (float64, error)

func (*Parameter) Int

func (instance *Parameter) Int() (int, error)

Int reads the value through the same parser its sibling accessors use, so one grammar answers for every typed reading of a parameter: an int64 registered at runtime — what a caller writing RegisterRuntime("app.batch_size", int64(500)) hands over — converted through Float and refused through Int, on a value that is plainly a whole number. The one thing this door adds is the narrowing: internal.Int answers an int64 while an int is what a caller asked for, so a value outside the int range is refused by name rather than truncated, which is the silent corruption the shared parser already refuses for a float64 too wide to hold.

func (*Parameter) IsDefault

func (instance *Parameter) IsDefault() bool

func (*Parameter) IsSecret added in v1.18.0

func (instance *Parameter) IsSecret() bool

IsSecret reports whether the parameter was declared as holding a credential, either directly or by resolving a template that reads one. Commands that render the configuration redact such a parameter; the value itself is untouched.

func (*Parameter) MustString

func (instance *Parameter) MustString() string

func (*Parameter) String

func (instance *Parameter) String() string

func (*Parameter) Value

func (instance *Parameter) Value() any

type ParameterMap

type ParameterMap map[string]*Parameter

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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