Documentation
¶
Overview ¶
Package control provides the data types and logic for defining how component health statuses influence the overall application health. This is a core part of the status monitoring system, enabling granular control over failure propagation.
Overview ¶
In a distributed system or a complex application, "health" is rarely a binary state. Some components are critical (e.g., the primary database), while others are optional (e.g., an analytics service) or redundant (e.g., one of many cache nodes).
The `control` package introduces the concept of a `Mode`. A `Mode` is attached to each monitored component or group of components and dictates how that component's status (OK, WARN, KO) aggregates into the global status.
Control Modes & Data Flow ¶
The following modes are available, ordered by their impact logic:
1. Ignore
- Description: The component is monitored, but its status is completely disregarded for the global health.
- Use Case: Experimental features, non-critical background jobs, or debugging.
- Data Flow: [Component Status: KO/WARN/OK] --(Ignore)--> [Global Impact: None (Always OK)]
2. Should
- Description: The component is important but not critical. Failure results in a degraded state (WARN) rather than a system outage.
- Use Case: Caching layers, secondary features, metrics exporters.
- Data Flow: [Component Status: OK] --(Should)--> [Global Impact: OK] [Component Status: WARN] --(Should)--> [Global Impact: WARN] [Component Status: KO] --(Should)--> [Global Impact: WARN]
3. Must
- Description: The component is critical. Its failure directly causes a global system failure.
- Use Case: Primary database, authentication service, main API listener.
- Data Flow: [Component Status: OK] --(Must)--> [Global Impact: OK] [Component Status: WARN] --(Must)--> [Global Impact: WARN] [Component Status: KO] --(Must)--> [Global Impact: KO]
4. AnyOf
- Description: Used for a group of redundant components. The group is considered healthy if *at least one* component is healthy.
- Use Case: HA clusters, multiple upstream providers, load-balanced read replicas.
- Data Flow: [Comp1: KO, Comp2: OK] --(AnyOf)--> [Global Impact: OK] [Comp1: KO, Comp2: KO] --(AnyOf)--> [Global Impact: KO]
5. Quorum
- Description: Used for consensus-based groups. The group is considered healthy if a *majority* (>50%) of components are healthy.
- Use Case: Raft/Paxos clusters, distributed storage nodes.
- Data Flow: [Comp1: OK, Comp2: OK, Comp3: KO] (2/3 OK) --(Quorum)--> [Global Impact: OK] [Comp1: OK, Comp2: KO, Comp3: KO] (1/3 OK) --(Quorum)--> [Global Impact: KO]
Interoperability ¶
The `Mode` type implements standard interfaces for serialization and formatted output:
- `fmt.Stringer`: Returns PascalCase strings ("Must", "Should").
- `json.Marshaler` / `json.Unmarshaler`: JSON support.
- `yaml.Marshaler` / `yaml.Unmarshaler`: YAML support.
- `toml.Marshaler` / `toml.Unmarshaler`: TOML support.
- `cbor.Marshaler` / `cbor.Unmarshaler`: CBOR support.
- `mapstructure` hook: Integration with Viper for configuration loading.
Numeric Representation ¶
Modes can also be represented as numeric values, useful for compact storage or database columns:
- 0: Ignore
- 1: Should
- 2: Must
- 3: AnyOf
- 4: Quorum
Package control provides the validation modes that govern how component health affects the overall application status. These modes are used to define flexible and robust health check policies.
The package defines a set of standard control modes (Ignore, Should, Must, AnyOf, Quorum) and provides utilities for parsing and serializing them.
Index ¶
- func ViperDecoderHook() libmap.DecodeHookFuncType
- type Mode
- func Parse(s string) Mode
- func ParseBytes(p []byte) Mode
- func ParseInt8(p int8) Mode
- func ParseInt16(p int16) Mode
- func ParseInt32(p int32) Mode
- func ParseInt64(p int64) Mode
- func ParseUint8(p uint8) Mode
- func ParseUint16(p uint16) Mode
- func ParseUint32(p uint32) Mode
- func ParseUint64(p uint64) Mode
- func (c Mode) Code() string
- func (c Mode) Int8() int8
- func (c Mode) Int16() int16
- func (c Mode) Int32() int32
- func (c Mode) Int64() int64
- func (c Mode) MarshalCBOR() ([]byte, error)
- func (c Mode) MarshalJSON() ([]byte, error)
- func (c Mode) MarshalTOML() ([]byte, error)
- func (c Mode) MarshalText() ([]byte, error)
- func (c Mode) MarshalYAML() (interface{}, error)
- func (c Mode) String() string
- func (c Mode) Uint8() uint8
- func (c Mode) Uint16() uint16
- func (c Mode) Uint32() uint32
- func (c Mode) Uint64() uint64
- func (c *Mode) UnmarshalCBOR(bytes []byte) error
- func (c *Mode) UnmarshalJSON(bytes []byte) error
- func (c *Mode) UnmarshalTOML(i interface{}) error
- func (c *Mode) UnmarshalText(bytes []byte) error
- func (c *Mode) UnmarshalYAML(value *yaml.Node) error
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ViperDecoderHook ¶
func ViperDecoderHook() libmap.DecodeHookFuncType
ViperDecoderHook returns a `mapstructure.DecodeHookFunc` that can be used with Viper to automatically decode string values from configuration files (e.g., YAML, JSON, TOML) into `Mode` types during the unmarshaling process.
This hook is essential for a seamless configuration experience, as it allows developers to use human-readable strings (like "must" or "Should") in their config files, which are then automatically converted to the correct `Mode` type. The decoding is case-insensitive.
Example usage with Viper:
import (
"github.com/spf13/viper"
"github.com/mitchellh/mapstructure"
"github.com/nabbar/golib/status/control"
)
type MyConfig struct {
ValidationMode control.Mode `mapstructure:"validation_mode"`
}
v := viper.New()
// ... load config from file or other source ...
var cfg MyConfig
// The hook is passed to Viper's Unmarshal function.
err := v.Unmarshal(&cfg, viper.DecodeHook(control.ViperDecoderHook()))
In a YAML file:
validation_mode: "Must"
The string "Must" will be correctly decoded into `control.Must`.
Types ¶
type Mode ¶
type Mode uint8
Mode represents a control mode for mandatory component validation. It determines the strictness of the health check for a component or a group of components. It is implemented as a `uint8` for efficiency.
const ( // Ignore indicates that no validation is required for the component. // This is the default mode (zero value). Components in this mode are // monitored, but their status (even if KO) does not affect the overall // application status. Ignore Mode = iota // Should indicates that the component is important but not critical. If the // component is unhealthy (KO or WARN), it will generate a warning but will // not cause a critical failure (KO) of the overall application. This is // useful for optional features or degraded modes. Should // Must indicates that the component is critical and must be healthy. If the // component is unhealthy (KO), the overall application status will be marked // as failed (KO). If it is WARN, the overall status will be WARN. Must // AnyOf is used for redundant groups of components (e.g., a cluster of // read-only databases). It requires at least one component in the group to // be healthy (OK or WARN). If all components are KO, the group is KO. AnyOf // Quorum is used for distributed systems requiring consensus. It requires a // majority (>50%) of the components in the group to be healthy (OK or WARN). // If 50% or fewer are healthy, the group is considered KO. Quorum )
func Parse ¶
Parse converts a string to a `Mode`. The parsing is case-insensitive. If the string does not match any known mode, `Ignore` is returned as the default.
Supported values:
- "ignore" -> Ignore
- "should" -> Should
- "must" -> Must
- "anyof" -> AnyOf
- "quorum" -> Quorum
func ParseBytes ¶
ParseBytes is a convenience wrapper for `Parse` that accepts a byte slice. It converts the byte slice to a string and calls `Parse`.
func ParseInt8 ¶ added in v1.21.0
ParseInt8 converts an `int8` to a `Mode`. It is a convenience wrapper around `ParseInt64`.
func ParseInt16 ¶ added in v1.21.0
ParseInt16 converts an `int16` to a `Mode`. It is a convenience wrapper around `ParseInt64`.
func ParseInt32 ¶ added in v1.21.0
ParseInt32 converts an `int32` to a `Mode`. It is a convenience wrapper around `ParseInt64`.
func ParseInt64 ¶
ParseInt64 converts an `int64` to a `Mode`. Negative values are treated as 0 (`Ignore`). This is useful for signed numeric configurations.
Mapping:
- < 0 -> Ignore
- 0 -> Ignore
- 1 -> Should
- 2 -> Must
- 3 -> AnyOf
- 4 -> Quorum
func ParseUint8 ¶ added in v1.21.0
ParseUint8 converts a `uint8` to a `Mode`. It is a convenience wrapper around `ParseUint64`.
func ParseUint16 ¶ added in v1.21.0
ParseUint16 converts a `uint16` to a `Mode`. It is a convenience wrapper around `ParseUint64`.
func ParseUint32 ¶ added in v1.21.0
ParseUint32 converts a `uint32` to a `Mode`. It is a convenience wrapper around `ParseUint64`.
func ParseUint64 ¶ added in v1.19.0
ParseUint64 converts a `uint64` to a `Mode`. This is useful when reading mode values from numeric configurations or databases. If the value is out of the valid range for `Mode`, `Ignore` is returned.
Mapping:
- 0 -> Ignore
- 1 -> Should
- 2 -> Must
- 3 -> AnyOf
- 4 -> Quorum
func (Mode) Code ¶
Code returns the lowercase string representation of the `Mode`. This is primarily used for case-insensitive comparisons and for storing the mode in configuration files in a consistent format.
Example:
fmt.Println(control.Must.Code()) // Output: must
func (Mode) Int8 ¶ added in v1.21.0
Int8 returns the `Mode` value as an `int8`. Currently, this implementation returns 0 (Ignore) for safety or compatibility reasons. Developers should check if this specific behavior meets their needs.
func (Mode) Int16 ¶ added in v1.21.0
Int16 returns the `Mode` value as an `int16`. Currently, this implementation returns 0 (Ignore).
func (Mode) Int32 ¶ added in v1.21.0
Int32 returns the `Mode` value as an `int32`. Currently, this implementation returns 0 (Ignore).
func (Mode) Int64 ¶ added in v1.21.0
Int64 returns the `Mode` value as an `int64`. Unlike smaller signed integer conversions in this package, this method returns the actual underlying value of the `Mode` cast to `int64`.
func (Mode) MarshalCBOR ¶
MarshalCBOR implements the `cbor.Marshaler` interface. It serializes the `Mode` into a CBOR (Concise Binary Object Representation) string. CBOR is a binary data serialization format loosely based on JSON.
func (Mode) MarshalJSON ¶
MarshalJSON implements the `json.Marshaler` interface. It serializes the `Mode` into a JSON string using its PascalCase representation (e.g., "Must", "Should").
Example:
data, _ := json.Marshal(control.Must) // data is []byte(`"Must"`)
func (Mode) MarshalTOML ¶
MarshalTOML implements the `toml.Marshaler` interface. It serializes the `Mode` into a TOML string. It reuses `MarshalJSON` internally to ensure consistency.
func (Mode) MarshalText ¶
MarshalText implements the `encoding.TextMarshaler` interface. It serializes the `Mode` into a plain text byte slice using its PascalCase representation. This is useful for generic text-based protocols or logging.
func (Mode) MarshalYAML ¶
MarshalYAML implements the `yaml.Marshaler` interface. It serializes the `Mode` into a YAML string using its PascalCase representation.
func (Mode) String ¶
String returns the PascalCase string representation of the `Mode`. The `Ignore` mode returns an empty string, which is its defined string value.
This method implements the `fmt.Stringer` interface, allowing `Mode` values to be printed directly and clearly in logs and other outputs.
Example:
fmt.Println(control.Must) // Output: Must
func (Mode) Uint8 ¶ added in v1.21.0
Uint8 returns the `Mode` value as a `uint8`. This is the underlying type of `Mode` and allows for easy conversion when interfacing with libraries that expect standard integer types.
func (Mode) Uint16 ¶ added in v1.21.0
Uint16 returns the `Mode` value as a `uint16`. Useful for compatibility with APIs expecting 16-bit unsigned integers.
func (Mode) Uint32 ¶ added in v1.21.0
Uint32 returns the `Mode` value as a `uint32`. Useful for compatibility with APIs expecting 32-bit unsigned integers.
func (Mode) Uint64 ¶ added in v1.21.0
Uint64 returns the `Mode` value as a `uint64`. Useful for compatibility with APIs expecting 64-bit unsigned integers.
func (*Mode) UnmarshalCBOR ¶
UnmarshalCBOR implements the `cbor.Unmarshaler` interface. It deserializes a CBOR-encoded byte slice into a `Mode`. The parsing is case-insensitive.
func (*Mode) UnmarshalJSON ¶
UnmarshalJSON implements the `json.Unmarshaler` interface. It deserializes a JSON string into a `Mode`. The parsing is case-insensitive. If the JSON value is not a valid string or does not match a known mode, it defaults to `Ignore`.
Example:
var m control.Mode json.Unmarshal([]byte(`"must"`), &m) // m is control.Must
func (*Mode) UnmarshalTOML ¶
UnmarshalTOML implements the `toml.Unmarshaler` interface. It deserializes a TOML value into a `Mode`. It supports both byte slices and strings as input. The parsing is case-insensitive.
If the input is not a byte slice or a string, it returns an error indicating an invalid format.
func (*Mode) UnmarshalText ¶
UnmarshalText implements the `encoding.TextUnmarshaler` interface. It deserializes a plain text byte slice into a `Mode`. The parsing is case-insensitive.