Documentation
¶
Index ¶
- Constants
- func ConfigMustFromContainer(serviceContainer containercontract.Container) configcontract.Configuration
- func ConfigMustFromResolver(resolver containercontract.Resolver) configcontract.Configuration
- func IntWithDefault(configParameter configcontract.Parameter, defaultValue int) int
- func RoleAllowsBackgroundWork(role string) bool
- func RoleAllowsHttp(role string) bool
- type Configuration
- func (instance *Configuration) Cli() configcontract.CliConfiguration
- func (instance *Configuration) EnvironmentKeyCount() int
- func (instance *Configuration) Get(name string) configcontract.Parameter
- func (instance *Configuration) Http() configcontract.HttpConfiguration
- func (instance *Configuration) Kernel() configcontract.KernelConfiguration
- func (instance *Configuration) MarkSecret(name string) bool
- func (instance *Configuration) MarkServing()
- func (instance *Configuration) MustGet(name string) configcontract.Parameter
- func (instance *Configuration) Names() []string
- func (instance *Configuration) Parameters() ParameterMap
- func (instance *Configuration) RegisterRuntime(name string, value any)
- func (instance *Configuration) RegisterRuntimeSecret(name string, value any)
- func (instance *Configuration) Resolve() error
- type Environment
- type EnvironmentSource
- type Parameter
- func (instance *Parameter) Bool() (bool, error)
- func (instance *Parameter) Duration() (time.Duration, error)
- func (instance *Parameter) EnvironmentKey() string
- func (instance *Parameter) EnvironmentValue() any
- func (instance *Parameter) Float() (float64, error)
- func (instance *Parameter) Int() (int, error)
- func (instance *Parameter) IsDefault() bool
- func (instance *Parameter) IsSecret() bool
- func (instance *Parameter) MustString() string
- func (instance *Parameter) String() string
- func (instance *Parameter) Value() any
- type ParameterMap
Constants ¶
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" )
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.
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.
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.
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.
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
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
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 (instance *Configuration) Cli() configcontract.CliConfiguration
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 (instance *Configuration) Http() configcontract.HttpConfiguration
func (*Configuration) Kernel ¶
func (instance *Configuration) Kernel() configcontract.KernelConfiguration
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
type EnvironmentSource ¶
type EnvironmentSource struct {
// contains filtered or unexported fields
}
func NewEnvironmentSource ¶
func NewEnvironmentSource( fileSystem fs.FS, baseDir string, ) *EnvironmentSource
type Parameter ¶
type Parameter struct {
// contains filtered or unexported fields
}
func NewParameter ¶
func (*Parameter) Bool ¶
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) EnvironmentKey ¶
func (*Parameter) EnvironmentValue ¶
func (*Parameter) Int ¶
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) IsSecret ¶ added in v1.18.0
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.