Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
208 changes: 0 additions & 208 deletions cbreaker/predicates.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package cbreaker
import (
"fmt"

"github.com/vulcand/oxy/v2/internal/holsterv4/clock"
"github.com/vulcand/predicate"
)

Expand Down Expand Up @@ -44,210 +43,3 @@ func parseExpression(in string) (hpredicate, error) {

return pr, nil
}

type toInt func(c *CircuitBreaker) int

type toFloat64 func(c *CircuitBreaker) float64

func latencyAtQuantile(quantile float64) toInt {
return func(c *CircuitBreaker) int {
h, err := c.metrics.LatencyHistogram()
if err != nil {
c.log.Error("Failed to get latency histogram, for %v error: %v", c, err)
return 0
}

return int(h.LatencyAtQuantile(quantile) / clock.Millisecond)
}
}

func networkErrorRatio() toFloat64 {
return func(c *CircuitBreaker) float64 {
return c.metrics.NetworkErrorRatio()
}
}

func responseCodeRatio(startA, endA, startB, endB int) toFloat64 {
return func(c *CircuitBreaker) float64 {
return c.metrics.ResponseCodeRatio(startA, endA, startB, endB)
}
}

// or returns predicate by joining the passed predicates with logical 'or'.
func or(fns ...hpredicate) hpredicate {
return func(c *CircuitBreaker) bool {
for _, fn := range fns {
if fn(c) {
return true
}
}

return false
}
}

// and returns predicate by joining the passed predicates with logical 'and'.
func and(fns ...hpredicate) hpredicate {
return func(c *CircuitBreaker) bool {
for _, fn := range fns {
if !fn(c) {
return false
}
}

return true
}
}

// not creates negation of the passed predicate.
func not(p hpredicate) hpredicate {
return func(c *CircuitBreaker) bool {
return !p(c)
}
}

// eq returns predicate that tests for equality of the value of the mapper and the constant.
func eq(m any, value any) (hpredicate, error) {
switch mapper := m.(type) {
case toInt:
return intEQ(mapper, value)
case toFloat64:
return float64EQ(mapper, value)
}

return nil, fmt.Errorf("eq: unsupported argument: %T", m)
}

// neq returns predicate that tests for inequality of the value of the mapper and the constant.
func neq(m any, value any) (hpredicate, error) {
p, err := eq(m, value)
if err != nil {
return nil, err
}

return not(p), nil
}

// lt returns predicate that tests that value of the mapper function is less than the constant.
func lt(m any, value any) (hpredicate, error) {
switch mapper := m.(type) {
case toInt:
return intLT(mapper, value)
case toFloat64:
return float64LT(mapper, value)
}

return nil, fmt.Errorf("lt: unsupported argument: %T", m)
}

// le returns predicate that tests that value of the mapper function is less or equal than the constant.
func le(m any, value any) (hpredicate, error) {
l, err := lt(m, value)
if err != nil {
return nil, err
}

e, err := eq(m, value)
if err != nil {
return nil, err
}

return func(c *CircuitBreaker) bool {
return l(c) || e(c)
}, nil
}

// gt returns predicate that tests that value of the mapper function is greater than the constant.
func gt(m any, value any) (hpredicate, error) {
switch mapper := m.(type) {
case toInt:
return intGT(mapper, value)
case toFloat64:
return float64GT(mapper, value)
}

return nil, fmt.Errorf("gt: unsupported argument: %T", m)
}

// ge returns predicate that tests that value of the mapper function is less or equal than the constant.
func ge(m any, value any) (hpredicate, error) {
g, err := gt(m, value)
if err != nil {
return nil, err
}

e, err := eq(m, value)
if err != nil {
return nil, err
}

return func(c *CircuitBreaker) bool {
return g(c) || e(c)
}, nil
}

func intEQ(m toInt, val any) (hpredicate, error) {
value, ok := val.(int)
if !ok {
return nil, fmt.Errorf("expected int, got %T", val)
}

return func(c *CircuitBreaker) bool {
return m(c) == value
}, nil
}

func float64EQ(m toFloat64, val any) (hpredicate, error) {
value, ok := val.(float64)
if !ok {
return nil, fmt.Errorf("expected float64, got %T", val)
}

return func(c *CircuitBreaker) bool {
return m(c) == value
}, nil
}

func intLT(m toInt, val any) (hpredicate, error) {
value, ok := val.(int)
if !ok {
return nil, fmt.Errorf("expected int, got %T", val)
}

return func(c *CircuitBreaker) bool {
return m(c) < value
}, nil
}

func intGT(m toInt, val any) (hpredicate, error) {
value, ok := val.(int)
if !ok {
return nil, fmt.Errorf("expected int, got %T", val)
}

return func(c *CircuitBreaker) bool {
return m(c) > value
}, nil
}

func float64LT(m toFloat64, val any) (hpredicate, error) {
value, ok := val.(float64)
if !ok {
return nil, fmt.Errorf("expected int, got %T", val)
}

return func(c *CircuitBreaker) bool {
return m(c) < value
}, nil
}

func float64GT(m toFloat64, val any) (hpredicate, error) {
value, ok := val.(float64)
if !ok {
return nil, fmt.Errorf("expected int, got %T", val)
}

return func(c *CircuitBreaker) bool {
return m(c) > value
}, nil
}
31 changes: 31 additions & 0 deletions cbreaker/predicates_functions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package cbreaker

import (
"github.com/vulcand/oxy/v2/internal/holsterv4/clock"
)

type toType[T int | float64] func(c *CircuitBreaker) T

func latencyAtQuantile(quantile float64) toType[int] {
return func(c *CircuitBreaker) int {
h, err := c.metrics.LatencyHistogram()
if err != nil {
c.log.Error("Failed to get latency histogram, for %v error: %v", c, err)
return 0
}

return int(h.LatencyAtQuantile(quantile) / clock.Millisecond)
}
}

func networkErrorRatio() toType[float64] {
return func(c *CircuitBreaker) float64 {
return c.metrics.NetworkErrorRatio()
}
}

func responseCodeRatio(startA, endA, startB, endB int) toType[float64] {
return func(c *CircuitBreaker) float64 {
return c.metrics.ResponseCodeRatio(startA, endA, startB, endB)
}
}
Loading