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 29a15654 feat: add router static config sample (#1059)
29a15654 is described below
commit 29a1565416a7c6be9259ac55c453d0e4695875e1
Author: Aether <[email protected]>
AuthorDate: Mon Apr 13 12:03:46 2026 +0800
feat: add router static config sample (#1059)
* add router static config sample
* fix(router): exit non-zero when static config consumer invoke fails
* refactor(router): align static router samples with integration layout
* chore(router): add static router samples to integration docs and CI list
* fix: add more attemps to reduce test flakiness
* fix(router): align static tag router key with provider application
---------
Co-authored-by: Aetherance <[email protected]>
---
README.md | 2 +
README_CN.md | 2 +
router/static_config/README.md | 27 ++++++
router/static_config/README_CN.md | 27 ++++++
router/static_config/condition/README.md | 59 ++++++++++++
router/static_config/condition/README_CN.md | 59 ++++++++++++
.../condition/go-client/cmd/client.go | 94 ++++++++++++++++++
.../condition/go-node2-server/cmd/server_node2.go | 76 +++++++++++++++
.../condition/go-server/cmd/server.go | 76 +++++++++++++++
router/static_config/tag/README.md | 78 +++++++++++++++
router/static_config/tag/README_CN.md | 78 +++++++++++++++
router/static_config/tag/go-client/cmd/client.go | 105 +++++++++++++++++++++
router/static_config/tag/go-server/cmd/server.go | 76 +++++++++++++++
.../tag/go-tag-server/cmd/server_tag.go | 77 +++++++++++++++
start_integrate_test.sh | 2 +
15 files changed, 838 insertions(+)
diff --git a/README.md b/README.md
index c7313344..4a30dc51 100644
--- a/README.md
+++ b/README.md
@@ -57,6 +57,8 @@ Please refer to [HOWTO.md](HOWTO.md) for detailed
instructions on running the sa
* `router/condition`: Dubbo-go condition router examples.
* `router/script`: Dubbo-go script router examples.
* `router/polaris`: Quickly experience Polaris' service routing capabilities
in Dubbo-go.
+ * `router/static_config/tag`: Dubbo-go static tag router example.
+ * `router/static_config/condition`: Dubbo-go static condition router example.
* `rpc`: Various RPC protocol examples with Dubbo-go.
* `rpc/dubbo`: Dubbo protocol example, including Java–Go interop.
* `rpc/grpc`: gRPC protocol example.
diff --git a/README_CN.md b/README_CN.md
index 943a0dcc..f5f4bebd 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -57,6 +57,8 @@
* `router/condition`: Dubbo-go 的 condition router 使用示例。
* `router/script`: Dubbo-go 的 script router 使用示例。
* `router/polaris`:在 Dubbo-go 中快速体验北极星的服务路由能力。
+ * `router/static_config/tag`: 静态配置的 tag router 示例。
+ * `router/static_config/condition`: 静态配置的 condition router 示例。
* `rpc`:Dubbo-go 支持的多种 RPC 协议示例。
* `rpc/dubbo`:Dubbo 协议示例,包含 Java–Go 互操作。
* `rpc/grpc`:基于 gRPC 协议的示例。
diff --git a/router/static_config/README.md b/router/static_config/README.md
new file mode 100644
index 00000000..56b52b02
--- /dev/null
+++ b/router/static_config/README.md
@@ -0,0 +1,27 @@
+# Static router configuration
+
+This directory contains static router samples configured directly in code.
+Here, `static_config` means the router rules are injected statically on the
consumer side, instead of being delivered dynamically from a config center.
+
+English | [中文](README_CN.md)
+
+## Prerequisites
+
+- Go 1.25+.
+
+## Sub-samples
+
+- `condition`: service-scope static condition router sample with direct URLs
+- `tag`: application-scope static tag router sample with direct URLs
+
+## How to use
+
+Choose one sub-sample and follow its own README:
+
+- `condition/README.md`
+- `tag/README.md`
+
+The `condition` sample uses direct URLs only.
+The `tag` sample uses direct URLs only.
+Neither sample requires a config center.
+Each sub-sample can be run locally after following its own prerequisites and
setup steps.
diff --git a/router/static_config/README_CN.md
b/router/static_config/README_CN.md
new file mode 100644
index 00000000..f6a9707b
--- /dev/null
+++ b/router/static_config/README_CN.md
@@ -0,0 +1,27 @@
+# 静态路由配置
+
+这个目录用于展示如何在代码中直接配置 Dubbo-Go 的静态路由。
+这里的 `static_config` 指的是:在 consumer 侧通过代码静态注入路由规则,而不是从配置中心动态下发。
+
+[English](README.md) | 中文
+
+## 前置准备
+
+- Go 1.25+。
+
+## 子示例
+
+- `condition`:基于直连地址的服务级静态条件路由示例
+- `tag`:基于直连地址的应用级静态标签路由示例
+
+## 如何使用
+
+进入对应子目录,按各自 README 运行:
+
+- `condition/README_CN.md`
+- `tag/README_CN.md`
+
+`condition` 示例只使用直连 URL。
+`tag` 示例只使用直连 URL。
+两个示例都不需要配置中心。
+每个子示例都需要先完成各自 README 中的前置准备和启动步骤。
diff --git a/router/static_config/condition/README.md
b/router/static_config/condition/README.md
new file mode 100644
index 00000000..3aebac2e
--- /dev/null
+++ b/router/static_config/condition/README.md
@@ -0,0 +1,59 @@
+# Static condition router
+
+This example shows how to configure Dubbo-Go's condition router statically in
code with direct provider URLs.
+
+English | [中文](README_CN.md)
+
+## Prerequisites
+
+- Go 1.25+.
+
+## What this sample demonstrates
+
+- Two providers listening directly on ports `20000` and `20001`
+- A service-scope static condition router configured by `dubbo.WithRouter(...)`
+- A `force=true` rule that routes `Greet` requests to port `20000`
+
+## How to run
+
+### Run providers
+
+Start two providers in separate terminals:
+
+```shell
+$ go run ./go-server/cmd/server.go
+$ go run ./go-node2-server/cmd/server_node2.go
+```
+
+- `go-server` listens on `:20000`
+- `go-node2-server` listens on `:20001`
+
+### Run consumer
+
+If you want to change the provider addresses, update `directURL` in
`go-client/cmd/client.go`.
+
+```shell
+$ go run ./go-client/cmd/client.go
+```
+
+The client connects to both providers by direct URLs.
+No registry or config center is required.
+
+## Expected result
+
+- The client logs `invoke successfully: receive: static condition router,
response from: server-node-20000`
+
+## Key router config
+
+The consumer injects this service-scope static condition router:
+
+```go
+dubbo.WithRouter(
+ router.WithScope("service"),
+ router.WithKey(greet.GreetServiceName),
+ router.WithForce(true),
+ router.WithConditions([]string{
+ "method = Greet => port = 20000",
+ }),
+)
+```
diff --git a/router/static_config/condition/README_CN.md
b/router/static_config/condition/README_CN.md
new file mode 100644
index 00000000..3a5794d7
--- /dev/null
+++ b/router/static_config/condition/README_CN.md
@@ -0,0 +1,59 @@
+# 静态条件路由
+
+这个示例展示了如何在代码中直接配置 Dubbo-Go 的静态条件路由,并通过直连地址访问服务实例。
+
+[English](README.md) | 中文
+
+## 前置准备
+
+- Go 1.25+。
+
+## 这个示例演示了什么
+
+- 两个通过直连地址访问的 provider,分别监听 `20000` 和 `20001`
+- 使用 `dubbo.WithRouter(...)` 配置服务级静态 condition router
+- 通过 `force=true` 规则把 `Greet` 请求固定路由到 `20000`
+
+## 如何运行
+
+### 启动 Provider
+
+在两个终端中分别启动下面两个 provider:
+
+```shell
+$ go run ./go-server/cmd/server.go
+$ go run ./go-node2-server/cmd/server_node2.go
+```
+
+- `go-server` 监听 `:20000`
+- `go-node2-server` 监听 `:20001`
+
+### 启动 Consumer
+
+如果你需要修改 provider 地址,请同步修改 `go-client/cmd/client.go` 中的 `directURL`。
+
+```shell
+$ go run ./go-client/cmd/client.go
+```
+
+客户端会通过直连 URL 连接两个 provider。
+这个示例不需要注册中心和配置中心。
+
+## 预期结果
+
+- 客户端会打印 `invoke successfully: receive: static condition router, response
from: server-node-20000`
+
+## 关键路由配置
+
+consumer 注入的是一个服务级静态 condition router:
+
+```go
+dubbo.WithRouter(
+ router.WithScope("service"),
+ router.WithKey(greet.GreetServiceName),
+ router.WithForce(true),
+ router.WithConditions([]string{
+ "method = Greet => port = 20000",
+ }),
+)
+```
diff --git a/router/static_config/condition/go-client/cmd/client.go
b/router/static_config/condition/go-client/cmd/client.go
new file mode 100644
index 00000000..f0936b8f
--- /dev/null
+++ b/router/static_config/condition/go-client/cmd/client.go
@@ -0,0 +1,94 @@
+/*
+ * 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"
+ "os"
+ "strings"
+)
+
+import (
+ "dubbo.apache.org/dubbo-go/v3"
+ "dubbo.apache.org/dubbo-go/v3/client"
+ "dubbo.apache.org/dubbo-go/v3/cluster/router"
+ _ "dubbo.apache.org/dubbo-go/v3/imports"
+
+ "github.com/dubbogo/gost/log/logger"
+)
+
+import (
+ greet "github.com/apache/dubbo-go-samples/direct/proto"
+)
+
+const (
+ clientApplication = "static-condition-client"
+ directURL = "tri://127.0.0.1:20000;tri://127.0.0.1:20001"
+ expectedServer = "server-node-20000"
+ attemptCount = 5
+)
+
+func main() {
+ ins, err := dubbo.NewInstance(
+ dubbo.WithName(clientApplication),
+ dubbo.WithRouter(
+ router.WithScope("service"),
+ router.WithKey(greet.GreetServiceName),
+ router.WithPriority(100),
+ router.WithForce(true),
+ router.WithConditions([]string{
+ "method = Greet => port = 20000",
+ }),
+ ),
+ )
+ if err != nil {
+ logger.Errorf("new instance failed: %v", err)
+ panic(err)
+ }
+
+ cli, err := ins.NewClient(client.WithClientURL(directURL))
+ if err != nil {
+ logger.Errorf("new client failed: %v", err)
+ panic(err)
+ }
+
+ svc, err := greet.NewGreetService(cli)
+ if err != nil {
+ logger.Errorf("new service failed: %v", err)
+ panic(err)
+ }
+
+ for i := 1; i <= attemptCount; i++ {
+ resp, err := svc.Greet(context.Background(),
&greet.GreetRequest{
+ Name: fmt.Sprintf("static condition router attempt %d",
i),
+ })
+ if err != nil {
+ logger.Errorf("invoke failed on attempt %d/%d: %v", i,
attemptCount, err)
+ os.Exit(1)
+ }
+
+ if !strings.Contains(resp.Greeting, expectedServer) {
+ logger.Errorf("routed to unexpected server on attempt
%d/%d, want %s, got %q",
+ i, attemptCount, expectedServer, resp.Greeting)
+ os.Exit(1)
+ }
+
+ logger.Infof("invoke successfully on attempt %d/%d: %v", i,
attemptCount, resp.Greeting)
+ }
+}
diff --git a/router/static_config/condition/go-node2-server/cmd/server_node2.go
b/router/static_config/condition/go-node2-server/cmd/server_node2.go
new file mode 100644
index 00000000..c723d78e
--- /dev/null
+++ b/router/static_config/condition/go-node2-server/cmd/server_node2.go
@@ -0,0 +1,76 @@
+/*
+ * 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/imports"
+ "dubbo.apache.org/dubbo-go/v3/protocol"
+
+ "github.com/dubbogo/gost/log/logger"
+)
+
+import (
+ greet "github.com/apache/dubbo-go-samples/direct/proto"
+)
+
+const (
+ providerApplication = "static-condition-provider"
+ triPort = 20001
+ serverName = "server-node-20001"
+)
+
+type GreetServer struct{}
+
+func (s *GreetServer) Greet(_ context.Context, req *greet.GreetRequest)
(*greet.GreetResponse, error) {
+ logger.Infof("%s received request: %s", serverName, req.Name)
+ return &greet.GreetResponse{
+ Greeting: "receive: " + req.Name + ", response from: " +
serverName,
+ }, nil
+}
+
+func main() {
+ ins, err := dubbo.NewInstance(
+ dubbo.WithName(providerApplication),
+ dubbo.WithProtocol(
+ protocol.WithTriple(),
+ protocol.WithPort(triPort),
+ ),
+ )
+ if err != nil {
+ panic(err)
+ }
+
+ srv, err := ins.NewServer()
+ if err != nil {
+ panic(err)
+ }
+
+ if err := greet.RegisterGreetServiceHandler(srv, &GreetServer{}); err
!= nil {
+ panic(err)
+ }
+
+ logger.Infof("%s started on :%d", serverName, triPort)
+ if err := srv.Serve(); err != nil {
+ logger.Errorf("%s stopped: %v", serverName, err)
+ }
+}
diff --git a/router/static_config/condition/go-server/cmd/server.go
b/router/static_config/condition/go-server/cmd/server.go
new file mode 100644
index 00000000..18582ac0
--- /dev/null
+++ b/router/static_config/condition/go-server/cmd/server.go
@@ -0,0 +1,76 @@
+/*
+ * 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/imports"
+ "dubbo.apache.org/dubbo-go/v3/protocol"
+
+ "github.com/dubbogo/gost/log/logger"
+)
+
+import (
+ greet "github.com/apache/dubbo-go-samples/direct/proto"
+)
+
+const (
+ providerApplication = "static-condition-provider"
+ triPort = 20000
+ serverName = "server-node-20000"
+)
+
+type GreetServer struct{}
+
+func (s *GreetServer) Greet(_ context.Context, req *greet.GreetRequest)
(*greet.GreetResponse, error) {
+ logger.Infof("%s received request: %s", serverName, req.Name)
+ return &greet.GreetResponse{
+ Greeting: "receive: " + req.Name + ", response from: " +
serverName,
+ }, nil
+}
+
+func main() {
+ ins, err := dubbo.NewInstance(
+ dubbo.WithName(providerApplication),
+ dubbo.WithProtocol(
+ protocol.WithTriple(),
+ protocol.WithPort(triPort),
+ ),
+ )
+ if err != nil {
+ panic(err)
+ }
+
+ srv, err := ins.NewServer()
+ if err != nil {
+ panic(err)
+ }
+
+ if err := greet.RegisterGreetServiceHandler(srv, &GreetServer{}); err
!= nil {
+ panic(err)
+ }
+
+ logger.Infof("%s started on :%d", serverName, triPort)
+ if err := srv.Serve(); err != nil {
+ logger.Errorf("%s stopped: %v", serverName, err)
+ }
+}
diff --git a/router/static_config/tag/README.md
b/router/static_config/tag/README.md
new file mode 100644
index 00000000..10eb9f04
--- /dev/null
+++ b/router/static_config/tag/README.md
@@ -0,0 +1,78 @@
+# Static tag router
+
+This example shows how to configure Dubbo-Go's tag router statically in code,
without a registry or config center.
+
+English | [中文](README_CN.md)
+
+## Prerequisites
+
+- Go 1.25+.
+
+## What this sample demonstrates
+
+- One untagged provider on port `20000`
+- One `gray` tagged provider on port `20002`
+- An application-scope static tag router configured by `dubbo.WithRouter(...)`
+
+## How to run
+
+### Run providers
+
+Start two providers in separate terminals:
+
+```shell
+$ go run ./go-server/cmd/server.go
+$ go run ./go-tag-server/cmd/server_tag.go
+```
+
+- `go-server` listens on `:20000` without a tag
+- `go-tag-server` listens on `:20002` and exports the service with tag `gray`
+
+### Run consumer
+
+```shell
+$ go run ./go-client/cmd/client.go
+```
+
+The client uses direct URLs only:
+
+```text
+tri://127.0.0.1:20000;tri://127.0.0.1:20002?dubbo.tag=gray
+```
+
+No registry or config center is required.
+
+## Expected result
+
+The client runs a single scenario and routes to `server-with-gray-tag`.
+You should see logs similar to:
+
+```text
+INFO ... invoke successfully: receive: static tag router, response from:
server-with-gray-tag
+```
+
+## Key router config
+
+Static tag router:
+
+```go
+dubbo.WithRouter(
+ router.WithScope("application"),
+ router.WithKey("static-tag-provider"),
+ router.WithForce(false),
+ router.WithTags([]global.Tag{
+ {
+ Name: "gray",
+ Addresses: []string{"127.0.0.1:20002"},
+ },
+ }),
+)
+```
+
+Request with tag attachment:
+
+```go
+ctx := context.WithValue(context.Background(), constant.AttachmentKey,
map[string]string{
+ constant.Tagkey: "gray",
+})
+```
diff --git a/router/static_config/tag/README_CN.md
b/router/static_config/tag/README_CN.md
new file mode 100644
index 00000000..ca357f7f
--- /dev/null
+++ b/router/static_config/tag/README_CN.md
@@ -0,0 +1,78 @@
+# 静态标签路由
+
+这个示例展示了如何在代码中直接配置 Dubbo-Go 的静态标签路由,不依赖注册中心和配置中心。
+
+[English](README.md) | 中文
+
+## 前置准备
+
+- Go 1.25+。
+
+## 这个示例演示了什么
+
+- 一个不带 tag 的 provider,监听 `20000`
+- 一个带 `gray` tag 的 provider,监听 `20002`
+- 使用 `dubbo.WithRouter(...)` 配置应用级静态 tag router
+
+## 如何运行
+
+### 启动 Provider
+
+在两个终端中分别启动下面两个 provider:
+
+```shell
+$ go run ./go-server/cmd/server.go
+$ go run ./go-tag-server/cmd/server_tag.go
+```
+
+- `go-server` 监听 `:20000`,不带 tag
+- `go-tag-server` 监听 `:20002`,并以 `gray` 标签导出服务
+
+### 启动 Consumer
+
+```shell
+$ go run ./go-client/cmd/client.go
+```
+
+客户端只使用直连 URL:
+
+```text
+tri://127.0.0.1:20000;tri://127.0.0.1:20002?dubbo.tag=gray
+```
+
+这个示例不需要注册中心,也不需要配置中心。
+
+## 预期结果
+
+客户端会运行一个场景,并路由到 `server-with-gray-tag`。
+你会看到类似下面的日志:
+
+```text
+INFO ... invoke successfully: receive: static tag router, response from:
server-with-gray-tag
+```
+
+## 关键路由配置
+
+静态 tag router:
+
+```go
+dubbo.WithRouter(
+ router.WithScope("application"),
+ router.WithKey("static-tag-provider"),
+ router.WithForce(false),
+ router.WithTags([]global.Tag{
+ {
+ Name: "gray",
+ Addresses: []string{"127.0.0.1:20002"},
+ },
+ }),
+)
+```
+
+携带请求 tag:
+
+```go
+ctx := context.WithValue(context.Background(), constant.AttachmentKey,
map[string]string{
+ constant.Tagkey: "gray",
+})
+```
diff --git a/router/static_config/tag/go-client/cmd/client.go
b/router/static_config/tag/go-client/cmd/client.go
new file mode 100644
index 00000000..931b706e
--- /dev/null
+++ b/router/static_config/tag/go-client/cmd/client.go
@@ -0,0 +1,105 @@
+/*
+ * 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"
+ "os"
+ "strings"
+)
+
+import (
+ "dubbo.apache.org/dubbo-go/v3"
+ "dubbo.apache.org/dubbo-go/v3/client"
+ "dubbo.apache.org/dubbo-go/v3/cluster/router"
+ "dubbo.apache.org/dubbo-go/v3/common/constant"
+ "dubbo.apache.org/dubbo-go/v3/global"
+ _ "dubbo.apache.org/dubbo-go/v3/imports"
+
+ "github.com/dubbogo/gost/log/logger"
+)
+
+import (
+ greet "github.com/apache/dubbo-go-samples/direct/proto"
+)
+
+const (
+ clientApplication = "static-tag-client"
+ tagName = "gray"
+ grayAddress = "127.0.0.1:20002"
+ directURL =
"tri://127.0.0.1:20000;tri://127.0.0.1:20002?dubbo.tag=gray"
+ expectedServer = "server-with-gray-tag"
+ attemptCount = 5
+)
+
+func main() {
+ ins, err := dubbo.NewInstance(
+ dubbo.WithName(clientApplication),
+ dubbo.WithRouter(
+ router.WithScope("application"),
+ router.WithKey("static-tag-provider"),
+ router.WithPriority(100),
+ router.WithForce(false),
+ router.WithTags([]global.Tag{
+ {
+ Name: tagName,
+ Addresses: []string{grayAddress},
+ },
+ }),
+ ),
+ )
+ if err != nil {
+ logger.Errorf("new instance failed: %v", err)
+ panic(err)
+ }
+
+ cli, err := ins.NewClient(client.WithClientURL(directURL))
+ if err != nil {
+ logger.Errorf("new client failed: %v", err)
+ panic(err)
+ }
+
+ svc, err := greet.NewGreetService(cli)
+ if err != nil {
+ logger.Errorf("new service failed: %v", err)
+ panic(err)
+ }
+
+ ctx := context.WithValue(context.Background(), constant.AttachmentKey,
map[string]string{
+ constant.Tagkey: tagName,
+ })
+
+ for i := 1; i <= attemptCount; i++ {
+ resp, err := svc.Greet(ctx, &greet.GreetRequest{
+ Name: fmt.Sprintf("static tag router attempt %d", i),
+ })
+ if err != nil {
+ logger.Errorf("invoke failed on attempt %d/%d: %v", i,
attemptCount, err)
+ os.Exit(1)
+ }
+
+ if !strings.Contains(resp.Greeting, expectedServer) {
+ logger.Errorf("routed to unexpected server on attempt
%d/%d, want %s, got %q",
+ i, attemptCount, expectedServer, resp.Greeting)
+ os.Exit(1)
+ }
+
+ logger.Infof("invoke successfully on attempt %d/%d: %v", i,
attemptCount, resp.Greeting)
+ }
+}
diff --git a/router/static_config/tag/go-server/cmd/server.go
b/router/static_config/tag/go-server/cmd/server.go
new file mode 100644
index 00000000..12fa2f33
--- /dev/null
+++ b/router/static_config/tag/go-server/cmd/server.go
@@ -0,0 +1,76 @@
+/*
+ * 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/imports"
+ "dubbo.apache.org/dubbo-go/v3/protocol"
+
+ "github.com/dubbogo/gost/log/logger"
+)
+
+import (
+ greet "github.com/apache/dubbo-go-samples/direct/proto"
+)
+
+const (
+ providerApplication = "static-tag-provider"
+ triPort = 20000
+ serverName = "server-without-tag"
+)
+
+type GreetServer struct{}
+
+func (s *GreetServer) Greet(_ context.Context, req *greet.GreetRequest)
(*greet.GreetResponse, error) {
+ logger.Infof("%s received request: %s", serverName, req.Name)
+ return &greet.GreetResponse{
+ Greeting: "receive: " + req.Name + ", response from: " +
serverName,
+ }, nil
+}
+
+func main() {
+ ins, err := dubbo.NewInstance(
+ dubbo.WithName(providerApplication),
+ dubbo.WithProtocol(
+ protocol.WithTriple(),
+ protocol.WithPort(triPort),
+ ),
+ )
+ if err != nil {
+ panic(err)
+ }
+
+ srv, err := ins.NewServer()
+ if err != nil {
+ panic(err)
+ }
+
+ if err := greet.RegisterGreetServiceHandler(srv, &GreetServer{}); err
!= nil {
+ panic(err)
+ }
+
+ logger.Infof("%s started on :%d", serverName, triPort)
+ if err := srv.Serve(); err != nil {
+ logger.Errorf("%s stopped: %v", serverName, err)
+ }
+}
diff --git a/router/static_config/tag/go-tag-server/cmd/server_tag.go
b/router/static_config/tag/go-tag-server/cmd/server_tag.go
new file mode 100644
index 00000000..e7a0faf6
--- /dev/null
+++ b/router/static_config/tag/go-tag-server/cmd/server_tag.go
@@ -0,0 +1,77 @@
+/*
+ * 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/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/direct/proto"
+)
+
+const (
+ providerApplication = "static-tag-provider"
+ triPort = 20002
+ serverName = "server-with-gray-tag"
+)
+
+type GreetServer struct{}
+
+func (s *GreetServer) Greet(_ context.Context, req *greet.GreetRequest)
(*greet.GreetResponse, error) {
+ logger.Infof("%s received request: %s", serverName, req.Name)
+ return &greet.GreetResponse{
+ Greeting: "receive: " + req.Name + ", response from: " +
serverName,
+ }, nil
+}
+
+func main() {
+ ins, err := dubbo.NewInstance(
+ dubbo.WithName(providerApplication),
+ dubbo.WithProtocol(
+ protocol.WithTriple(),
+ protocol.WithPort(triPort),
+ ),
+ )
+ if err != nil {
+ panic(err)
+ }
+
+ srv, err := ins.NewServer()
+ if err != nil {
+ panic(err)
+ }
+
+ if err := greet.RegisterGreetServiceHandler(srv, &GreetServer{},
server.WithTag("gray")); err != nil {
+ panic(err)
+ }
+
+ logger.Infof("%s started on :%d with tag gray", serverName, triPort)
+ if err := srv.Serve(); err != nil {
+ logger.Errorf("%s stopped: %v", serverName, err)
+ }
+}
diff --git a/start_integrate_test.sh b/start_integrate_test.sh
index 7706ea76..91200bc9 100755
--- a/start_integrate_test.sh
+++ b/start_integrate_test.sh
@@ -97,6 +97,8 @@ array+=("java_interop/service_discovery/service")
# router
array+=("router/tag")
+array+=("router/static_config/tag")
+array+=("router/static_config/condition")
DOCKER_DIR="$(pwd)"
DOCKER_COMPOSE_CMD="docker-compose"