Documentation
¶
Index ¶
- Variables
- func DefaultErrorClassifier(err error) (bool, bool)
- func LabelsFromContext(ctx context.Context, rules CtxValueRules) []string
- func LabelsFromGRPC(ctx context.Context, rules GRPCLabelRules) []string
- func LabelsFromHTTP(r *http.Request, rules HTTPLabelRules) []string
- func LabelsFromJWT(claims map[string]any, rules JWTLabelRules) []string
- func UnifiedDiff(a, b string) string
- func WithHTTPRequest(ctx context.Context, r *http.Request) context.Context
- func WithJWTClaims(ctx context.Context, claims map[string]any) context.Context
- func WithTenantID(ctx context.Context, tenantID string) context.Context
- type ApplyOptions
- type AutoLabelResolverOptions
- type Connector
- type CtxValueRules
- type DBConfig
- type DiffReport
- type DisplayMeta
- type DisplayOptions
- type EqExpr
- type ErrorClassifier
- type FailoverPolicy
- type FieldDef
- type FieldDiff
- type FieldMeta
- type FileProvider
- type GRPCLabelRules
- type HTTPLabelRules
- type HasExpr
- type HotReloadRegistry
- func (r *HotReloadRegistry) Default() (TargetConn, bool)
- func (r *HotReloadRegistry) DefaultKey() string
- func (r *HotReloadRegistry) FindAllByLabels(labels ...string) []string
- func (r *HotReloadRegistry) FindAnyByLabels(labels ...string) []string
- func (r *HotReloadRegistry) FindByLabel(label string) []string
- func (r *HotReloadRegistry) FindByQuery(q Query) []string
- func (r *HotReloadRegistry) ForEachByQuery(q Query, fn func(key string, t TargetConn) error) error
- func (r *HotReloadRegistry) Get(key string) (TargetConn, bool)
- func (r *HotReloadRegistry) Keys() []string
- func (r *HotReloadRegistry) Register(ctx context.Context, key string, cfg TargetConfig, mk Connector) (err error)
- func (r *HotReloadRegistry) ReplaceAll(ctx context.Context, cfgs map[string]TargetConfig, mk Connector, ...) (err error)
- func (r *HotReloadRegistry) SetDefault(key string)
- func (r *HotReloadRegistry) Snapshot() map[string]TargetConn
- func (r *HotReloadRegistry) Unregister(key string) (err error)
- func (r *HotReloadRegistry) Update(ctx context.Context, key string, cfg TargetConfig, mk Connector) (err error)
- type InExpr
- type JWTLabelRules
- type LabelExpr
- type MetaDBProvider
- type NotExpr
- type Query
- type ReadSource
- type ReconcileReport
- type ScanResult
- type SelectionHint
- type SelectionStrategy
- type Service
- type ServiceConfig
- type Snapshot
- type SnapshotClient
- type TargetConfig
- type TargetConn
- type TargetDecision
- type TargetProvider
- type TargetRegistry
- type TargetResolver
- type TargetResolverV2
- type TargetWatcher
- type TenantIDKey
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrNoTarget = errors.New("no target database resolved")
var (
ErrValidatorNotFound = errors.New("validator not found")
)
ErrValidatorNotFound is returned when a validator plugin cannot be found.
Functions ¶
func DefaultErrorClassifier ¶
DefaultErrorClassifier provides baseline classification for common errors.
func LabelsFromContext ¶
func LabelsFromContext(ctx context.Context, rules CtxValueRules) []string
LabelsFromContext extracts labels from context values according to rules.
func LabelsFromGRPC ¶
func LabelsFromGRPC(ctx context.Context, rules GRPCLabelRules) []string
LabelsFromGRPC extracts labels from gRPC metadata within a context.
func LabelsFromHTTP ¶
func LabelsFromHTTP(r *http.Request, rules HTTPLabelRules) []string
LabelsFromHTTP extracts labels from an *http.Request based on rules.
func LabelsFromJWT ¶
func LabelsFromJWT(claims map[string]any, rules JWTLabelRules) []string
LabelsFromJWT extracts labels from a claims map based on rules.
func UnifiedDiff ¶
UnifiedDiff returns a unified diff string of two inputs.
func WithHTTPRequest ¶
WithHTTPRequest stores *http.Request in context for AutoLabelResolver.
func WithJWTClaims ¶
WithJWTClaims stores JWT claims in context for AutoLabelResolver.
Types ¶
type ApplyOptions ¶
type AutoLabelResolverOptions ¶
type AutoLabelResolverOptions struct {
HTTP *HTTPLabelRules
GRPC *GRPCLabelRules
JWT *JWTLabelRules
Ctx *CtxValueRules
Hint *SelectionHint
}
AutoLabelResolverOptions configures AutoLabelResolver sources.
type CtxValueRules ¶
type CtxValueRules struct {
KeyMap map[any]string // context key -> label name
Fixed map[string]string
}
CtxValueRules configures label extraction from context values.
type DBConfig ¶
type DBConfig struct {
Driver string // mysql|postgres|mongo
DSN string
Schema string
TablePrefix string
}
DBConfig specifies database connection parameters.
type DiffReport ¶
type DiffReport struct {
// Added is the number of newly created fields.
Added int
// Deleted is the number of removed fields.
Deleted int
// Updated is the number of modified fields.
Updated int
}
func CalculateDiff ¶
func CalculateDiff(changes []registry.Change) DiffReport
CalculateDiff returns counts of added, deleted and updated changes.
type DisplayMeta ¶
type DisplayMeta = registry.DisplayMeta
type DisplayOptions ¶
type DisplayOptions = registry.DisplayOption
type ErrorClassifier ¶
ErrorClassifier determines whether an error is transient and retryable.
type FailoverPolicy ¶
type FailoverPolicy struct {
Enabled bool
MaxAttempts int
BaseBackoff time.Duration
MaxBackoff time.Duration
JitterRatio float64
OpenAfterFailures int
OpenDuration time.Duration
HalfOpenProbe int
PreferOnFail *SelectionHint
AllowWriteRetry bool
}
FailoverPolicy controls retry and circuit breaker behavior.
type FileProvider ¶
type FileProvider struct {
// contains filtered or unexported fields
}
FileProvider reads target configurations from a JSON file.
func NewFileProvider ¶
func NewFileProvider(path string) *FileProvider
NewFileProvider creates a provider for the given file path.
func (*FileProvider) Fetch ¶
func (p *FileProvider) Fetch(ctx context.Context) (map[string]TargetConfig, string, string, error)
Fetch loads target configs from the file, expanding environment variables in DSNs.
type GRPCLabelRules ¶
type GRPCLabelRules struct {
MetaMap map[string]string // metadata key -> label name
Fixed map[string]string
}
GRPCLabelRules configures label extraction from gRPC metadata.
type HTTPLabelRules ¶
type HTTPLabelRules struct {
HeaderMap map[string]string // header name -> label name
Fixed map[string]string
}
HTTPLabelRules configures label extraction from HTTP headers.
type HotReloadRegistry ¶
type HotReloadRegistry struct {
// contains filtered or unexported fields
}
HotReloadRegistry is an RCU-style implementation of TargetRegistry.
func NewHotReloadRegistry ¶
func NewHotReloadRegistry(defaultConn *TargetConn) *HotReloadRegistry
NewHotReloadRegistry creates a registry initialized with the default connection.
func (*HotReloadRegistry) Default ¶
func (r *HotReloadRegistry) Default() (TargetConn, bool)
Default returns the default target connection.
func (*HotReloadRegistry) DefaultKey ¶
func (r *HotReloadRegistry) DefaultKey() string
DefaultKey returns the current default key.
func (*HotReloadRegistry) FindAllByLabels ¶
func (r *HotReloadRegistry) FindAllByLabels(labels ...string) []string
FindAllByLabels returns keys of targets containing all the specified labels.
func (*HotReloadRegistry) FindAnyByLabels ¶
func (r *HotReloadRegistry) FindAnyByLabels(labels ...string) []string
FindAnyByLabels returns keys of targets containing any of the specified labels.
func (*HotReloadRegistry) FindByLabel ¶
func (r *HotReloadRegistry) FindByLabel(label string) []string
FindByLabel returns keys of targets having the given label.
func (*HotReloadRegistry) FindByQuery ¶
func (r *HotReloadRegistry) FindByQuery(q Query) []string
FindByQuery returns keys of targets matching q.
func (*HotReloadRegistry) ForEachByQuery ¶
func (r *HotReloadRegistry) ForEachByQuery(q Query, fn func(key string, t TargetConn) error) error
ForEachByQuery executes fn for each target matching q.
func (*HotReloadRegistry) Get ¶
func (r *HotReloadRegistry) Get(key string) (TargetConn, bool)
Get retrieves a target by key.
func (*HotReloadRegistry) Keys ¶
func (r *HotReloadRegistry) Keys() []string
Keys returns a copy of available keys.
func (*HotReloadRegistry) Register ¶
func (r *HotReloadRegistry) Register(ctx context.Context, key string, cfg TargetConfig, mk Connector) (err error)
Register adds a new target.
func (*HotReloadRegistry) ReplaceAll ¶
func (r *HotReloadRegistry) ReplaceAll(ctx context.Context, cfgs map[string]TargetConfig, mk Connector, defaultKey string) (err error)
ReplaceAll swaps the registry contents atomically.
func (*HotReloadRegistry) SetDefault ¶
func (r *HotReloadRegistry) SetDefault(key string)
SetDefault marks the given key as default if it exists.
func (*HotReloadRegistry) Snapshot ¶
func (r *HotReloadRegistry) Snapshot() map[string]TargetConn
Snapshot returns a copy of the current targets.
func (*HotReloadRegistry) Unregister ¶
func (r *HotReloadRegistry) Unregister(key string) (err error)
Unregister removes a target. The connection is closed after publishing the snapshot.
func (*HotReloadRegistry) Update ¶
func (r *HotReloadRegistry) Update(ctx context.Context, key string, cfg TargetConfig, mk Connector) (err error)
Update replaces an existing target's connection.
type JWTLabelRules ¶
type JWTLabelRules struct {
ClaimMap map[string]string // claim name -> label name
Fixed map[string]string
}
JWTLabelRules configures label extraction from JWT claims.
type MetaDBProvider ¶
type MetaDBProvider struct {
// contains filtered or unexported fields
}
MetaDBProvider reads target configuration from a MetaStore.
func NewMetaDBProvider ¶
func NewMetaDBProvider(meta metapkg.MetaStore) *MetaDBProvider
NewMetaDBProvider creates a provider backed by MetaStore.
func (*MetaDBProvider) Fetch ¶
func (p *MetaDBProvider) Fetch(ctx context.Context) (map[string]TargetConfig, string, string, error)
Fetch retrieves target configurations from the meta store.
type Query ¶
func ParseQuery ¶
func QueryFromLabels ¶
QueryFromLabels builds a Query that ANDs all label strings. "k=v" becomes EqExpr and plain "k" becomes HasExpr.
type ReadSource ¶
type ReadSource int
ReadSource specifies the origin for reading custom field definitions.
const ( // ReadFromTarget reads metadata from the target database (default). ReadFromTarget ReadSource = iota // ReadFromMeta reads metadata from the MetaDB. ReadFromMeta // ReadAuto reads from target first then falls back to MetaDB on failure or empty result. ReadAuto )
type ReconcileReport ¶
type ReconcileReport struct {
MissingInTarget []FieldDef
MissingInMeta []FieldDef
Mismatched []FieldDiff
}
ReconcileReport summarizes differences between MetaDB and target custom field definitions. MissingInTarget lists fields defined in MetaDB but absent in target. MissingInMeta lists fields present in target but missing in MetaDB. Mismatched captures fields with conflicting attributes.
type ScanResult ¶
type ScanResult = schema.ScanResult
type SelectionHint ¶
type SelectionHint struct {
Strategy SelectionStrategy
PreferLabel string
HashSource string
}
SelectionHint provides optional parameters for selection strategies.
type SelectionStrategy ¶
type SelectionStrategy int
SelectionStrategy indicates how to choose a key from multiple matches.
const ( // SelectFirst picks the first key in sorted order. SelectFirst SelectionStrategy = iota // SelectPreferLabel prioritizes targets with a given label. SelectPreferLabel // SelectConsistentHash chooses a target based on a consistent hash of // a provided source string. SelectConsistentHash )
type Service ¶
type Service interface {
// Scan reads schema information from the database.
Scan(ctx context.Context, cfg DBConfig) ([]registry.FieldMeta, error)
// Export dumps registry metadata as YAML.
Export(ctx context.Context, cfg DBConfig) ([]byte, error)
// Apply updates the registry based on the provided YAML.
Apply(ctx context.Context, cfg DBConfig, yaml []byte, opts ApplyOptions) (DiffReport, error)
// MigrateRegistry upgrades or downgrades the registry schema.
MigrateRegistry(ctx context.Context, cfg DBConfig, target int) error
// RegistryVersion returns the current registry schema version.
RegistryVersion(ctx context.Context, cfg DBConfig) (int, error)
// ListCustomFields returns custom field metadata.
ListCustomFields(ctx context.Context, dbID int64, table string) ([]registry.FieldMeta, error)
// CreateCustomField inserts a new field into the registry.
CreateCustomField(ctx context.Context, fm registry.FieldMeta) error
// UpdateCustomField modifies an existing field.
UpdateCustomField(ctx context.Context, fm registry.FieldMeta) error
// DeleteCustomField removes a field from the registry.
DeleteCustomField(ctx context.Context, table, column string) error
// ReconcileCustomFields compares metadata between target and MetaDB and optionally repairs discrepancies.
ReconcileCustomFields(ctx context.Context, dbID int64, table string, repair bool) (*ReconcileReport, error)
// StartTargetWatcher periodically fetches target configurations from a provider.
StartTargetWatcher(ctx context.Context, p TargetProvider, interval time.Duration) (stop func())
}
Service exposes high level operations for custom field registry. Service provides database operations for custom field registry.
Example (MultiTarget) ¶
package main
import (
"context"
"database/sql"
"os"
"github.com/faciam-dev/gcfm/sdk"
)
func main() {
meta, _ := sql.Open("postgres", os.Getenv("META_DSN"))
dbA, _ := sql.Open("mysql", os.Getenv("TENANT_A_DSN"))
dbB, _ := sql.Open("mysql", os.Getenv("TENANT_B_DSN"))
svc := sdk.New(sdk.ServiceConfig{
DB: dbA,
Driver: "mysql",
MetaDB: meta,
MetaDriver: "postgres",
MetaSchema: "gcfm_meta",
Targets: []sdk.TargetConfig{
{Key: "tenant:A", DB: dbA, Driver: "mysql", Schema: ""},
{Key: "tenant:B", DB: dbB, Driver: "mysql", Schema: ""},
},
TargetResolver: sdk.TenantResolverFromPrefix("tenant:"),
})
ctx := sdk.WithTenantID(context.Background(), "A")
_, _ = svc.ListCustomFields(ctx, 1, "posts")
}
Example (Quickstart) ¶
package main
import (
"context"
"log"
"github.com/faciam-dev/gcfm/sdk"
)
func main() {
ctx := context.Background()
svc := sdk.New(sdk.ServiceConfig{})
cfg := sdk.DBConfig{
DSN: "mysql://user:pass@tcp(localhost:3306)/app",
Schema: "app",
}
yaml, err := svc.Export(ctx, cfg)
if err != nil {
log.Fatal(err)
}
if _, err := svc.Apply(ctx, cfg, yaml, sdk.ApplyOptions{DryRun: true}); err != nil {
log.Fatal(err)
}
if err := svc.MigrateRegistry(ctx, cfg, 0); err != nil {
log.Fatal(err)
}
}
Example (SeparateMetaDB) ¶
package main
import (
"database/sql"
"os"
"github.com/faciam-dev/gcfm/sdk"
)
func main() {
meta, _ := sql.Open("postgres", os.Getenv("META_DSN"))
target, _ := sql.Open("mysql", os.Getenv("TARGET_DSN"))
_ = sdk.New(sdk.ServiceConfig{
DB: target,
Driver: "mysql",
MetaDB: meta,
MetaDriver: "postgres",
MetaSchema: "gcfm_meta",
})
}
func New ¶
func New(cfg ServiceConfig) Service
New returns a Service initialized with the given configuration. Validator plugins under PluginDir are loaded automatically.
type ServiceConfig ¶
type ServiceConfig struct {
Logger *zap.SugaredLogger
PluginDir string
PluginPublicKey string
PluginEnabled *bool
Recorder *audit.Recorder
Notifier notifier.Broker
// Default connection for monitored databases. Kept for backward
// compatibility.
DB *sql.DB
Driver string
Schema string
// Optional separate connection for metadata storage. When omitted,
// the above DB/Driver/Schema values are used.
MetaDB *sql.DB
MetaDriver string
MetaSchema string
// Target databases for monitoring. If empty, the default DB/Driver/
// Schema fields represent the only target.
Targets []TargetConfig
// TargetResolver selects a target based on the request context. When
// nil, operations fall back to the default target.
TargetResolver TargetResolver
// TargetResolverV2 returns either a direct key or a query. When both
// V1 and V2 are provided, V2 takes precedence.
TargetResolverV2 TargetResolverV2
// DefaultStrategy determines how to choose among multiple candidates
// returned by a query. The zero value means SelectFirst.
DefaultStrategy SelectionStrategy
// DefaultPreferLabel is used when DefaultStrategy is SelectPreferLabel
// and no hint is supplied.
DefaultPreferLabel string
// Connector creates new DB connections. When nil, a default
// implementation based on sql.Open and PingContext is used.
Connector Connector
// Failover controls retry and circuit breaker behavior.
Failover FailoverPolicy
// ErrorClassifier distinguishes transient errors for retry decisions.
ErrorClassifier ErrorClassifier
// ReadSource selects where to read custom field metadata from.
ReadSource ReadSource
}
ServiceConfig holds optional configuration for Service.
DB, Driver and Schema specify the default connection to the monitored database. If the Meta* fields are left nil or empty, they inherit these default values.
type SnapshotClient ¶
type SnapshotClient interface {
List(ctx context.Context, tenant string) ([]Snapshot, error)
Create(ctx context.Context, tenant, bump, msg string) (Snapshot, error)
Apply(ctx context.Context, tenant, ver string) error
Diff(ctx context.Context, tenant, from, to string) (string, error)
}
SnapshotClient provides snapshot operations.
type TargetConfig ¶
type TargetConfig struct {
Key string // unique identifier like "tenant:foo" or "db:orders"
Driver string
Schema string
Labels []string // optional tags such as "tenant:foo" or "region:tokyo"
// Physical connection information (hot reload target).
DSN string
MaxOpenConns int
MaxIdleConns int
ConnMaxIdle time.Duration
ConnMaxLife time.Duration
// Backward compatibility: pre-established connection. Connections
// provided via DB are not subject to hot reload.
DB *sql.DB
}
TargetConfig defines an individual monitored database.
type TargetConn ¶
type TargetConn struct {
DB *sql.DB
Driver string
Schema string
Dialect ormdriver.Dialect
Labels map[string]struct{}
}
TargetConn represents a monitored database connection.
type TargetDecision ¶
type TargetDecision struct {
Key string
Query *Query
Hint *SelectionHint
}
TargetDecision represents a proposal for selecting a target. Either Key or Query (or both) may be specified.
type TargetProvider ¶
type TargetProvider interface {
Fetch(ctx context.Context) (cfgs map[string]TargetConfig, defaultKey string, version string, err error)
}
TargetProvider fetches target configurations from an external source.
type TargetRegistry ¶
type TargetRegistry interface {
Register(ctx context.Context, key string, cfg TargetConfig, mk Connector) error
Unregister(key string) error
Update(ctx context.Context, key string, cfg TargetConfig, mk Connector) error
ReplaceAll(ctx context.Context, cfgs map[string]TargetConfig, mk Connector, defaultKey string) error
Snapshot() map[string]TargetConn
Get(key string) (TargetConn, bool)
Default() (TargetConn, bool)
SetDefault(key string)
Keys() []string
FindByLabel(label string) []string
FindAllByLabels(labels ...string) []string
FindAnyByLabels(labels ...string) []string
FindByQuery(q Query) []string
ForEachByQuery(q Query, fn func(key string, t TargetConn) error) error
}
TargetRegistry manages monitored database connections.
type TargetResolver ¶
TargetResolver chooses a target key from the request context. It returns the key and true on success.
func TenantResolverFromPrefix ¶
func TenantResolverFromPrefix(prefix string) TargetResolver
TenantResolverFromPrefix returns a TargetResolver that looks up tenant ID with given prefix.
type TargetResolverV2 ¶
type TargetResolverV2 func(ctx context.Context) (TargetDecision, bool)
TargetResolverV2 returns a TargetDecision derived from the request context. It returns false when no decision could be made.
func AutoLabelResolver ¶
func AutoLabelResolver(opts AutoLabelResolverOptions) TargetResolverV2
AutoLabelResolver builds a TargetResolverV2 that aggregates labels from various sources and turns them into a Query.
type TargetWatcher ¶
type TargetWatcher struct {
// contains filtered or unexported fields
}
TargetWatcher periodically applies configuration updates from a provider.