This is an automated email from the ASF dual-hosted git repository.
xuetaoli pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/dubbo-go-samples.git
The following commit(s) were added to refs/heads/main by this push:
new 5c11a1f5 feat: add hystrix sample (#1060)
5c11a1f5 is described below
commit 5c11a1f527f6e3838c3569995d3381937877e3af
Author: Zecheng Zhu <[email protected]>
AuthorDate: Sun Apr 5 22:02:45 2026 +0800
feat: add hystrix sample (#1060)
* feat: add hystrix sample
* update readme
* fix docs
* update readme
* fix: improve hystrix sample concurrency and error handling
* add hystrix to integration test list
* fix readme err
---
README.md | 5 +
README_CN.md | 5 +
filter/hystrix/README.md | 118 +++++++++++++++
filter/hystrix/README_zh.md | 118 +++++++++++++++
filter/hystrix/go-client/cmd/main.go | 119 +++++++++++++++
filter/hystrix/go-server/cmd/main.go | 74 ++++++++++
filter/hystrix/proto/greet.pb.go | 230 +++++++++++++++++++++++++++++
filter/hystrix/proto/greet.proto | 33 +++++
filter/{ => hystrix}/proto/greet.triple.go | 2 +-
filter/proto/greet.triple.go | 2 +-
go.mod | 3 +-
go.sum | 2 +
start_integrate_test.sh | 1 +
13 files changed, 709 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index 9de60f94..7dfc6b2d 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,12 @@ Please refer to [HOWTO.md](HOWTO.md) for detailed
instructions on running the sa
* `context`: Demonstrates passing user data (attachments) via Go `context`
between client and server.
* `error`: Error-handling examples in Dubbo-go.
* `filter`: Demonstrates the use of built-in and custom filters in Dubbo-go.
+ * `custom`: Implements custom client and server filters.
+ * `hystrix`: Uses `hystrix-go` to demonstrate circuit breaker protection on
Dubbo-go calls.
+ * `sentinel`: Demonstrates flow control, isolation, and circuit breaking
with Sentinel filters.
* `polaris/limit`: Uses Polaris as a TPS limiter.
+ * `token`: Demonstrates token-based request validation between consumer and
provider.
+ * `tpslimit`: Demonstrates Dubbo-go's built-in TPS limiting filter with
custom limit and rejection strategies.
* `healthcheck`: Service health check example.
* `helloworld`: Basic “Hello World” example for Dubbo-go, also includes
Go–Java interoperability.
* `http3`: HTTP/3 (QUIC) protocol support example demonstrating how to use
Triple protocol with HTTP/3 for high-performance communication between Go and
Java services with TLS encryption.
diff --git a/README_CN.md b/README_CN.md
index b42aab1b..fd74ad3d 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -20,7 +20,12 @@
* `context`:演示如何通过 Go 的 `context` 在客户端与服务端之间传递用户数据(attachments)。
* `error`:Dubbo-go 的错误处理示例。
* `filter`:演示 Dubbo-go 中内置和自定义 Filter 的使用。
+ * `custom`:实现自定义的客户端和服务端 Filter。
+ * `hystrix`:使用 `hystrix-go` 演示 Dubbo-go 调用中的熔断保护。
+ * `sentinel`:演示基于 Sentinel Filter 的流控、隔离和熔断能力。
* `polaris/limit`:使用 Polaris 实现 TPS 限流。
+ * `token`:演示消费端与提供端之间基于 token 的请求校验。
+ * `tpslimit`:演示 Dubbo-go 内置 TPSLimit Filter,以及自定义限流和拒绝处理策略。
* `healthcheck`:服务健康检查示例。
* `helloworld`:Dubbo-go 最基础的 “Hello World” 示例,同时包含 Go 与 Java 的互操作示例。
* `http3`:HTTP/3(QUIC)协议支持示例,演示如何通过 Triple 协议使用 HTTP/3 实现 Go 与 Java
服务之间的高性能通信,并支持 TLS 加密。
diff --git a/filter/hystrix/README.md b/filter/hystrix/README.md
new file mode 100644
index 00000000..e9e4d62c
--- /dev/null
+++ b/filter/hystrix/README.md
@@ -0,0 +1,118 @@
+# Hystrix Filter Example
+
+[English](README.md) | [中文](README_zh.md)
+
+## Background
+
+This example demonstrates how to use the Hystrix filter in dubbo-go to
implement circuit breaker functionality. Hystrix is a latency and fault
tolerance library designed to isolate points of access to remote systems,
services, and 3rd party libraries, stop cascading failures, and enable
resilience in complex distributed systems.
+
+## Implementation
+
+### 1. Configure Hystrix Commands
+
+Use the `hystrix-go` API to configure circuit breaker commands. The resource
name format is:
+```
+dubbo:consumer:InterfaceName:group:version:Method
+```
+
+**Client Configuration** (`go-client/cmd/main.go`):
+```go
+import (
+ "github.com/afex/hystrix-go/hystrix"
+ _ "github.com/apache/dubbo-go-extensions/filter/hystrix"
+)
+
+func init() {
+ // Resource name format: dubbo:consumer:InterfaceName:group:version:Method
+ cmdName := "dubbo:consumer:greet.GreetService:::Greet"
+
+ hystrix.ConfigureCommand(cmdName, hystrix.CommandConfig{
+ Timeout: 1000, // timeout in milliseconds
+ MaxConcurrentRequests: 10, // max concurrent requests
+ RequestVolumeThreshold: 5, // minimum requests to trip the circuit
+ SleepWindow: 5000, // time to wait before attempting
recovery (ms)
+ ErrorPercentThreshold: 50, // error rate threshold (percentage)
+ })
+}
+```
+
+### 2. Use Hystrix Filter
+
+**Client** (`go-client/cmd/main.go`):
+```go
+import (
+ "dubbo.apache.org/dubbo-go/v3/client"
+)
+
+svc, err := greet.NewGreetService(cli, client.WithFilter("hystrix_consumer"))
+```
+
+## Configuration Parameters
+
+| Parameter | Description |
+|-----------|-------------|
+| `Timeout` | Command execution timeout in milliseconds |
+| `MaxConcurrentRequests` | Maximum number of concurrent requests allowed |
+| `RequestVolumeThreshold` | Minimum number of requests required to trip the
circuit (within sliding window) |
+| `SleepWindow` | Time to wait after circuit opens before attempting recovery
(milliseconds) |
+| `ErrorPercentThreshold` | Error rate threshold that triggers circuit opening
(percentage) |
+
+## How to Run
+
+### Prerequisites
+
+1. Start the Go server and make sure `127.0.0.1:20000` is ready to accept
requests.
+
+### Start Server
+
+```shell
+cd filter/hystrix/go-server
+go run ./cmd/main.go
+```
+
+### Start Client
+
+```shell
+cd filter/hystrix/go-client
+go run ./cmd/main.go
+```
+
+## Expected Output
+
+**Client Output:**
+```bash
+=== Test 1: Sending normal requests ===
+Request 1 success: Hello, request-1! (request #1)
+Request 2 success: Hello, request-2! (request #2)
+Request 3 success: Hello, request-3! (request #3)
+
+=== Test 2: Sending concurrent requests ===
+Concurrent request 1 success: Hello, concurrent-1! (request #4)
+Concurrent request 2 success: Hello, concurrent-2! (request #5)
+...
+
+=== Test 3: Sending requests after concurrent test ===
+After-test request 1 failed (circuit might be open): ...
+```
+
+When the circuit breaker is open, you will see errors like:
+```bash
+After-test request 1 failed: hystrix: circuit open
+```
+
+## Testing Circuit Breaker
+
+The example program includes three test phases:
+
+1. **Normal Requests**: Sends 3 normal requests to verify basic functionality
+2. **Concurrent Requests**: Sends 15 concurrent requests, potentially
triggering the circuit breaker
+3. **Recovery Test**: Continues sending requests after concurrent test to
observe circuit breaker state
+
+If the circuit breaker is triggered, wait about 5 seconds (SleepWindow
configuration) before running the client again to see the circuit recover.
+
+## Notes
+
+- Hystrix filter is primarily used on the **client side** to protect callers
from downstream service failures
+- The resource name must match the actual interface, group, version, and
method name
+- Circuit breaker states: Closed → Open → Half-Open → Closed
+- Configure timeout and concurrency limits appropriately to avoid resource
exhaustion
diff --git a/filter/hystrix/README_zh.md b/filter/hystrix/README_zh.md
new file mode 100644
index 00000000..5ead47fa
--- /dev/null
+++ b/filter/hystrix/README_zh.md
@@ -0,0 +1,118 @@
+# Hystrix Filter 示例
+
+[English](README.md) | [中文](README_zh.md)
+
+## 背景
+
+本示例演示了如何在 dubbo-go 中使用 Hystrix filter 实现熔断器功能。Hystrix
是一个延迟和容错库,用于隔离访问远程系统、服务或第三方库的访问点,防止级联故障,实现熔断器模式。
+
+## 实现方法
+
+### 1. 配置 Hystrix 命令
+
+使用 `hystrix-go` API 配置熔断器命令。资源名称格式为:
+```
+dubbo:consumer:InterfaceName:group:version:Method
+```
+
+**客户端配置** (`go-client/cmd/main.go`):
+```go
+import (
+ "github.com/afex/hystrix-go/hystrix"
+ _ "github.com/apache/dubbo-go-extensions/filter/hystrix"
+)
+
+func init() {
+ // 资源名称格式: dubbo:consumer:接口名:分组:版本:方法
+ cmdName := "dubbo:consumer:greet.GreetService:::Greet"
+
+ hystrix.ConfigureCommand(cmdName, hystrix.CommandConfig{
+ Timeout: 1000, // 超时时间(毫秒)
+ MaxConcurrentRequests: 10, // 最大并发请求数
+ RequestVolumeThreshold: 5, // 熔断器触发的最小请求数
+ SleepWindow: 5000, // 熔断后尝试恢复的时间(毫秒)
+ ErrorPercentThreshold: 50, // 错误率阈值(百分比)
+ })
+}
+```
+
+### 2. 使用 Hystrix Filter
+
+**客户端** (`go-client/cmd/main.go`):
+```go
+import (
+ "dubbo.apache.org/dubbo-go/v3/client"
+)
+
+svc, err := greet.NewGreetService(cli, client.WithFilter("hystrix_consumer"))
+```
+
+## 配置参数说明
+
+| 参数 | 说明 |
+|------|------|
+| `Timeout` | 命令执行超时时间(毫秒) |
+| `MaxConcurrentRequests` | 同一时间最大的并发请求数 |
+| `RequestVolumeThreshold` | 熔断器触发的最小请求数(滑动窗口内) |
+| `SleepWindow` | 熔断器打开后,等待多久尝试恢复(毫秒) |
+| `ErrorPercentThreshold` | 错误率阈值,超过此百分比熔断器打开 |
+
+## 运行方法
+
+### 前置条件
+
+1. 先启动 Go 服务端,并确认 `127.0.0.1:20000` 已经可以接受请求。
+
+### 启动服务端
+
+```shell
+cd filter/hystrix/go-server
+go run ./cmd/main.go
+```
+
+### 启动客户端
+
+```shell
+cd filter/hystrix/go-client
+go run ./cmd/main.go
+```
+
+## 预期输出
+
+**客户端输出:**
+```bash
+=== Test 1: Sending normal requests ===
+Request 1 success: Hello, request-1! (request #1)
+Request 2 success: Hello, request-2! (request #2)
+Request 3 success: Hello, request-3! (request #3)
+
+=== Test 2: Sending concurrent requests ===
+Concurrent request 1 success: Hello, concurrent-1! (request #4)
+Concurrent request 2 success: Hello, concurrent-2! (request #5)
+...
+
+=== Test 3: Sending requests after concurrent test ===
+After-test request 1 failed (circuit might be open): ...
+```
+
+当熔断器打开时,你会看到类似以下的错误:
+```bash
+After-test request 1 failed: hystrix: circuit open
+```
+
+## 测试熔断器功能
+
+示例程序包含三个测试阶段:
+
+1. **正常请求**: 发送3个正常请求,验证基本功能
+2. **并发请求**: 发送15个并发请求,可能触发熔断器
+3. **恢复测试**: 在并发请求后继续发送请求,观察熔断器状态
+
+如果触发了熔断器,等待约5秒(SleepWindow配置)后再运行客户端,可以看到熔断器恢复。
+
+## 注意事项
+
+- Hystrix filter 主要用于**客户端**,保护调用方免受下游服务故障的影响
+- 资源名称需要与实际接口、分组、版本和方法名保持一致
+- 熔断器状态:关闭 → 打开 → 半开 → 关闭
+- 合理配置超时时间和并发数,避免资源耗尽
diff --git a/filter/hystrix/go-client/cmd/main.go
b/filter/hystrix/go-client/cmd/main.go
new file mode 100644
index 00000000..827f07a7
--- /dev/null
+++ b/filter/hystrix/go-client/cmd/main.go
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package main
+
+import (
+ "context"
+ "fmt"
+ "sync"
+ "time"
+)
+
+import (
+ "dubbo.apache.org/dubbo-go/v3/client"
+ _ "dubbo.apache.org/dubbo-go/v3/imports"
+
+ "github.com/afex/hystrix-go/hystrix"
+
+ _ "github.com/apache/dubbo-go-extensions/filter/hystrix"
+
+ "github.com/dubbogo/gost/log/logger"
+)
+
+import (
+ greet "github.com/apache/dubbo-go-samples/filter/hystrix/proto"
+)
+
+func init() {
+ // Configure hystrix command for the GreetService.Greet method
+ // Resource name format:
dubbo:consumer:InterfaceName:group:version:Method
+ // For this example: dubbo:consumer:greet.GreetService:::Greet
+ cmdName := "dubbo:consumer:greet.GreetService:::Greet"
+
+ hystrix.ConfigureCommand(cmdName, hystrix.CommandConfig{
+ Timeout: 1000, // 1 second timeout
+ MaxConcurrentRequests: 10, // Max 10 concurrent requests
+ RequestVolumeThreshold: 5, // Minimum 5 requests before
circuit can trip
+ SleepWindow: 5000, // 5 seconds to wait after
circuit opens before testing
+ ErrorPercentThreshold: 50, // 50% error rate triggers
circuit opening
+ })
+
+ logger.Infof("Configured hystrix command: %s", cmdName)
+}
+
+func logGreetResult(stage string, idx int, resp *greet.GreetResponse, err
error) {
+ if err != nil {
+ logger.Infof("%s %d failed: %v", stage, idx, err)
+ return
+ }
+
+ logger.Infof("%s %d success: %s", stage, idx, resp.Greeting)
+}
+
+func main() {
+ cli, err := client.NewClient(
+ client.WithClientURL("127.0.0.1:20000"),
+ )
+ if err != nil {
+ panic(err)
+ }
+
+ svc, err := greet.NewGreetService(cli,
client.WithFilter("hystrix_consumer"))
+ if err != nil {
+ panic(err)
+ }
+
+ // Test 1: Normal requests
+ logger.Info("=== Test 1: Sending normal requests ===")
+ for i := 1; i <= 3; i++ {
+ resp, err := svc.Greet(context.Background(),
&greet.GreetRequest{Name: fmt.Sprintf("request-%d", i)})
+ logGreetResult("Request", i, resp, err)
+ }
+
+ // Test 2: Multiple concurrent requests to potentially trigger circuit
breaker
+ logger.Info("\n=== Test 2: Sending concurrent requests ===")
+ var wg sync.WaitGroup
+ for i := 1; i <= 15; i++ {
+ wg.Add(1)
+ go func(idx int) {
+ defer wg.Done()
+
+ resp, err := svc.Greet(context.Background(),
&greet.GreetRequest{Name: fmt.Sprintf("concurrent-%d", idx)})
+ logGreetResult("Concurrent request", idx, resp, err)
+ }(i)
+ }
+
+ // Wait for concurrent requests to complete before observing circuit
state.
+ wg.Wait()
+
+ // Test 3: Try requests after circuit might be open
+ logger.Info("\n=== Test 3: Sending requests after concurrent test ===")
+ for i := 1; i <= 5; i++ {
+ resp, err := svc.Greet(context.Background(),
&greet.GreetRequest{Name: fmt.Sprintf("after-%d", i)})
+ if err != nil {
+ logger.Infof("After-test request %d failed (circuit
might be open): %v", i, err)
+ } else {
+ logger.Infof("After-test request %d success: %s", i,
resp.Greeting)
+ }
+ time.Sleep(500 * time.Millisecond)
+ }
+
+ logger.Info("\nAll tests completed!")
+ logger.Info("If you see 'circuit open' errors, it means Hystrix
successfully triggered the circuit breaker.")
+ logger.Info("Wait a few seconds and try again to see the circuit
recover.")
+}
diff --git a/filter/hystrix/go-server/cmd/main.go
b/filter/hystrix/go-server/cmd/main.go
new file mode 100644
index 00000000..bd081e02
--- /dev/null
+++ b/filter/hystrix/go-server/cmd/main.go
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package main
+
+import (
+ "context"
+ "fmt"
+ "sync/atomic"
+ "time"
+)
+
+import (
+ _ "dubbo.apache.org/dubbo-go/v3/imports"
+ "dubbo.apache.org/dubbo-go/v3/protocol"
+ "dubbo.apache.org/dubbo-go/v3/server"
+
+ "github.com/dubbogo/gost/log/logger"
+)
+
+import (
+ greet "github.com/apache/dubbo-go-samples/filter/hystrix/proto"
+)
+
+type GreetTripleServer struct {
+ requestCount atomic.Int64
+}
+
+func (srv *GreetTripleServer) Greet(ctx context.Context, req
*greet.GreetRequest) (*greet.GreetResponse, error) {
+ requestNum := srv.requestCount.Add(1)
+ logger.Infof("[%d] Received request: %s", requestNum, req.Name)
+
+ // Simulate some processing time
+ time.Sleep(100 * time.Millisecond)
+
+ resp := &greet.GreetResponse{
+ Greeting: fmt.Sprintf("Hello, %s! (request #%d)", req.Name,
requestNum),
+ }
+ return resp, nil
+}
+
+func main() {
+ srv, err := server.NewServer(
+ server.WithServerProtocol(
+ protocol.WithPort(20000),
+ protocol.WithTriple(),
+ ),
+ )
+ if err != nil {
+ panic(err)
+ }
+
+ if err := greet.RegisterGreetServiceHandler(srv, &GreetTripleServer{});
err != nil {
+ panic(err)
+ }
+
+ if err := srv.Serve(); err != nil {
+ logger.Error(err)
+ }
+}
diff --git a/filter/hystrix/proto/greet.pb.go b/filter/hystrix/proto/greet.pb.go
new file mode 100644
index 00000000..d45ce90c
--- /dev/null
+++ b/filter/hystrix/proto/greet.pb.go
@@ -0,0 +1,230 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.31.0
+// protoc v3.21.12
+// source: proto/greet.proto
+
+package greet
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type GreetRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Name string `protobuf:"bytes,1,opt,name=name,proto3"
json:"name,omitempty"`
+}
+
+func (x *GreetRequest) Reset() {
+ *x = GreetRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_proto_greet_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GreetRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GreetRequest) ProtoMessage() {}
+
+func (x *GreetRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_proto_greet_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GreetRequest.ProtoReflect.Descriptor instead.
+func (*GreetRequest) Descriptor() ([]byte, []int) {
+ return file_proto_greet_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *GreetRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+type GreetResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Greeting string `protobuf:"bytes,1,opt,name=greeting,proto3"
json:"greeting,omitempty"`
+}
+
+func (x *GreetResponse) Reset() {
+ *x = GreetResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_proto_greet_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GreetResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GreetResponse) ProtoMessage() {}
+
+func (x *GreetResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_proto_greet_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GreetResponse.ProtoReflect.Descriptor instead.
+func (*GreetResponse) Descriptor() ([]byte, []int) {
+ return file_proto_greet_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *GreetResponse) GetGreeting() string {
+ if x != nil {
+ return x.Greeting
+ }
+ return ""
+}
+
+var File_proto_greet_proto protoreflect.FileDescriptor
+
+var file_proto_greet_proto_rawDesc = []byte{
+ 0x0a, 0x11, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x72, 0x65, 0x65,
0x74, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x67, 0x72, 0x65, 0x65, 0x74, 0x22, 0x22,
0x0a, 0x0c, 0x47, 0x72,
+ 0x65, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12,
0x0a, 0x04, 0x6e, 0x61,
+ 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
0x6d, 0x65, 0x22, 0x2b,
+ 0x0a, 0x0d, 0x47, 0x72, 0x65, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12,
+ 0x1a, 0x0a, 0x08, 0x67, 0x72, 0x65, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x18,
0x01, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x08, 0x67, 0x72, 0x65, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x32,
0x44, 0x0a, 0x0c, 0x47,
+ 0x72, 0x65, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
0x34, 0x0a, 0x05, 0x47,
+ 0x72, 0x65, 0x65, 0x74, 0x12, 0x13, 0x2e, 0x67, 0x72, 0x65, 0x65, 0x74,
0x2e, 0x47, 0x72, 0x65,
+ 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e,
0x67, 0x72, 0x65, 0x65,
+ 0x74, 0x2e, 0x47, 0x72, 0x65, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x22,
+ 0x00, 0x42, 0x3f, 0x5a, 0x3d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
0x63, 0x6f, 0x6d, 0x2f,
+ 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2f, 0x64, 0x75, 0x62, 0x62, 0x6f,
0x2d, 0x67, 0x6f, 0x2d,
+ 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x66, 0x69, 0x6c, 0x74,
0x65, 0x72, 0x2f, 0x68,
+ 0x79, 0x73, 0x74, 0x72, 0x69, 0x78, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x3b, 0x67, 0x72, 0x65,
+ 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+ file_proto_greet_proto_rawDescOnce sync.Once
+ file_proto_greet_proto_rawDescData = file_proto_greet_proto_rawDesc
+)
+
+func file_proto_greet_proto_rawDescGZIP() []byte {
+ file_proto_greet_proto_rawDescOnce.Do(func() {
+ file_proto_greet_proto_rawDescData =
protoimpl.X.CompressGZIP(file_proto_greet_proto_rawDescData)
+ })
+ return file_proto_greet_proto_rawDescData
+}
+
+var file_proto_greet_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_proto_greet_proto_goTypes = []interface{}{
+ (*GreetRequest)(nil), // 0: greet.GreetRequest
+ (*GreetResponse)(nil), // 1: greet.GreetResponse
+}
+var file_proto_greet_proto_depIdxs = []int32{
+ 0, // 0: greet.GreetService.Greet:input_type -> greet.GreetRequest
+ 1, // 1: greet.GreetService.Greet:output_type -> greet.GreetResponse
+ 1, // [1:2] is the sub-list for method output_type
+ 0, // [0:1] is the sub-list for method input_type
+ 0, // [0:0] is the sub-list for extension type_name
+ 0, // [0:0] is the sub-list for extension extendee
+ 0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_proto_greet_proto_init() }
+func file_proto_greet_proto_init() {
+ if File_proto_greet_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_proto_greet_proto_msgTypes[0].Exporter = func(v
interface{}, i int) interface{} {
+ switch v := v.(*GreetRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_proto_greet_proto_msgTypes[1].Exporter = func(v
interface{}, i int) interface{} {
+ switch v := v.(*GreetResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_proto_greet_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 2,
+ NumExtensions: 0,
+ NumServices: 1,
+ },
+ GoTypes: file_proto_greet_proto_goTypes,
+ DependencyIndexes: file_proto_greet_proto_depIdxs,
+ MessageInfos: file_proto_greet_proto_msgTypes,
+ }.Build()
+ File_proto_greet_proto = out.File
+ file_proto_greet_proto_rawDesc = nil
+ file_proto_greet_proto_goTypes = nil
+ file_proto_greet_proto_depIdxs = nil
+}
diff --git a/filter/hystrix/proto/greet.proto b/filter/hystrix/proto/greet.proto
new file mode 100644
index 00000000..e7701946
--- /dev/null
+++ b/filter/hystrix/proto/greet.proto
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+package greet;
+
+option go_package =
"github.com/apache/dubbo-go-samples/filter/hystrix/proto;greet";
+
+message GreetRequest {
+ string name = 1;
+}
+
+message GreetResponse {
+ string greeting = 1;
+}
+
+service GreetService {
+ rpc Greet(GreetRequest) returns (GreetResponse) {}
+}
\ No newline at end of file
diff --git a/filter/proto/greet.triple.go b/filter/hystrix/proto/greet.triple.go
similarity index 99%
copy from filter/proto/greet.triple.go
copy to filter/hystrix/proto/greet.triple.go
index 6f906938..1df73466 100644
--- a/filter/proto/greet.triple.go
+++ b/filter/hystrix/proto/greet.triple.go
@@ -1,6 +1,6 @@
// Code generated by protoc-gen-triple. DO NOT EDIT.
//
-// Source: greet.proto
+// Source: proto/greet.proto
package greet
import (
diff --git a/filter/proto/greet.triple.go b/filter/proto/greet.triple.go
index 6f906938..1df73466 100644
--- a/filter/proto/greet.triple.go
+++ b/filter/proto/greet.triple.go
@@ -1,6 +1,6 @@
// Code generated by protoc-gen-triple. DO NOT EDIT.
//
-// Source: greet.proto
+// Source: proto/greet.proto
package greet
import (
diff --git a/go.mod b/go.mod
index 68887276..e8ed4165 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,9 @@ go 1.25.0
require (
dubbo.apache.org/dubbo-go/v3 v3.3.1
+ github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5
github.com/alibaba/sentinel-golang v1.0.4
+ github.com/apache/dubbo-go-extensions v0.0.0-20260312085545-de428af0b99e
github.com/apache/dubbo-go-hessian2 v1.12.5
github.com/dubbogo/go-zookeeper v1.0.4-0.20211212162352-f9d2183d89d5
github.com/dubbogo/gost v1.14.3
@@ -30,7 +32,6 @@ require (
require (
github.com/RoaringBitmap/roaring v1.2.3 // indirect
github.com/Workiva/go-datastructures v1.0.52 // indirect
- github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 //
indirect
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68 //
indirect
github.com/alibabacloud-go/tea v1.1.17 // indirect
github.com/alibabacloud-go/tea-utils v1.4.4 // indirect
diff --git a/go.sum b/go.sum
index 6d0136ab..2676b7cd 100644
--- a/go.sum
+++ b/go.sum
@@ -96,6 +96,8 @@ github.com/antihax/optional v1.0.0/go.mod
h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd
github.com/apache/dubbo-getty v1.4.8/go.mod
h1:cPJlbcHUTNTpiboMQjMHhE9XBni11LiBiG8FdrDuVzk=
github.com/apache/dubbo-getty v1.4.10
h1:ZmkpHJa/qgS0evX2tTNqNCz6rClI/9Wwp7ctyMml82w=
github.com/apache/dubbo-getty v1.4.10/go.mod
h1:V64WqLIxksEgNu5aBJBOxNIvpOZyfUJ7J/DXBlKSUoA=
+github.com/apache/dubbo-go-extensions v0.0.0-20260312085545-de428af0b99e
h1:qwdBjqJhwHbRXBtpehiEzilkgFAyZs90e6OC7kNWxwQ=
+github.com/apache/dubbo-go-extensions
v0.0.0-20260312085545-de428af0b99e/go.mod
h1:vpp1J/MZLQYPNrpzx5PsDFCceUEBkdV8KBHVbEfqr4A=
github.com/apache/dubbo-go-hessian2 v1.9.1/go.mod
h1:xQUjE7F8PX49nm80kChFvepA/AvqAZ0oh/UaB6+6pBE=
github.com/apache/dubbo-go-hessian2 v1.9.3/go.mod
h1:xQUjE7F8PX49nm80kChFvepA/AvqAZ0oh/UaB6+6pBE=
github.com/apache/dubbo-go-hessian2 v1.11.0/go.mod
h1:7rEw9guWABQa6Aqb8HeZcsYPHsOS7XT1qtJvkmI6c5w=
diff --git a/start_integrate_test.sh b/start_integrate_test.sh
index 6666f31e..df11ea29 100755
--- a/start_integrate_test.sh
+++ b/start_integrate_test.sh
@@ -31,6 +31,7 @@ array+=("direct")
# filter
array+=("filter/token")
array+=("filter/custom")
+array+=("filter/hystrix")
# registry
array+=("registry/zookeeper")