diff --git a/lib/gat/gatcaddyfile/critic.go b/lib/gat/gatcaddyfile/critic.go index b77589a869cc29ffc9702d08baae3220787248d4..b4fa1c4a470077ea690c8b6b644daf90ce5e0684 100644 --- a/lib/gat/gatcaddyfile/critic.go +++ b/lib/gat/gatcaddyfile/critic.go @@ -2,8 +2,6 @@ package gatcaddyfile import ( "gfx.cafe/gfx/pggat/lib/gat/handlers/pool/critics/replication" - "time" - "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" @@ -14,49 +12,62 @@ import ( func init() { // Register a directive for the latency critic which measures query response // time as the determining factor for load balancing between replicas - RegisterDirective(Critic, "latency", func(d *caddyfile.Dispenser, warnings *[]caddyconfig.Warning) (caddy.Module, error) { - module := &latency.Critic{ - Validity: caddy.Duration(5 * time.Minute), - } - - // parse nested format - if d.NextBlock(d.Nesting()) { - return parseLatency(module, d, warnings) - } - - // parse legacy format - if !d.NextArg() { - return nil, d.ArgErr() - } - - threshold, err := caddy.ParseDuration(d.Val()) - if err != nil { - return nil, d.WrapErr(err) - } - module.Threshold = caddy.Duration(threshold) - - if d.NextArg() { - // optional validity - var validity time.Duration - validity, err = caddy.ParseDuration(d.Val()) - if err != nil { - return nil, d.WrapErr(err) - } - module.Validity = caddy.Duration(validity) - } + // + // Config Format + // + // * All fields are optional and will fall back to a suitable default + // * Duration values use caddy.Duration syntax + // + // penalize query_latency [query_threshold duration [validity duration]] + // + // -or- + // + // penalize query_latency { + // [query_threshold] {duration} + // [validity] {duration} + // } + // + // pool basic session { + // penalize query_latency # use the defaults + // penalize query_latency 500ms # set query threshold w/ default validity + // penalize query_latency 500ms 3m # set query threshold and validity + // penalize query_latency { + // query_threshold 300ms + // validity 5m + // } + // } + RegisterDirective(Critic, "query_latency", func(d *caddyfile.Dispenser, warnings *[]caddyconfig.Warning) (caddy.Module, error) { + return parseQueryCritic(d, warnings) + }) - return module, nil + // legacy directive for query_latency + RegisterDirective(Critic, "latency", func(d *caddyfile.Dispenser, warnings *[]caddyconfig.Warning) (caddy.Module, error) { + return parseQueryCritic(d, warnings) }) // Register a directive handler for the replication critic which uses - // replication lag as a determining factor for load balancing between replicas - RegisterDirective(Critic, "replication", func(d *caddyfile.Dispenser, warnings *[]caddyconfig.Warning) (caddy.Module, error) { - module := &replication.Critic{ - Validity: caddy.Duration(2 * time.Minute), - } + // replication lag as a determining factor for load balancing between + // replicas + // + // Config format + // + // * All fields are optional and will fall back to a suitable default + // * Duration values use caddy.Duration syntax + // + // pool basic session { + // penalize replication_latency # valid declaration. Use default values + // + // penalize replication_latency { + // replication_threshold 3s + // query_threshold 300ms + // validity 5m + // } + // } + RegisterDirective(Critic, "replication_latency", func(d *caddyfile.Dispenser, warnings *[]caddyconfig.Warning) (caddy.Module, error) { + module := replication.NewCritic() if !d.NextBlock(d.Nesting()) { - return nil, d.ArgErr() + return module, nil } for { @@ -71,23 +82,34 @@ func init() { return nil, d.ArgErr() } - validity, err := time.ParseDuration(d.Val()) + validity, err := caddy.ParseDuration(d.Val()) if err != nil { return nil, d.WrapErr(err) } module.Validity = caddy.Duration(validity) - case "threshold": + case "replication_threshold": if !d.NextArg() { return nil, d.ArgErr() } - threshold, err := time.ParseDuration(d.Val()) + threshold, err := caddy.ParseDuration(d.Val()) if err != nil { return nil, d.WrapErr(err) } - module.Threshold = caddy.Duration(threshold) + module.ReplicationThreshold = caddy.Duration(threshold) + case "query_threshold": + if !d.NextArg() { + return nil, d.ArgErr() + } + + threshold, err := caddy.ParseDuration(d.Val()) + if err != nil { + return nil, d.WrapErr(err) + } + + module.QueryThreshold = caddy.Duration(threshold) default: return nil, d.ArgErr() } @@ -101,7 +123,39 @@ func init() { }) } -func parseLatency(critic *latency.Critic, d *caddyfile.Dispenser, warnings *[]caddyconfig.Warning) (caddy.Module, error) { +func parseQueryCritic(d *caddyfile.Dispenser, warnings *[]caddyconfig.Warning) (caddy.Module, error) { + module := latency.NewCritic() + + // parse block format + if d.NextBlock(d.Nesting()) { + return parseLatency(module, d, warnings) + } + + // use the defaults + if !d.NextArg() { + return module, nil + } + + // parse legacy format + dur, err := caddy.ParseDuration(d.Val()) + if err != nil { + return nil, d.WrapErr(err) + } + module.QueryThreshold = caddy.Duration(dur) + + if d.NextArg() { + // optional validity + dur, err = caddy.ParseDuration(d.Val()) + if err != nil { + return nil, d.WrapErr(err) + } + module.Validity = caddy.Duration(dur) + } + + return module, nil +} + +func parseLatency(critic *latency.Critic, d *caddyfile.Dispenser, _ *[]caddyconfig.Warning) (caddy.Module, error) { for { if d.Val() == "}" { break @@ -114,23 +168,23 @@ func parseLatency(critic *latency.Critic, d *caddyfile.Dispenser, warnings *[]ca return nil, d.ArgErr() } - validity, err := time.ParseDuration(d.Val()) + validity, err := caddy.ParseDuration(d.Val()) if err != nil { return nil, d.WrapErr(err) } critic.Validity = caddy.Duration(validity) - case "threshold": + case "query_threshold": if !d.NextArg() { return nil, d.ArgErr() } - threshold, err := time.ParseDuration(d.Val()) + threshold, err := caddy.ParseDuration(d.Val()) if err != nil { return nil, d.WrapErr(err) } - critic.Threshold = caddy.Duration(threshold) + critic.QueryThreshold = caddy.Duration(threshold) default: return nil, d.ArgErr() }