Skip to content

refactor(filter): replace config package for hystrix#3193

Open
zbchi wants to merge 1 commit intoapache:developfrom
zbchi:config-filter
Open

refactor(filter): replace config package for hystrix#3193
zbchi wants to merge 1 commit intoapache:developfrom
zbchi:config-filter

Conversation

@zbchi
Copy link
Contributor

@zbchi zbchi commented Feb 4, 2026

Description

#2741
This PR refactors the Hystrix filter to simplify its configuration approach by removing the config package.
Users now configure Hystrix commands using the hystrix-go API directly,aligning with the Sentinel filter's API.

before

  filter_conf:
    hystrix_consumer:
      configs:
        "Default":
          timeout: 1000
...

after

import     "github.com/afex/hystrix-go/hystrix"

	cmdName := "dubbo:consumer:greet.GreetService:::Greet"

	hystrix.ConfigureCommand(cmdName, hystrix.CommandConfig{
		Timeout:                1000, 
		MaxConcurrentRequests:  10,
		RequestVolumeThreshold: 5,
		SleepWindow:            5000,
		ErrorPercentThreshold:  50,
	})

svc, err := greet.NewGreetService(cli, client.WithFilter("hystrix_consumer"))

benifits

no longer depend on config package
direct api usage, aligns with Sentinel filter configuration approach

Checklist

  • I confirm the target branch is develop
  • Code has passed local testing
  • I have added tests that prove my fix is effective or that my feature works

@sonarqubecloud
Copy link

sonarqubecloud bot commented Feb 4, 2026

@codecov-commenter
Copy link

Codecov Report

❌ Patch coverage is 65.51724% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 48.41%. Comparing base (60d1c2a) to head (597a260).
⚠️ Report is 725 commits behind head on develop.

Files with missing lines Patch % Lines
filter/hystrix/filter.go 65.51% 7 Missing and 3 partials ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #3193      +/-   ##
===========================================
+ Coverage    46.76%   48.41%   +1.65%     
===========================================
  Files          295      461     +166     
  Lines        17172    33369   +16197     
===========================================
+ Hits          8031    16157    +8126     
- Misses        8287    15902    +7615     
- Partials       854     1310     +456     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Alanxtl Alanxtl linked an issue Feb 4, 2026 that may be closed by this pull request
@Alanxtl Alanxtl added ✏️ Feature 3.3.2 version 3.3.2 labels Feb 4, 2026
@AlexStocks AlexStocks requested a review from Copilot February 5, 2026 01:29
@AlexStocks
Copy link
Contributor

hystrix 已经七八年没人维护了,可以不要了吧?

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the Hystrix filter to remove its dependency on the config package and align with the Sentinel filter's API design. Users now configure Hystrix commands directly using the hystrix-go API instead of through YAML configuration.

Changes:

  • Removed config package dependency and all YAML-based configuration code
  • Simplified filter implementation to use hystrix-go API directly
  • Changed resource name format from URL.Key() based to a colon-separated format matching Sentinel filter

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
filter/hystrix/filter.go Removed config loading logic, error whitelist support, and synchronization primitives; simplified Invoke method to use hystrix.Do directly; added resource name generation matching Sentinel filter format
filter/hystrix/filter_test.go Replaced comprehensive config-based tests with simpler API-based tests demonstrating new configuration approach

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

// Invoke is an implementation of filter, provides Hystrix pattern latency and fault tolerance
func (f *Filter) Invoke(ctx context.Context, invoker base.Invoker, invocation base.Invocation) result.Result {
cmdName := fmt.Sprintf("%s&method=%s", invoker.GetURL().Key(), invocation.MethodName())
cmdName := getResourceName(invoker, invocation, f.COrP)
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The resource name format has changed from the old implementation. Previously, it used URL.Key() which had a different format. The new format "dubbo:consumer:InterfaceName:group:version:Method(paramTypes)" is consistent with the Sentinel filter but represents a breaking change. Users who configured hystrix commands based on the old format will need to update their configuration. Consider documenting this breaking change in the PR description or migration guide.

Copilot uses AI. Check for mistakes.
Comment on lines +98 to +100
err := hystrix.Do(cmdName, func() error {
res = invoker.Invoke(ctx, invocation)
err := res.Error()
if err != nil {
res.SetError(NewHystrixFilterError(err, false))
for _, reg := range f.res[invocation.MethodName()] {
if reg.MatchString(err.Error()) {
logger.Debugf("[Hystrix Filter]Error in invocation but omitted in circuit breaker: %v; %s", err, cmdName)
return nil
}
}
}
return err
return res.Error()
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error whitelist feature has been removed. Previously, users could configure error patterns to exclude from circuit breaker metrics. While this simplifies the implementation and aligns with the Sentinel filter approach, it's a breaking change for users who relied on this functionality. Consider documenting this removal and providing guidance on alternative approaches, such as implementing custom error filtering logic before the hystrix filter.

Copilot uses AI. Check for mistakes.
Comment on lines +53 to 76
func TestHystrixFilter_Invoke(t *testing.T) {
// Configure hystrix command for testing
// Resource name format: dubbo:consumer:InterfaceName:group:version:Method(paramTypes)
cmdName := "dubbo:consumer:com.ikurento.user.UserProvider:::TestMethod()"
hystrix.ConfigureCommand(cmdName, hystrix.CommandConfig{
Timeout: 1000,
MaxConcurrentRequests: 10,
RequestVolumeThreshold: 5,
SleepWindow: 1000,
ErrorPercentThreshold: 50,
})

func TestHystrixFilterInvokeFail(t *testing.T) {
hf := &Filter{}
testUrl, err := common.NewURL(
fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider", constant.LocalHostValue, constant.DefaultPort))
url, err := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider")
require.NoError(t, err)
testInvoker := testMockFailInvoker{*base.NewBaseInvoker(testUrl)}
invokeResult := hf.Invoke(context.Background(), &testInvoker, &invocation.RPCInvocation{})
assert.NotNil(t, invokeResult)
require.Error(t, invokeResult.Error())
}

func TestHystrixFilterInvokeCircuitBreak(t *testing.T) {
mockInitHystrixConfig()
hystrix.Flush()
hf := &Filter{COrP: true}
resChan := make(chan result.Result, 50)
configLoadMutex.Lock()
defer configLoadMutex.Unlock()
for i := 0; i < 50; i++ {
go func() {
testUrl, err := common.NewURL(
fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider", constant.LocalHostValue, constant.DefaultPort))
assert.NoError(t, err)
testInvoker := testMockSuccessInvoker{*base.NewBaseInvoker(testUrl)}
invokeResult := hf.Invoke(context.Background(), &testInvoker, &invocation.RPCInvocation{})
resChan <- invokeResult
}()
}
// This can not always pass the test when on travis due to concurrency, you can uncomment the code below and test it locally
mockInvoker := base.NewBaseInvoker(url)

//var lastRest bool
//for i := 0; i < 50; i++ {
// lastRest = (<-resChan).Error().(*FilterError).FailByHystrix()
//}
//Normally the last result should be true, which means the circuit has been opened
//
//assert.True(t, lastRest)
}

func TestHystrixFilterInvokeCircuitBreakOmitException(t *testing.T) {
mockInitHystrixConfig()
hystrix.Flush()
reg, _ := regexp.Compile(".*exception.*")
regs := []*regexp.Regexp{reg}
hf := &Filter{res: map[string][]*regexp.Regexp{"": regs}, COrP: true}
resChan := make(chan result.Result, 50)
configLoadMutex.Lock()
defer configLoadMutex.Unlock()
for i := 0; i < 50; i++ {
go func() {
testUrl, err := common.NewURL(
fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider", constant.LocalHostValue, constant.DefaultPort))
assert.NoError(t, err)
testInvoker := testMockSuccessInvoker{*base.NewBaseInvoker(testUrl)}
invokeResult := hf.Invoke(context.Background(), &testInvoker, &invocation.RPCInvocation{})
resChan <- invokeResult
}()
}
// This can not always pass the test when on travis due to concurrency, you can uncomment the code below and test it locally
filter := &Filter{COrP: true}
mockInvocation := invocation.NewRPCInvocation("TestMethod", []any{"OK"}, make(map[string]any))

//time.Sleep(time.Second * 6)
//var lastRest bool
//for i := 0; i < 50; i++ {
// lastRest = (<-resChan).Error().(*FilterError).FailByHystrix()
//}
//
//assert.False(t, lastRest)
ctx := context.Background()
result := filter.Invoke(ctx, mockInvoker, mockInvocation)
assert.NotNil(t, result)
assert.NoError(t, result.Error())
}
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test coverage is minimal compared to the old implementation. The removed tests covered important scenarios like circuit breaking behavior, error handling, and concurrent requests. Consider adding tests for: 1) invocation errors being properly handled, 2) circuit breaker opening after threshold is reached, 3) fallback behavior when circuit is open. The Sentinel filter has similar comprehensive tests (filter/sentinel/filter_test.go:45-92, 118-160) that could serve as a reference.

Copilot uses AI. Check for mistakes.
Comment on lines +23 to +31
// // Resource name format: dubbo:consumer:InterfaceName:group:version:Method(param1,param2)
// // Example: dubbo:consumer:com.example.GreetService:::Greet(string,string)
// hystrix.ConfigureCommand("dubbo:consumer:com.example.GreetService:::Greet(string,string)", hystrix.CommandConfig{
// Timeout: 1000,
// MaxConcurrentRequests: 20,
// RequestVolumeThreshold: 20,
// SleepWindow: 5000,
// ErrorPercentThreshold: 50,
// })
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation example shows parameter types as "string,string" but the test shows empty parameter types with "()". The documentation should clarify that parameter types are included only when they exist, and show a clearer example. For instance, the test uses "TestMethod()" with no parameters, which doesn't match the documentation example format.

Copilot uses AI. Check for mistakes.
@Alanxtl
Copy link
Contributor

Alanxtl commented Feb 5, 2026

hystrix 已经七八年没人维护了,可以不要了吧?

@AlexStocks @zbchi 可以把这个filter放到 https://github.com/apache/dubbo-go-contrib 里面,正好以这个filter为例子把dubbo-go-contrib利用起来

@AlexStocks
Copy link
Contributor

hystrix 已经七八年没人维护了,可以不要了吧?

@AlexStocks @zbchi 可以把这个filter放到 https://github.com/apache/dubbo-go-contrib 里面,正好以这个filter为例子把dubbo-go-contrib利用起来

用这个库 https://github.com/apache/dubbo-go-extensions 吧,https://github.com/apache/dubbo-go-contrib 这个就算了

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Enhancement] Complete delete config package

5 participants