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 8a01c958 feat: migrate old filter sample to new (#965)
8a01c958 is described below
commit 8a01c958c4fb300108a46caf16bf07d3f5012e78
Author: zbchi <[email protected]>
AuthorDate: Wed Nov 26 18:31:47 2025 +0800
feat: migrate old filter sample to new (#965)
* feat: add new filter sample and remove the old
* update tpslimit sample api
* add filter/custom intergrate test
* remove useless docs
---
README.md | 1 -
README_CN.md | 1 -
.../filter/custom/go-client/conf/dubbogo.yml | 16 ---
.../filter/custom/go-server/cmd/server.go | 51 -------
.../filter/custom/go-server/conf/dubbogo.yml | 16 ---
compatibility/filter/tpslimit/README.md | 53 --------
compatibility/filter/tpslimit/README_zh.md | 53 --------
.../filter/tpslimit/go-client/conf/dubbogo.yml | 16 ---
.../filter/tpslimit/go-server/cmd/server.go | 76 -----------
.../filter/tpslimit/go-server/conf/dubbogo.yml | 26 ----
direct/README.md | 5 +-
direct/README_zh.md | 50 +------
{compatibility/filter => filter}/README.md | 55 ++++----
{compatibility/filter => filter}/README_zh.md | 49 +++----
filter/custom/README.md | 150 +++++++++++++++++++++
filter/custom/README_zh.md | 150 +++++++++++++++++++++
.../custom/go-client/cmd/main.go | 36 +++--
.../custom/go-client/filter}/myfilter.go | 2 +-
.../custom/go-server/cmd/main.go | 42 ++++--
.../custom/go-server/filter}/myfilter.go | 2 +-
filter/tpslimit/README.md | 84 ++++++++++++
filter/tpslimit/README_zh.md | 84 ++++++++++++
.../tpslimit/go-client/cmd/main.go | 39 +++---
.../tpslimit/go-client/pkg/user.go | 0
filter/tpslimit/go-server/cmd/main.go | 85 ++++++++++++
.../tpslimit/go-server/pkg/limit_strategy.go | 0
.../tpslimit/go-server/pkg/reject_handler.go | 0
.../tpslimit/go-server/pkg/user.go | 0
.../filter/custom/tests/integration/myfilter.go | 49 -------
.../custom/tests/integration/userprovider_test.go | 39 ------
.../custom/tests/integration/assert_filter.go | 80 +++++++++++
.../custom/tests/integration/custom_filter_test.go | 89 ++++++++++++
.../filter/custom/tests/integration/main_test.go | 31 ++++-
start_integrate_test.sh | 4 +-
34 files changed, 887 insertions(+), 547 deletions(-)
diff --git a/README.md b/README.md
index 8e8bf766..bd35f7e2 100644
--- a/README.md
+++ b/README.md
@@ -49,7 +49,6 @@ A collection of runnable Dubbo-go examples covering
configuration, registries, o
* `compatibility/apisix`: Example integrating Apache APISIX with Dubbo-go.
* `compatibility/config-api`: Shows how to use Dubbo-go via APIs without
configuration files.
* `compatibility/configcenter`: Usage of different config centers, including
Zookeeper, Nacos, and Apollo.
-* `compatibility/filter`: Examples of different filters, including
`custom_filter` and `tpslimit`.
* `compatibility/generic`: Generic invocation example.
* `compatibility/mesh`: Proxy-based service mesh example showing how to deploy
Dubbo-go services with Envoy on Kubernetes.
* `compatibility/proxyless`: Proxyless service mesh example for deploying
Dubbo-go services on Kubernetes.
diff --git a/README_CN.md b/README_CN.md
index 2638fcfc..1b990262 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -49,7 +49,6 @@
* `compatibility/apisix`:Dubbo-go 集成 Apache APISIX 的示例。
* `compatibility/config-api`:演示如何在不使用配置文件的情况下,通过 API 使用 Dubbo-go。
* `compatibility/configcenter`:不同配置中心的使用示例,包括 Zookeeper、Nacos 和 Apollo。
-* `compatibility/filter`:多种 Filter 示例,包括 `custom_filter` 和 `tpslimit`。
* `compatibility/generic`:泛化调用示例。
* `compatibility/mesh`:基于代理的服务网格示例,展示如何在 Kubernetes 上结合 Envoy 部署 Dubbo-go 服务。
* `compatibility/proxyless`:无 Sidecar 的服务网格示例,展示在 Kubernetes 上的部署方式。
diff --git a/compatibility/filter/custom/go-client/conf/dubbogo.yml
b/compatibility/filter/custom/go-client/conf/dubbogo.yml
deleted file mode 100644
index 96513a1f..00000000
--- a/compatibility/filter/custom/go-client/conf/dubbogo.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-# dubbo client yaml configure file
-
-dubbo:
- registries:
- demoZK:
- protocol: zookeeper
- timeout: 3s
- address: 127.0.0.1:2181
- consumer:
- filter: myClientFilter
- check: true
- request_timeout: 3s
- connect_timeout: 3s
- references:
- GreeterClientImpl:
- protocol: tri
\ No newline at end of file
diff --git a/compatibility/filter/custom/go-server/cmd/server.go
b/compatibility/filter/custom/go-server/cmd/server.go
deleted file mode 100644
index 32c2ddaa..00000000
--- a/compatibility/filter/custom/go-server/cmd/server.go
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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"
-)
-
-import (
- "dubbo.apache.org/dubbo-go/v3/config"
- _ "dubbo.apache.org/dubbo-go/v3/imports"
-
- "github.com/dubbogo/gost/log/logger"
-)
-
-import (
- "github.com/apache/dubbo-go-samples/compatibility/api"
-)
-
-type GreeterProvider struct {
- api.UnimplementedGreeterServer
-}
-
-func (s *GreeterProvider) SayHello(ctx context.Context, in *api.HelloRequest)
(*api.User, error) {
- logger.Infof("Dubbo3 GreeterProvider get user name = %s\n", in.Name)
- return &api.User{Name: "Hello " + in.Name, Id: "12345", Age: 21}, nil
-}
-
-// export DUBBO_GO_CONFIG_PATH=
PATH_TO_SAMPLES/helloworld/go-server/conf/dubbogo.yml
-func main() {
- config.SetProviderService(&GreeterProvider{})
- if err := config.Load(); err != nil {
- panic(err)
- }
- select {}
-}
diff --git a/compatibility/filter/custom/go-server/conf/dubbogo.yml
b/compatibility/filter/custom/go-server/conf/dubbogo.yml
deleted file mode 100644
index d7ec402c..00000000
--- a/compatibility/filter/custom/go-server/conf/dubbogo.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-dubbo:
- registries:
- demoZK:
- protocol: zookeeper
- address: 127.0.0.1:2181
- protocols:
- tripleProtocol:
- name: tri
- port: 20000
- provider:
- services:
- GreeterProvider:
- filter: myServerFilter
- loadbalance: random
- warmup: 100
- cluster: failover
diff --git a/compatibility/filter/tpslimit/README.md
b/compatibility/filter/tpslimit/README.md
deleted file mode 100644
index be319db0..00000000
--- a/compatibility/filter/tpslimit/README.md
+++ /dev/null
@@ -1,53 +0,0 @@
-# TPSLimit Filter Sample
-
-### Background
-
-Dubbo-go has a built in filter for limiting TPS purpose - "tpslimit". It can
be enabled by configuring on the provider side, furthermore, user can customize
the TPS limit strategy and the return value after the request is rejected.
-
-### Example
-
-##### 1. Code
-
-A) Customize TPS limit strategy:
-
-To customize TPS limit strategy, the interface "filter.TpsLimitStrategy" is
needed to implement. In this example, the strategy is implemented as randomly
rejecting the incoming request. Examples are linked as follows:
https://github.com/apache/dubbo-go-samples/tree/master/filter/tpslimit/go-server/pkg/limit_strategy.go
-
-B) Customize execution handler when the request is rejected.
-
-Implement the interface "filter.RejectedExecutionHandler" to customize the
return result to the client when the request is rejected. In this example, when
the TPS limit criteria meets, the customized execution handler will return the
error "The request is rejected and doesn't have any default value." back to the
consumer. Examples are linked as follows:
https://github.com/apache/dubbo-go-samples/tree/master/filter/tpslimit/go-server/pkg/reject_handler.go
-
-##### 2. Configuration
-
-Enable tpslimit filter in provider's configuration file like below:
-
-```yaml
-# service config
-services:
- UserProvider:
- registry: demoZk
- protocol: dubbo
- interface: org.apache.dubbo.UserProvider
- tps.limiter: method-service
- tps.limit.strategy: RandomLimitStrategy
- tps.limit.rejected.handler: DefaultValueHandler
- tps.limit.interval: 5000
- tps.limit.rate: 300
-```
-
-##### 3. Run
-
-Pls. refer to [HOWTO.md](../../../HOWTO.md) under the root directory to run
this sample.
-
-The provider side will print out:
-
-```bash
-[2021-03-10/17:11:10
github.com/apache/dubbo-go-samples/filter/tpslimit/go-server/pkg.RandomTpsLimitStrategy.IsAllowable:
limit_strategy.go: 56] %s
-Random IsAllowable!
-2021-03-10T17:11:10.748+0800 ERROR filter_impl/tps_limit_filter.go:69
The invocation was rejected due to over the tps limitation, ...
-```
-
-The consumer side will print out:
-
-```bash
-error: The request is rejected and doesn't have any default value.
-```
\ No newline at end of file
diff --git a/compatibility/filter/tpslimit/README_zh.md
b/compatibility/filter/tpslimit/README_zh.md
deleted file mode 100644
index badfff4a..00000000
--- a/compatibility/filter/tpslimit/README_zh.md
+++ /dev/null
@@ -1,53 +0,0 @@
-# TPSLimit Filter 示例
-
-### 背景
-
-Dubbo-go 内置了限流 filter "tpslimit"。可以通过在服务端的配置来激活,另外,用户还可以自定义限流策略和拒绝访问后的处理逻辑。
-
-### 示例
-
-##### 1. 代码
-
-A) 自定义限流策略:
-
-通过实现 filter.TpsLimitStrategy
来自定义限流策略。在本例中,采取的策略是随机限流。例子链接为:https://github.com/apache/dubbo-go-samples/tree/master/filter/tpslimit/go-server/pkg/limit_strategy.go
-
-B) 自定义拒绝访问处理:
-
-通过实现 filter.RejectedExecutionHandler。在本例中,当限流条件满足的情况下,拒绝访问的自定义处理逻辑将会返回 "The
request is rejected and doesn't have any default value. "
的错误给客户端。例子链接为:https://github.com/apache/dubbo-go-samples/tree/master/filter/tpslimit/go-server/pkg/reject_handler.go
-
-##### 2. 配置
-
-在服务端的配置文件中,按如下所示配置该 filter:
-
-```yaml
-# service config
-services:
- UserProvider:
- registry: demoZk
- protocol: dubbo
- interface: org.apache.dubbo.UserProvider
- tps.limiter: method-service
- tps.limit.strategy: RandomLimitStrategy
- tps.limit.rejected.handler: DefaultValueHandler
- tps.limit.interval: 5000
- tps.limit.rate: 300
-```
-
-##### 3. 运行
-
-请参阅根目录中的 [HOWTO.md](../../../HOWTO_zh.md) 来运行本例。
-
-观察服务端的输出:
-
-```bash
-[2021-03-10/17:11:10
github.com/apache/dubbo-go-samples/filter/tpslimit/go-server/pkg.RandomTpsLimitStrategy.IsAllowable:
limit_strategy.go: 56] %s
-Random IsAllowable!
-2021-03-10T17:11:10.748+0800 ERROR filter_impl/tps_limit_filter.go:69
The invocation was rejected due to over the tps limitation, ...
-```
-
-观察客户端的输出:
-
-```bash
-error: The request is rejected and doesn't have any default value.
-```
\ No newline at end of file
diff --git a/compatibility/filter/tpslimit/go-client/conf/dubbogo.yml
b/compatibility/filter/tpslimit/go-client/conf/dubbogo.yml
deleted file mode 100644
index 78e76bb6..00000000
--- a/compatibility/filter/tpslimit/go-client/conf/dubbogo.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-# dubbo client yaml configure file
-
-dubbo:
- registries:
- demoZK:
- protocol: zookeeper
- timeout: 3s
- address: 127.0.0.1:2181
- consumer:
- request_timeout: 3s
- connect_timeout: 3s
- references:
- UserProvider:
- retries: 0
- protocol: dubbo
- interface: org.apache.dubbo.UserProvider
\ No newline at end of file
diff --git a/compatibility/filter/tpslimit/go-server/cmd/server.go
b/compatibility/filter/tpslimit/go-server/cmd/server.go
deleted file mode 100644
index 4898728c..00000000
--- a/compatibility/filter/tpslimit/go-server/cmd/server.go
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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 (
- "os"
- "os/signal"
- "syscall"
- "time"
-)
-
-import (
- "dubbo.apache.org/dubbo-go/v3/config"
- _ "dubbo.apache.org/dubbo-go/v3/filter/tps/strategy"
- _ "dubbo.apache.org/dubbo-go/v3/imports"
-
- hessian "github.com/apache/dubbo-go-hessian2"
-
- "github.com/dubbogo/gost/log/logger"
-)
-
-import (
-
"github.com/apache/dubbo-go-samples/compatibility/filter/tpslimit/go-server/pkg"
-)
-
-var (
- survivalTimeout = int(3e9)
-)
-
-func main() {
- config.SetProviderService(new(pkg.UserProvider))
- hessian.RegisterPOJO(&pkg.User{})
- err := config.Load()
- if err != nil {
- panic(err)
- }
- initSignal()
-}
-
-func initSignal() {
- signals := make(chan os.Signal, 1)
- // It is not possible to block SIGKILL or syscall.SIGSTOP
- signal.Notify(signals, os.Interrupt, syscall.SIGHUP, syscall.SIGQUIT,
syscall.SIGTERM)
- for {
- sig := <-signals
- logger.Infof("get signal %s", sig.String())
- switch sig {
- case syscall.SIGHUP:
- // reload()
- default:
- time.AfterFunc(time.Duration(survivalTimeout), func() {
- logger.Warnf("app exit now by force...")
- os.Exit(1)
- })
-
- // The program exits normally or timeout forcibly exits.
- logger.Infof("provider app exit now...")
- return
- }
- }
-}
diff --git a/compatibility/filter/tpslimit/go-server/conf/dubbogo.yml
b/compatibility/filter/tpslimit/go-server/conf/dubbogo.yml
deleted file mode 100644
index 83da28c4..00000000
--- a/compatibility/filter/tpslimit/go-server/conf/dubbogo.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-# dubbo server yaml configure file
-
-
-dubbo:
- registries:
- demoZK:
- protocol: zookeeper
- timeout: 3s
- address: 127.0.0.1:2181
- protocols:
- dubbo:
- name: dubbo
- port: 20000
- provider:
- services:
- UserProvider:
- interface: org.apache.dubbo.UserProvider
- cluster: failover
- loadbalance: random # load balancing strategy, such as random,
roundrobin, leastactive or consistenthash.
- warmup: 100 # warmup period, in seconds
- tps.limiter: method-service # the Limiter that judge if the TPS overs
the threshold, such as method-service or default
- tps.limit.strategy: fixedWindow # the name of limit strategy, such as
fixedWindow, slidingWindow, default, threadSafeFixedWindow or the strategy name
you customed
- tps.limit.rejected.handler: DefaultValueHandler
- tps.limit.interval: 1000 # the interval time unit is ms
- tps.limit.rate: 3 # the max value in the interval. <0 means that the
service will not be limited.
-
diff --git a/direct/README.md b/direct/README.md
index cb3f30c6..3efc7002 100644
--- a/direct/README.md
+++ b/direct/README.md
@@ -43,7 +43,4 @@ Consumer log:
```
INFO ... direct call response: hello dubbo-go
-```
-
-That's it—this sample shows the minimal code you need to stand up a direct
triple connection with Dubbo-Go.
-
+```
\ No newline at end of file
diff --git a/direct/README_zh.md b/direct/README_zh.md
index 7aff5430..96420e57 100644
--- a/direct/README_zh.md
+++ b/direct/README_zh.md
@@ -43,52 +43,4 @@ INFO ... Direct server received name = dubbo-go
```
INFO ... direct call response: hello dubbo-go
-```
-
-以上就是使用 Dubbo-Go 实现 Triple 直连的全部步骤。
-# Direct 示例(Triple 直连)
-
-在本示例中,Dubbo-Go v3 Triple 服务端直接监听本地端口,客户端通过
`client.WithClientURL("tri://127.0.0.1:20000")`
指定目标地址,完全绕过注册中心,展示最小可运行的点对点调用链路,方便本地调试。
-
-## 目录结构
-
-```
-direct/
-├── proto/ # greet.proto 以及对应的 triple 代码
-├── go-server/ # 提供 greet.GreetService 的服务端
-└── go-client/ # 直接拨号 tri://127.0.0.1:20000 的客户端
-```
-
-## 启动服务端
-
-```bash
-go run go-server/cmd/main.go
-```
-
-服务端监听 `20000` 端口,并实现 `greet.GreetService` 的 `Greet` 方法。
-
-## 启动客户端
-
-```bash
-go run go-client/cmd/main.go
-```
-
-客户端通过 `client.WithClientURL` 配置直连地址,无需任何 yaml 配置,也无需注册中心即可完成调用。
-
-## 预期输出
-
-服务端日志:
-
-```
-INFO ... Direct server received name = dubbo-go
-```
-
-客户端日志:
-
-```
-INFO ... direct call response: hello dubbo-go
-```
-
-以上就是使用 Dubbo-Go 实现 Triple 直连的全部步骤。
-
-
+```
\ No newline at end of file
diff --git a/compatibility/filter/README.md b/filter/README.md
similarity index 69%
rename from compatibility/filter/README.md
rename to filter/README.md
index 653e941e..09b02935 100644
--- a/compatibility/filter/README.md
+++ b/filter/README.md
@@ -1,5 +1,7 @@
# Dubbo-go Filter Samples
+[English](README.md) | [中文](README_zh.md)
+
## Background
Dubbo-go designs and implements the filter mode, which helps the
provider/consumer to process some actions before sending/processing requests.
Dubbo-go has some built-in filter implementations, such as tps limiter, token,
etc., and also supports user-defined implementations filter, please refer to
the custom module.
@@ -26,9 +28,9 @@ Consumer:
For more built-in implementations of filter, please refer to the filter module
of dubbo-go.
-#### 1.2 Filter Confugration
+#### 1.2 Filter Configuration
-Just configure the name of the filter under the corresponding provider or
consumer, refer to Section 2.2.
+Use `server.WithFilter()` for provider side or `client.WithFilter()` for
consumer side. See examples in the token, sentinel, and custom modules.
### 2. Custom Filter
@@ -70,33 +72,32 @@ func (f *MyClientFilter) OnResponse(ctx context.Context,
result protocol.Result,
}
```
-#### 2.2 Filter Confugration
-
-```yaml
-# service config
-dubbo:
- registries:
- demoZK:
- protocol: zookeeper
- timeout: 3s
- address: 127.0.0.1:2181
- consumer:
- filter: myClientFilter
- check: true
- request_timeout: 3s
- connect_timeout: 3s
- references:
- GreeterClientImpl:
- protocol: tri
+#### 2.2 Filter Configuration
+
+For provider side:
+```go
+if err := greet.RegisterGreetServiceHandler(srv, &GreetTripleServer{},
+ server.WithFilter("myServerFilter"),
+); err != nil {
+ panic(err)
+}
+```
+
+For consumer side:
+```go
+svc, err := greet.NewGreetService(cli, client.WithFilter("myClientFilter"))
+if err != nil {
+ panic(err)
+}
```
-### 3. Running
+## Examples
-See [HOWTO.md](../HOWTO_en.md) in the root directory to run this example.
+This directory contains the following filter examples:
-Observe the output of the client:
+- **custom**: Custom filter implementation example (client and server)
+- **token**: Token filter example
+- **sentinel**: Sentinel filter example for flow control and circuit breaking
+- **polaris/limit**: Polaris TPS limiter example
+- **tpslimit**: Custom TPS limit strategy and rejected execution handler
example
-```bash
-MyClientFilter Invoke is called, method Name = SayHello
-MyClientFilter OnResponse is called
-```
\ No newline at end of file
diff --git a/compatibility/filter/README_zh.md b/filter/README_zh.md
similarity index 70%
rename from compatibility/filter/README_zh.md
rename to filter/README_zh.md
index 92c2d60f..567f37b8 100644
--- a/compatibility/filter/README_zh.md
+++ b/filter/README_zh.md
@@ -1,5 +1,7 @@
# Filter 示例
+[English](README.md) | [中文](README_zh.md)
+
## 背景
Dubbo-go 设计实现了过滤器模式,帮助客户端/服务端在发送/处理请求前置处理一些动作,dubbo-go 内置了一些过滤器实现,如 tps
limiter、token 等,也支持用户自定义实现 filter,可参考 custom 模块。
@@ -26,7 +28,7 @@ Consumer 端:
更多 filter 内置实现可参考 dubbo-go 的 filter 模块。
#### 1.2 Filter 配置
-只需在对应 provider 或 consumer 下配置该 filter 的名字即可,参考 2.2 节。
+在服务端使用 `server.WithFilter()`,在客户端使用 `client.WithFilter()`。可参考 token、sentinel 和
custom 模块的示例。
### 2. 自定义 Filter
以 Client 端为例,更具体的代码参考 custom 模块。
@@ -69,31 +71,30 @@ func (f *MyClientFilter) OnResponse(ctx context.Context,
result protocol.Result,
#### 2.2 Filter 配置
-```yaml
-# service config
-dubbo:
- registries:
- demoZK:
- protocol: zookeeper
- timeout: 3s
- address: 127.0.0.1:2181
- consumer:
- filter: myClientFilter
- check: true
- request_timeout: 3s
- connect_timeout: 3s
- references:
- GreeterClientImpl:
- protocol: tri
+服务端配置:
+```go
+if err := greet.RegisterGreetServiceHandler(srv, &GreetTripleServer{},
+ server.WithFilter("myServerFilter"),
+); err != nil {
+ panic(err)
+}
+```
+
+客户端配置:
+```go
+svc, err := greet.NewGreetService(cli, client.WithFilter("myClientFilter"))
+if err != nil {
+ panic(err)
+}
```
-### 3. 运行
+## 示例
-请参阅根目录中的 [HOWTO.md](../../HOWTO_zh.md) 来运行本例。
+本目录包含以下过滤器示例:
-观察客户端的输出:
+- **custom**: 自定义过滤器实现示例(客户端和服务端)
+- **token**: Token 过滤器示例
+- **sentinel**: Sentinel 过滤器示例(流量控制和熔断)
+- **polaris/limit**: Polaris TPS 限流器示例
+- **tpslimit**: 自定义 TPS 限流策略和拒绝执行处理器示例
-```bash
-MyClientFilter Invoke is called, method Name = SayHello
-MyClientFilter OnResponse is called
-```
\ No newline at end of file
diff --git a/filter/custom/README.md b/filter/custom/README.md
new file mode 100644
index 00000000..7af9789a
--- /dev/null
+++ b/filter/custom/README.md
@@ -0,0 +1,150 @@
+# Custom Filter Sample
+
+[English](README.md) | [中文](README_zh.md)
+
+## Background
+
+This example demonstrates how to implement custom filters in dubbo-go. Custom
filters allow you to intercept and process requests/responses on both the
client and server sides.
+
+## Implementation
+
+### 1. Implement Custom Filter
+
+Implement the `Filter` interface:
+
+```go
+type Filter interface {
+ Invoke(context.Context, protocol.Invoker, protocol.Invocation)
protocol.Result
+ OnResponse(context.Context, protocol.Result, protocol.Invoker,
protocol.Invocation) protocol.Result
+}
+```
+
+### 2. Register Filter
+
+Register your custom filter using `extension.SetFilter()` in the `init()`
function:
+
+**Client Filter** (`go-client/filter/myfilter.go`):
+```go
+func init() {
+ extension.SetFilter("myClientFilter", NewMyClientFilter)
+}
+
+func NewMyClientFilter() filter.Filter {
+ return &MyClientFilter{}
+}
+
+type MyClientFilter struct {
+}
+
+func (f *MyClientFilter) Invoke(ctx context.Context, invoker protocol.Invoker,
invocation protocol.Invocation) protocol.Result {
+ fmt.Println("MyClientFilter Invoke is called, method Name = ",
invocation.MethodName())
+ invocation.SetAttachment("request-key1", "request-value1")
+ invocation.SetAttachment("request-key2", []string{"request-value2.1",
"request-value2.2"})
+ return invoker.Invoke(ctx, invocation)
+}
+
+func (f *MyClientFilter) OnResponse(ctx context.Context, result
protocol.Result, invoker protocol.Invoker, protocol protocol.Invocation)
protocol.Result {
+ fmt.Println("MyClientFilter OnResponse is called")
+ fmt.Println("result attachment = ", result.Attachments())
+ return result
+}
+```
+
+**Server Filter** (`go-server/filter/myfilter.go`):
+```go
+func init() {
+ extension.SetFilter("myServerFilter", NewMyServerFilter)
+}
+
+func NewMyServerFilter() filter.Filter {
+ return &MyServerFilter{}
+}
+
+type MyServerFilter struct {
+}
+
+func (f *MyServerFilter) Invoke(ctx context.Context, invoker protocol.Invoker,
invocation protocol.Invocation) protocol.Result {
+ fmt.Println("MyServerFilter Invoke is called, method Name = ",
invocation.MethodName())
+ fmt.Printf("request attachments = %s\n", invocation.Attachments())
+ return invoker.Invoke(ctx, invocation)
+}
+
+func (f *MyServerFilter) OnResponse(ctx context.Context, result
protocol.Result, invoker protocol.Invoker, protocol protocol.Invocation)
protocol.Result {
+ fmt.Println("MyServerFilter OnResponse is called")
+ myAttachmentMap := make(map[string]interface{})
+ myAttachmentMap["key1"] = "value1"
+ myAttachmentMap["key2"] = []string{"value1", "value2"}
+ result.SetAttachments(myAttachmentMap)
+ return result
+}
+```
+
+### 3. Use Custom Filter
+
+**Client Side** (`go-client/cmd/main.go`):
+```go
+import (
+ _ "github.com/apache/dubbo-go-samples/filter/custom/go-client/filter"
+ "dubbo.apache.org/dubbo-go/v3/client"
+ // ...
+)
+
+svc, err := greet.NewGreetService(cli, client.WithFilter("myClientFilter"))
+```
+
+**Server Side** (`go-server/cmd/main.go`):
+```go
+import (
+ _ "github.com/apache/dubbo-go-samples/filter/custom/go-server/filter"
+ "dubbo.apache.org/dubbo-go/v3/server"
+ // ...
+)
+
+if err := greet.RegisterGreetServiceHandler(srv, &GreetTripleServer{},
+ server.WithFilter("myServerFilter"),
+); err != nil {
+ panic(err)
+}
+```
+
+## Running
+
+### Prerequisites
+
+1. Start Zookeeper (default: `127.0.0.1:2181`)
+
+### Run Server
+
+```shell
+go run ./go-server/cmd/main.go
+```
+
+### Run Client
+
+```shell
+go run ./go-client/cmd/main.go
+```
+
+## Expected Output
+
+**Client Output:**
+```bash
+MyClientFilter Invoke is called, method Name = Greet
+MyClientFilter OnResponse is called
+result attachment = map[key1:value1 key2:[value1 value2]]
+Greet response: hello world
+```
+
+**Server Output:**
+```bash
+MyServerFilter Invoke is called, method Name = Greet
+request attachments = map[request-key1:request-value1
request-key2:[request-value2.1 request-value2.2]]
+MyServerFilter OnResponse is called
+```
+
+## Notes
+
+- The filter implementation must be in a separate package to avoid import
cycles
+- Import the filter package with `_` to trigger the `init()` function
+- Filters can modify request attachments in `Invoke()` and response
attachments in `OnResponse()`
+
diff --git a/filter/custom/README_zh.md b/filter/custom/README_zh.md
new file mode 100644
index 00000000..65246917
--- /dev/null
+++ b/filter/custom/README_zh.md
@@ -0,0 +1,150 @@
+# 自定义 Filter 示例
+
+[English](README.md) | [中文](README_zh.md)
+
+## 背景
+
+本示例演示了如何在 dubbo-go 中实现自定义过滤器。自定义过滤器允许您在客户端和服务端拦截和处理请求/响应。
+
+## 实现方法
+
+### 1. 实现自定义 Filter
+
+实现 `Filter` 接口:
+
+```go
+type Filter interface {
+ Invoke(context.Context, protocol.Invoker, protocol.Invocation)
protocol.Result
+ OnResponse(context.Context, protocol.Result, protocol.Invoker,
protocol.Invocation) protocol.Result
+}
+```
+
+### 2. 注册 Filter
+
+在 `init()` 函数中使用 `extension.SetFilter()` 注册您的自定义过滤器:
+
+**客户端 Filter** (`go-client/filter/myfilter.go`):
+```go
+func init() {
+ extension.SetFilter("myClientFilter", NewMyClientFilter)
+}
+
+func NewMyClientFilter() filter.Filter {
+ return &MyClientFilter{}
+}
+
+type MyClientFilter struct {
+}
+
+func (f *MyClientFilter) Invoke(ctx context.Context, invoker protocol.Invoker,
invocation protocol.Invocation) protocol.Result {
+ fmt.Println("MyClientFilter Invoke is called, method Name = ",
invocation.MethodName())
+ invocation.SetAttachment("request-key1", "request-value1")
+ invocation.SetAttachment("request-key2", []string{"request-value2.1",
"request-value2.2"})
+ return invoker.Invoke(ctx, invocation)
+}
+
+func (f *MyClientFilter) OnResponse(ctx context.Context, result
protocol.Result, invoker protocol.Invoker, protocol protocol.Invocation)
protocol.Result {
+ fmt.Println("MyClientFilter OnResponse is called")
+ fmt.Println("result attachment = ", result.Attachments())
+ return result
+}
+```
+
+**服务端 Filter** (`go-server/filter/myfilter.go`):
+```go
+func init() {
+ extension.SetFilter("myServerFilter", NewMyServerFilter)
+}
+
+func NewMyServerFilter() filter.Filter {
+ return &MyServerFilter{}
+}
+
+type MyServerFilter struct {
+}
+
+func (f *MyServerFilter) Invoke(ctx context.Context, invoker protocol.Invoker,
invocation protocol.Invocation) protocol.Result {
+ fmt.Println("MyServerFilter Invoke is called, method Name = ",
invocation.MethodName())
+ fmt.Printf("request attachments = %s\n", invocation.Attachments())
+ return invoker.Invoke(ctx, invocation)
+}
+
+func (f *MyServerFilter) OnResponse(ctx context.Context, result
protocol.Result, invoker protocol.Invoker, protocol protocol.Invocation)
protocol.Result {
+ fmt.Println("MyServerFilter OnResponse is called")
+ myAttachmentMap := make(map[string]interface{})
+ myAttachmentMap["key1"] = "value1"
+ myAttachmentMap["key2"] = []string{"value1", "value2"}
+ result.SetAttachments(myAttachmentMap)
+ return result
+}
+```
+
+### 3. 使用自定义 Filter
+
+**客户端** (`go-client/cmd/main.go`):
+```go
+import (
+ _ "github.com/apache/dubbo-go-samples/filter/custom/go-client/filter"
+ "dubbo.apache.org/dubbo-go/v3/client"
+ // ...
+)
+
+svc, err := greet.NewGreetService(cli, client.WithFilter("myClientFilter"))
+```
+
+**服务端** (`go-server/cmd/main.go`):
+```go
+import (
+ _ "github.com/apache/dubbo-go-samples/filter/custom/go-server/filter"
+ "dubbo.apache.org/dubbo-go/v3/server"
+ // ...
+)
+
+if err := greet.RegisterGreetServiceHandler(srv, &GreetTripleServer{},
+ server.WithFilter("myServerFilter"),
+); err != nil {
+ panic(err)
+}
+```
+
+## 运行方法
+
+### 前置条件
+
+1. 启动 Zookeeper(默认:`127.0.0.1:2181`)
+
+### 启动服务端
+
+```shell
+go run ./go-server/cmd/main.go
+```
+
+### 启动客户端
+
+```shell
+go run ./go-client/cmd/main.go
+```
+
+## 预期输出
+
+**客户端输出:**
+```bash
+MyClientFilter Invoke is called, method Name = Greet
+MyClientFilter OnResponse is called
+result attachment = map[key1:value1 key2:[value1 value2]]
+Greet response: hello world
+```
+
+**服务端输出:**
+```bash
+MyServerFilter Invoke is called, method Name = Greet
+request attachments = map[request-key1:request-value1
request-key2:[request-value2.1 request-value2.2]]
+MyServerFilter OnResponse is called
+```
+
+## 注意事项
+
+- 过滤器实现必须在单独的包中,以避免导入循环
+- 使用 `_` 导入过滤器包以触发 `init()` 函数
+- 过滤器可以在 `Invoke()` 中修改请求附件,在 `OnResponse()` 中修改响应附件
+
diff --git a/compatibility/filter/custom/go-client/cmd/client.go
b/filter/custom/go-client/cmd/main.go
similarity index 57%
copy from compatibility/filter/custom/go-client/cmd/client.go
copy to filter/custom/go-client/cmd/main.go
index 57fd838c..c1290441 100644
--- a/compatibility/filter/custom/go-client/cmd/client.go
+++ b/filter/custom/go-client/cmd/main.go
@@ -22,32 +22,44 @@ import (
)
import (
- "dubbo.apache.org/dubbo-go/v3/config"
+ "dubbo.apache.org/dubbo-go/v3"
+ "dubbo.apache.org/dubbo-go/v3/client"
_ "dubbo.apache.org/dubbo-go/v3/imports"
+ "dubbo.apache.org/dubbo-go/v3/registry"
"github.com/dubbogo/gost/log/logger"
)
import (
- "github.com/apache/dubbo-go-samples/compatibility/api"
+ _ "github.com/apache/dubbo-go-samples/filter/custom/go-client/filter"
+ greet "github.com/apache/dubbo-go-samples/filter/proto"
)
-var userProvider = &api.GreeterClientImpl{}
-
-func init() {
- config.SetConsumerService(userProvider)
-}
-
func main() {
- err := config.Load()
+ ins, err := dubbo.NewInstance(
+ dubbo.WithName("dubbo_filter_custom_client"),
+ dubbo.WithRegistry(
+ registry.WithZookeeper(),
+ registry.WithAddress("127.0.0.1:2181"),
+ ),
+ )
+ if err != nil {
+ panic(err)
+ }
+ cli, err := ins.NewClient()
if err != nil {
panic(err)
}
- logger.Infof("\n\n\nstart to test")
- user, err := userProvider.SayHello(context.TODO(),
&api.HelloRequest{Name: "laurence"})
+ svc, err := greet.NewGreetService(cli,
client.WithFilter("myClientFilter"))
if err != nil {
panic(err)
}
- logger.Infof("get user = %+v", user)
+
+ resp, err := svc.Greet(context.Background(), &greet.GreetRequest{Name:
"hello world"})
+ if err != nil {
+ logger.Error(err)
+ return
+ }
+ logger.Infof("Greet response: %s", resp.Greeting)
}
diff --git a/compatibility/filter/custom/go-client/cmd/myfilter.go
b/filter/custom/go-client/filter/myfilter.go
similarity index 99%
rename from compatibility/filter/custom/go-client/cmd/myfilter.go
rename to filter/custom/go-client/filter/myfilter.go
index 3af9a97b..b47b02c3 100644
--- a/compatibility/filter/custom/go-client/cmd/myfilter.go
+++ b/filter/custom/go-client/filter/myfilter.go
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package main
+package filter
import (
"context"
diff --git a/compatibility/filter/custom/go-client/cmd/client.go
b/filter/custom/go-server/cmd/main.go
similarity index 50%
rename from compatibility/filter/custom/go-client/cmd/client.go
rename to filter/custom/go-server/cmd/main.go
index 57fd838c..1ccc6053 100644
--- a/compatibility/filter/custom/go-client/cmd/client.go
+++ b/filter/custom/go-server/cmd/main.go
@@ -22,32 +22,56 @@ import (
)
import (
- "dubbo.apache.org/dubbo-go/v3/config"
+ "dubbo.apache.org/dubbo-go/v3"
_ "dubbo.apache.org/dubbo-go/v3/imports"
+ "dubbo.apache.org/dubbo-go/v3/protocol"
+ "dubbo.apache.org/dubbo-go/v3/registry"
+ "dubbo.apache.org/dubbo-go/v3/server"
"github.com/dubbogo/gost/log/logger"
)
import (
- "github.com/apache/dubbo-go-samples/compatibility/api"
+ _ "github.com/apache/dubbo-go-samples/filter/custom/go-server/filter"
+ greet "github.com/apache/dubbo-go-samples/filter/proto"
)
-var userProvider = &api.GreeterClientImpl{}
+type GreetTripleServer struct {
+}
-func init() {
- config.SetConsumerService(userProvider)
+func (srv *GreetTripleServer) Greet(ctx context.Context, req
*greet.GreetRequest) (*greet.GreetResponse, error) {
+ resp := &greet.GreetResponse{Greeting: req.Name}
+ return resp, nil
}
func main() {
- err := config.Load()
+ ins, err := dubbo.NewInstance(
+ dubbo.WithName("dubbo_filter_custom_server"),
+ dubbo.WithRegistry(
+ registry.WithZookeeper(),
+ registry.WithAddress("127.0.0.1:2181"),
+ ),
+ dubbo.WithProtocol(
+ protocol.WithTriple(),
+ protocol.WithPort(20000),
+ ),
+ )
if err != nil {
panic(err)
}
- logger.Infof("\n\n\nstart to test")
- user, err := userProvider.SayHello(context.TODO(),
&api.HelloRequest{Name: "laurence"})
+ srv, err := ins.NewServer()
if err != nil {
panic(err)
}
- logger.Infof("get user = %+v", user)
+
+ if err := greet.RegisterGreetServiceHandler(srv, &GreetTripleServer{},
+ server.WithFilter("myServerFilter"),
+ ); err != nil {
+ panic(err)
+ }
+
+ if err := srv.Serve(); err != nil {
+ logger.Error(err)
+ }
}
diff --git a/compatibility/filter/custom/go-server/cmd/myfilter.go
b/filter/custom/go-server/filter/myfilter.go
similarity index 99%
rename from compatibility/filter/custom/go-server/cmd/myfilter.go
rename to filter/custom/go-server/filter/myfilter.go
index b0472757..0e2b0cb0 100644
--- a/compatibility/filter/custom/go-server/cmd/myfilter.go
+++ b/filter/custom/go-server/filter/myfilter.go
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package main
+package filter
import (
"context"
diff --git a/filter/tpslimit/README.md b/filter/tpslimit/README.md
new file mode 100644
index 00000000..5ce96c39
--- /dev/null
+++ b/filter/tpslimit/README.md
@@ -0,0 +1,84 @@
+# TPSLimit Filter Sample
+
+[English](README.md) | [中文](README_zh.md)
+
+### Background
+
+Dubbo-go has a built in filter for limiting TPS purpose - "tpslimit". It can
be enabled by configuring on the provider side, furthermore, user can customize
the TPS limit strategy and the return value after the request is rejected.
+
+### Example
+
+##### 1. Code
+
+A) Customize TPS limit strategy:
+
+To customize TPS limit strategy, the interface "filter.TpsLimitStrategy" is
needed to implement. In this example, the strategy is implemented as randomly
rejecting the incoming request. Examples are linked as follows:
[limit_strategy.go](go-server/pkg/limit_strategy.go)
+
+B) Customize execution handler when the request is rejected.
+
+Implement the interface "filter.RejectedExecutionHandler" to customize the
return result to the client when the request is rejected. In this example, when
the TPS limit criteria meets, the customized execution handler will return the
error "The request is rejected and doesn't have any default value." back to the
consumer. Examples are linked as follows:
[reject_handler.go](go-server/pkg/reject_handler.go)
+
+##### 2. Configuration
+
+Enable tpslimit filter in provider's code using v3 API:
+
+```go
+import "dubbo.apache.org/dubbo-go/v3/config"
+
+if err := greet.RegisterGreetServiceHandler(srv, &GreetTripleServer{},
+ server.WithTpsLimiter("method-service"),
+ server.WithMethod(
+ config.WithName("Greet"),
+ config.WithTpsLimitRate(5), // must be >0, otherwise the
limiter falls back to the default -1 and gets ignored
+ config.WithTpsLimitInterval(1000), // ms
+ config.WithTpsLimitStrategy("RandomLimitStrategy"),
+ ),
+ server.WithTpsLimitRejectedHandler("DefaultValueHandler"),
+); err != nil {
+ panic(err)
+}
+```
+
+> **Note**: Only configuring `tps.limit.rate` at the service level may be
overridden by the Provider defaults (which set `-1`). Declaring the TPS options
via `server.WithMethod` guarantees `greet.GreetService#Greet` receives a
positive rate and interval so that the limiter actually works.
+
+The custom TPS limit strategy and rejected execution handler are registered
via `extension.SetTpsLimitStrategy()` and
`extension.SetRejectedExecutionHandler()` in the `init()` function of the
respective packages.
+
+##### 3. Run
+
+### Prerequisites
+
+1. Start Zookeeper (default: `127.0.0.1:2181`)
+
+### Run Server
+
+```shell
+go run ./go-server/cmd/main.go
+```
+
+### Run Client
+
+```shell
+go run ./go-client/cmd/main.go
+```
+
+## Expected Output
+
+**Server Output:**
+
+```bash
+Random IsAllowable!
+ERROR The invocation was rejected due to over the tps limitation, ...
+```
+
+**Client Output:**
+
+```bash
+start to test tpslimit
+error: The request is rejected and doesn't have any default value.
+response: hello world
+...
+successCount=<number>, failCount=<number>
+```
+
+The client will send 60 requests with 200ms intervals. Some requests will be
rejected by the TPS limiter, and you'll see both success and failure counts in
the final output.
+
diff --git a/filter/tpslimit/README_zh.md b/filter/tpslimit/README_zh.md
new file mode 100644
index 00000000..b1a1c977
--- /dev/null
+++ b/filter/tpslimit/README_zh.md
@@ -0,0 +1,84 @@
+# TPSLimit Filter 示例
+
+[English](README.md) | [中文](README_zh.md)
+
+### 背景
+
+Dubbo-go 内置了限流 filter "tpslimit"。可以通过在服务端的配置来激活,另外,用户还可以自定义限流策略和拒绝访问后的处理逻辑。
+
+### 示例
+
+##### 1. 代码
+
+A) 自定义限流策略:
+
+通过实现 filter.TpsLimitStrategy
来自定义限流策略。在本例中,采取的策略是随机限流。例子链接为:[limit_strategy.go](go-server/pkg/limit_strategy.go)
+
+B) 自定义拒绝访问处理:
+
+通过实现 filter.RejectedExecutionHandler。在本例中,当限流条件满足的情况下,拒绝访问的自定义处理逻辑将会返回 "The
request is rejected and doesn't have any default value. "
的错误给客户端。例子链接为:[reject_handler.go](go-server/pkg/reject_handler.go)
+
+##### 2. 配置
+
+在服务端代码中使用 v3 API 启用 tpslimit filter:
+
+```go
+import "dubbo.apache.org/dubbo-go/v3/config"
+
+if err := greet.RegisterGreetServiceHandler(srv, &GreetTripleServer{},
+ server.WithTpsLimiter("method-service"),
+ server.WithMethod(
+ config.WithName("Greet"),
+ config.WithTpsLimitRate(5), // 需要配置为正数,否则默认值 -1 会导致限流器被忽略
+ config.WithTpsLimitInterval(1000), // 单位 ms
+ config.WithTpsLimitStrategy("RandomLimitStrategy"),
+ ),
+ server.WithTpsLimitRejectedHandler("DefaultValueHandler"),
+); err != nil {
+ panic(err)
+}
+```
+
+> **注意**:如果只在服务级别设置 `tps.limit.rate`,Provider 默认配置可能会覆盖该值为 `-1`。因此示例通过
`server.WithMethod` 在方法级别写入正确的速率与时间窗口,确保 `greet.GreetService#Greet` 能被限流。
+
+自定义的 TPS 限流策略和拒绝执行处理器通过各自包的 `init()` 函数中的 `extension.SetTpsLimitStrategy()` 和
`extension.SetRejectedExecutionHandler()` 进行注册。
+
+##### 3. 运行
+
+### 前置条件
+
+1. 启动 Zookeeper(默认地址:`127.0.0.1:2181`)
+
+### 运行服务端
+
+```shell
+go run ./go-server/cmd/main.go
+```
+
+### 运行客户端
+
+```shell
+go run ./go-client/cmd/main.go
+```
+
+## 预期输出
+
+**服务端输出:**
+
+```bash
+Random IsAllowable!
+ERROR The invocation was rejected due to over the tps limitation, ...
+```
+
+**客户端输出:**
+
+```bash
+start to test tpslimit
+error: The request is rejected and doesn't have any default value.
+response: hello world
+...
+successCount=<数量>, failCount=<数量>
+```
+
+客户端将发送 60 个请求,每个请求间隔 200ms。部分请求会被 TPS 限流器拒绝,最终输出中会显示成功和失败的请求数量。
+
diff --git a/compatibility/filter/tpslimit/go-client/cmd/client.go
b/filter/tpslimit/go-client/cmd/main.go
similarity index 63%
rename from compatibility/filter/tpslimit/go-client/cmd/client.go
rename to filter/tpslimit/go-client/cmd/main.go
index 795c4bd5..f40385aa 100644
--- a/compatibility/filter/tpslimit/go-client/cmd/client.go
+++ b/filter/tpslimit/go-client/cmd/main.go
@@ -23,43 +23,50 @@ import (
)
import (
- "dubbo.apache.org/dubbo-go/v3/config"
+ "dubbo.apache.org/dubbo-go/v3"
_ "dubbo.apache.org/dubbo-go/v3/imports"
-
- hessian "github.com/apache/dubbo-go-hessian2"
+ "dubbo.apache.org/dubbo-go/v3/registry"
"github.com/dubbogo/gost/log/logger"
)
import (
-
"github.com/apache/dubbo-go-samples/compatibility/filter/tpslimit/go-client/pkg"
+ greet "github.com/apache/dubbo-go-samples/filter/proto"
)
-var userProvider = &pkg.UserProvider{}
-
-func init() {
- config.SetConsumerService(userProvider)
- hessian.RegisterPOJO(&pkg.User{})
-}
-
func main() {
- err := config.Load()
+ ins, err := dubbo.NewInstance(
+ dubbo.WithName("dubbo_filter_tpslimit_client"),
+ dubbo.WithRegistry(
+ registry.WithZookeeper(),
+ registry.WithAddress("127.0.0.1:2181"),
+ ),
+ )
+ if err != nil {
+ panic(err)
+ }
+ cli, err := ins.NewClient()
+ if err != nil {
+ panic(err)
+ }
+
+ svc, err := greet.NewGreetService(cli)
if err != nil {
panic(err)
}
var successCount, failCount int64
- logger.Infof("\n\n\nstart to test dubbo")
+ logger.Infof("\n\n\nstart to test tpslimit")
for i := 0; i < 60; i++ {
time.Sleep(200 * time.Millisecond)
- user, err := userProvider.GetUser(context.TODO(), "A001")
+ resp, err := svc.Greet(context.Background(),
&greet.GreetRequest{Name: "hello world"})
if err != nil {
failCount++
logger.Infof("error: %v\n", err)
} else {
successCount++
+ logger.Infof("response: %v\n", resp.Greeting)
}
- logger.Infof("response: %v\n", user)
}
- logger.Infof("failCount=%v, failCount=%v\n", successCount, failCount)
+ logger.Infof("successCount=%v, failCount=%v\n", successCount, failCount)
}
diff --git a/compatibility/filter/tpslimit/go-client/pkg/user.go
b/filter/tpslimit/go-client/pkg/user.go
similarity index 100%
rename from compatibility/filter/tpslimit/go-client/pkg/user.go
rename to filter/tpslimit/go-client/pkg/user.go
diff --git a/filter/tpslimit/go-server/cmd/main.go
b/filter/tpslimit/go-server/cmd/main.go
new file mode 100644
index 00000000..f13c16d7
--- /dev/null
+++ b/filter/tpslimit/go-server/cmd/main.go
@@ -0,0 +1,85 @@
+/*
+ * 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"
+)
+
+import (
+ "dubbo.apache.org/dubbo-go/v3"
+ "dubbo.apache.org/dubbo-go/v3/config"
+ _ "dubbo.apache.org/dubbo-go/v3/imports"
+ "dubbo.apache.org/dubbo-go/v3/protocol"
+ "dubbo.apache.org/dubbo-go/v3/registry"
+ "dubbo.apache.org/dubbo-go/v3/server"
+
+ "github.com/dubbogo/gost/log/logger"
+)
+
+import (
+ greet "github.com/apache/dubbo-go-samples/filter/proto"
+ _ "github.com/apache/dubbo-go-samples/filter/tpslimit/go-server/pkg"
+)
+
+type GreetTripleServer struct {
+}
+
+func (srv *GreetTripleServer) Greet(ctx context.Context, req
*greet.GreetRequest) (*greet.GreetResponse, error) {
+ resp := &greet.GreetResponse{Greeting: req.Name}
+ return resp, nil
+}
+
+func main() {
+ ins, err := dubbo.NewInstance(
+ dubbo.WithName("dubbo_filter_tpslimit_server"),
+ dubbo.WithRegistry(
+ registry.WithZookeeper(),
+ registry.WithAddress("127.0.0.1:2181"),
+ ),
+ dubbo.WithProtocol(
+ protocol.WithTriple(),
+ protocol.WithPort(20000),
+ ),
+ )
+ if err != nil {
+ panic(err)
+ }
+
+ srv, err := ins.NewServer()
+ if err != nil {
+ panic(err)
+ }
+
+ if err := greet.RegisterGreetServiceHandler(srv, &GreetTripleServer{},
+ server.WithTpsLimiter("method-service"),
+ server.WithMethod(
+ config.WithName("Greet"),
+ config.WithTpsLimitRate(5),
+ config.WithTpsLimitInterval(1000),
+ config.WithTpsLimitStrategy("RandomLimitStrategy"),
+ ),
+ server.WithTpsLimitRejectedHandler("DefaultValueHandler"),
+ ); err != nil {
+ panic(err)
+ }
+
+ if err := srv.Serve(); err != nil {
+ logger.Error(err)
+ }
+}
diff --git a/compatibility/filter/tpslimit/go-server/pkg/limit_strategy.go
b/filter/tpslimit/go-server/pkg/limit_strategy.go
similarity index 100%
rename from compatibility/filter/tpslimit/go-server/pkg/limit_strategy.go
rename to filter/tpslimit/go-server/pkg/limit_strategy.go
diff --git a/compatibility/filter/tpslimit/go-server/pkg/reject_handler.go
b/filter/tpslimit/go-server/pkg/reject_handler.go
similarity index 100%
rename from compatibility/filter/tpslimit/go-server/pkg/reject_handler.go
rename to filter/tpslimit/go-server/pkg/reject_handler.go
diff --git a/compatibility/filter/tpslimit/go-server/pkg/user.go
b/filter/tpslimit/go-server/pkg/user.go
similarity index 100%
rename from compatibility/filter/tpslimit/go-server/pkg/user.go
rename to filter/tpslimit/go-server/pkg/user.go
diff --git
a/integrate_test/compatibility/filter/custom/tests/integration/myfilter.go
b/integrate_test/compatibility/filter/custom/tests/integration/myfilter.go
deleted file mode 100644
index 5d47b5fc..00000000
--- a/integrate_test/compatibility/filter/custom/tests/integration/myfilter.go
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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 integration
-
-import (
- "context"
- "fmt"
-)
-
-import (
- "dubbo.apache.org/dubbo-go/v3/common/extension"
- "dubbo.apache.org/dubbo-go/v3/filter"
- "dubbo.apache.org/dubbo-go/v3/protocol"
-)
-
-func init() {
- extension.SetFilter("myClientFilter", NewMyClientFilter)
-}
-
-func NewMyClientFilter() filter.Filter {
- return &MyClientFilter{}
-}
-
-type MyClientFilter struct {
-}
-
-func (f *MyClientFilter) Invoke(ctx context.Context, invoker protocol.Invoker,
invocation protocol.Invocation) protocol.Result {
- fmt.Println("MyClientFilter Invoke is called, method Name = ",
invocation.MethodName())
- return invoker.Invoke(ctx, invocation)
-}
-func (f *MyClientFilter) OnResponse(ctx context.Context, result
protocol.Result, invoker protocol.Invoker, protocol protocol.Invocation)
protocol.Result {
- fmt.Println("MyClientFilter OnResponse is called")
- return result
-}
diff --git
a/integrate_test/compatibility/filter/custom/tests/integration/userprovider_test.go
b/integrate_test/compatibility/filter/custom/tests/integration/userprovider_test.go
deleted file mode 100644
index 9efe85a9..00000000
---
a/integrate_test/compatibility/filter/custom/tests/integration/userprovider_test.go
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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 integration
-
-import (
- "context"
- "testing"
-)
-
-import (
- "github.com/stretchr/testify/assert"
-)
-
-import (
- "github.com/apache/dubbo-go-samples/compatibility/api"
-)
-
-func TestGetUser(t *testing.T) {
- user, err := userProvider.SayHello(context.TODO(),
&api.HelloRequest{Name: "laurence"})
- assert.Nil(t, err)
- assert.Equal(t, "12345", user.Id)
- assert.Equal(t, "Hello laurence", user.Name)
- assert.Equal(t, int32(21), user.Age)
-}
diff --git a/integrate_test/filter/custom/tests/integration/assert_filter.go
b/integrate_test/filter/custom/tests/integration/assert_filter.go
new file mode 100644
index 00000000..e9880cd3
--- /dev/null
+++ b/integrate_test/filter/custom/tests/integration/assert_filter.go
@@ -0,0 +1,80 @@
+/*
+ * 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 integration
+
+import (
+ "context"
+ "sync"
+)
+
+import (
+ "dubbo.apache.org/dubbo-go/v3/common/extension"
+ "dubbo.apache.org/dubbo-go/v3/filter"
+ "dubbo.apache.org/dubbo-go/v3/protocol"
+)
+
+const (
+ clientAssertFilterName = "customIntegrationAssertFilter"
+)
+
+var (
+ requestAttachmentCh = make(chan map[string]interface{}, 1)
+ responseAttachmentCh = make(chan map[string]interface{}, 1)
+ once sync.Once
+)
+
+func init() {
+ once.Do(func() {
+ extension.SetFilter(clientAssertFilterName,
newCustomIntegrationAssertFilter)
+ })
+}
+
+func newCustomIntegrationAssertFilter() filter.Filter {
+ return &customIntegrationAssertFilter{}
+}
+
+type customIntegrationAssertFilter struct{}
+
+func (f *customIntegrationAssertFilter) Invoke(ctx context.Context, invoker
protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+ attachments := cloneAttachment(invocation.Attachments())
+ select {
+ case requestAttachmentCh <- attachments:
+ default:
+ }
+ return invoker.Invoke(ctx, invocation)
+}
+
+func (f *customIntegrationAssertFilter) OnResponse(ctx context.Context, result
protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation)
protocol.Result {
+ attachments := cloneAttachment(result.Attachments())
+ select {
+ case responseAttachmentCh <- attachments:
+ default:
+ }
+ return result
+}
+
+func cloneAttachment(src map[string]interface{}) map[string]interface{} {
+ if src == nil {
+ return map[string]interface{}{}
+ }
+ dst := make(map[string]interface{}, len(src))
+ for k, v := range src {
+ dst[k] = v
+ }
+ return dst
+}
diff --git
a/integrate_test/filter/custom/tests/integration/custom_filter_test.go
b/integrate_test/filter/custom/tests/integration/custom_filter_test.go
new file mode 100644
index 00000000..164d56b0
--- /dev/null
+++ b/integrate_test/filter/custom/tests/integration/custom_filter_test.go
@@ -0,0 +1,89 @@
+/*
+ * 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 integration
+
+import (
+ "context"
+ "testing"
+ "time"
+)
+
+import (
+ "github.com/stretchr/testify/require"
+)
+
+import (
+ greet "github.com/apache/dubbo-go-samples/filter/proto"
+)
+
+func TestCustomFilter_AttachmentsFlow(t *testing.T) {
+ drainAttachmentChannel(requestAttachmentCh)
+ drainAttachmentChannel(responseAttachmentCh)
+
+ req := &greet.GreetRequest{Name: "integration-custom-filter"}
+ resp, err := greetService.Greet(context.Background(), req)
+ require.NoError(t, err)
+ require.Equal(t, req.Name, resp.Greeting)
+
+ reqAttachment := waitAttachment(t, requestAttachmentCh)
+ requireAttachmentValues(t, reqAttachment, "request-key1",
[]string{"request-value1"})
+ requireAttachmentValues(t, reqAttachment, "request-key2",
[]string{"request-value2.1", "request-value2.2"})
+
+ respAttachment := waitAttachment(t, responseAttachmentCh)
+ requireAttachmentValues(t, respAttachment, "key1", []string{"value1"})
+ requireAttachmentValues(t, respAttachment, "key2", []string{"value1",
"value2"})
+}
+
+func waitAttachment(t *testing.T, ch chan map[string]interface{})
map[string]interface{} {
+ t.Helper()
+ select {
+ case attachment := <-ch:
+ return attachment
+ case <-time.After(3 * time.Second):
+ t.Fatal("timeout waiting for attachment")
+ return nil
+ }
+}
+
+func drainAttachmentChannel(ch chan map[string]interface{}) {
+ for {
+ select {
+ case <-ch:
+ default:
+ return
+ }
+ }
+}
+
+func requireAttachmentValues(t *testing.T, attachments map[string]interface{},
key string, expected []string) {
+ t.Helper()
+ raw, ok := attachments[key]
+ require.Truef(t, ok, "attachment key %s not found", key)
+
+ var actual []string
+ switch v := raw.(type) {
+ case string:
+ actual = []string{v}
+ case []string:
+ actual = v
+ default:
+ t.Fatalf("unexpected attachment type for key %s: %T", key, raw)
+ }
+
+ require.ElementsMatch(t, expected, actual)
+}
diff --git
a/integrate_test/compatibility/filter/custom/tests/integration/main_test.go
b/integrate_test/filter/custom/tests/integration/main_test.go
similarity index 56%
rename from
integrate_test/compatibility/filter/custom/tests/integration/main_test.go
rename to integrate_test/filter/custom/tests/integration/main_test.go
index 05f0ed7a..aea81552 100644
--- a/integrate_test/compatibility/filter/custom/tests/integration/main_test.go
+++ b/integrate_test/filter/custom/tests/integration/main_test.go
@@ -19,23 +19,44 @@ package integration
import (
"os"
+ "strings"
"testing"
)
import (
- "dubbo.apache.org/dubbo-go/v3/config"
+ "dubbo.apache.org/dubbo-go/v3"
+ "dubbo.apache.org/dubbo-go/v3/client"
_ "dubbo.apache.org/dubbo-go/v3/imports"
+ "dubbo.apache.org/dubbo-go/v3/registry"
)
import (
- "github.com/apache/dubbo-go-samples/compatibility/api"
+ _ "github.com/apache/dubbo-go-samples/filter/custom/go-client/filter"
+ greet "github.com/apache/dubbo-go-samples/filter/proto"
)
-var userProvider = &api.GreeterClientImpl{}
+var greetService greet.GreetService
func TestMain(m *testing.M) {
- config.SetConsumerService(userProvider)
- if err := config.Load(); err != nil {
+ ins, err := dubbo.NewInstance(
+ dubbo.WithName("dubbo_filter_custom_client_integration"),
+ dubbo.WithRegistry(
+ registry.WithZookeeper(),
+ registry.WithAddress("127.0.0.1:2181"),
+ ),
+ )
+ if err != nil {
+ panic(err)
+ }
+
+ cli, err := ins.NewClient()
+ if err != nil {
+ panic(err)
+ }
+
+ filterChain := strings.Join([]string{"myClientFilter",
clientAssertFilterName}, ",")
+ greetService, err = greet.NewGreetService(cli,
client.WithFilter(filterChain))
+ if err != nil {
panic(err)
}
diff --git a/start_integrate_test.sh b/start_integrate_test.sh
index 12ba57d6..cf68d181 100755
--- a/start_integrate_test.sh
+++ b/start_integrate_test.sh
@@ -35,9 +35,9 @@ array+=("otel/tracing/otlp_http_exporter")
# direct
array+=("direct")
-# filer
+# filter
array+=("filter/token")
-array+=("compatibility/filter/custom")
+array+=("filter/custom")
# registry
array+=("registry/zookeeper")