diff --git a/filter/impl/hystrix_filter.go b/filter/impl/hystrix_filter.go new file mode 100644 index 0000000000000000000000000000000000000000..ca7d77c21e34b73d8750badca85aad394069feee --- /dev/null +++ b/filter/impl/hystrix_filter.go @@ -0,0 +1,133 @@ +package impl + +import ( + "fmt" + "github.com/afex/hystrix-go/hystrix" + "github.com/apache/dubbo-go/common/extension" + "github.com/apache/dubbo-go/common/logger" + "github.com/apache/dubbo-go/filter" + "github.com/apache/dubbo-go/protocol" + perrors "github.com/pkg/errors" + "gopkg.in/yaml.v2" + "io/ioutil" + "os" + "path" +) + + +const ( + HYSTRIX="hystrix" + TIMEOUT_KEY="timeout" + MAXCONCURRENTREQUESTS_KEY="maxconcurrentrequests" + SLEEPWINDOW_KEY="sleepwindow" + ERRORPERCENTTHRESHOLD_KEY="errorpercentthreshold" + CONF_HYSTRIXFILTER_FILE_PATH="CONF_HYSTRIXFILTER_FILE_PATH" +) + + +var ( + //Timeout + //MaxConcurrentRequests + //RequestVolumeThreshold + //SleepWindow + //ErrorPercentThreshold + isConfigLoaded = false + + // + methodLevelConfigMap = make(map[string]hystrix.CommandConfig) + serviceLevelConfigMap = make(map[string]hystrix.CommandConfig) + defaultConfig hystrix.CommandConfig + + +) + +func init(){ + extension.SetFilter(HYSTRIX,GetHystrixFilter) +} +type HystrixFilter struct { + +} + +func (hf *HystrixFilter) Invoke(invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result{ + + cmdName := fmt.Sprintf("%s&method=%s",invoker.GetUrl().Key(),invocation.MethodName()) + + _,ifNew,err := hystrix.GetCircuit(cmdName) + if err != nil{ + logger.Errorf("[Hystrix Filter]Errors occurred getting circuit for %s , will invoke without hystrix, error is: ",cmdName,err) + return invoker.Invoke(invocation) + } + + // Do the configuration if the circuit breaker is created for the first time + if ifNew { + hystrix.ConfigureCommand(cmdName,hystrix.CommandConfig{ + + }) + } + + logger.Infof("[Hystrix Filter]Using hystrix filter: %s",cmdName) + var result protocol.Result + _ = hystrix.Do(cmdName, func() error { + result = invoker.Invoke(invocation) + return nil + }, func(err error) error { + + //failure logic + result = &protocol.RPCResult{} + result.SetError(err) + return nil + //failure logic + + }) + return result +} + +func (hf *HystrixFilter) OnResponse(result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result{ + return result +} +func GetHystrixFilter() filter.Filter{ + //When first called, load the config in + if !isConfigLoaded{ + if err:=initHystrixConfig();err!=nil{ + logger.Warnf("[Hystrix Filter]Config load failed, error is: %v , will use default",err) + } + + isConfigLoaded=true + } + + + return &HystrixFilter{} +} + + + + + +type HystrixFilterConfig struct { + Configs map[string] hystrix.CommandConfig + Default string + Services map[string] ServiceHystrixConfig +} +type ServiceHystrixConfig struct{ + ServiceConfig string `yaml:"service_config,omitempty"` + Methods map[string]string +} +func initHystrixConfig() error{ + confHystrixFile := os.Getenv(CONF_HYSTRIXFILTER_FILE_PATH) + if confHystrixFile==""{ + return perrors.Errorf("hystrix filter config file is nil") + } + if path.Ext(confHystrixFile) != ".yml"{ + return perrors.Errorf("hystrix filter config file suffix must be .yml") + } + confStream, err := ioutil.ReadFile(confHystrixFile) + if err != nil { + return perrors.Errorf("ioutil.ReadFile(file:%s) = error:%v", confHystrixFile, perrors.WithStack(err)) + } + hystrixConfig:=&HystrixFilterConfig{} + if err = yaml.Unmarshal(confStream,hystrixConfig);err!=nil{ + return perrors.Errorf("yaml.Unmarshal() = error:%v", perrors.WithStack(err)) + } + return nil +} + diff --git a/go.mod b/go.mod index 8fd3c215fbb38b9c54a6570630f5ef32ad8f56c1..ac1f1206f380294d9fca3e7d53c4197bbb2a552c 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,14 @@ module github.com/apache/dubbo-go require ( + github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 github.com/dubbogo/getty v1.0.7 github.com/dubbogo/gost v1.0.0 github.com/dubbogo/hessian2 v1.1.2 github.com/magiconair/properties v1.8.1 github.com/pkg/errors v0.8.1 github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec + github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945 // indirect github.com/stretchr/testify v1.3.0 go.uber.org/atomic v1.4.0 go.uber.org/zap v1.10.0 diff --git a/go.sum b/go.sum index 859e9aab1c882f3864668b45c6ac47ce7f01b262..cb5840050dfd007c15b3493f2b973cd591bc72f7 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 h1:rFw4nCn9iMW+Vajsk51NtYIcwSTkXr+JGrMd36kTDJw= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -9,8 +11,12 @@ github.com/dubbogo/hessian2 v1.1.2 h1:SRkPzIwVv2D+ZUOCE2XuI5kANoL01ShhAheLcc3usJ github.com/dubbogo/hessian2 v1.1.2/go.mod h1:XFGDn4oSZX26zkcfhkM/fCJrOqwQJxk/xgWW1KMJBKM= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= @@ -19,6 +25,10 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec h1:6ncX5ko6B9LntYM0YBRXkiSaZMmLYeZ/NWcmeB43mMY= github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945 h1:N8Bg45zpk/UcpNGnfJt2y/3lRWASHNTUET8owPYCgYI= +github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -29,12 +39,14 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/ go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53 h1:kcXqo9vE6fsZY5X5Rd7R1l7fTgnWaDCVmln65REefiE= golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=