This is an automated email from the ASF dual-hosted git repository.
alexstocks 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 0c7e6a7b feat: Add etcd registry example (#920)
0c7e6a7b is described below
commit 0c7e6a7bfaf5fc2dcc9aa5f47718b404827f68b6
Author: xuhe <[email protected]>
AuthorDate: Sat Sep 20 17:09:48 2025 +0800
feat: Add etcd registry example (#920)
* feat: Add dubbo-go-samples/registry/etcd dir for etcd registry example
* docs: Add etcd registry example to README
* Update registry/etcd/go-server/server.go
Modify the .proto file content to point to the correct compiled product path
Co-authored-by: Copilot <[email protected]>
* Update registry/etcd/go-client/client.go
Modify the go file import to import the correct compilation product path
Co-authored-by: Copilot <[email protected]>
* Update registry/etcd/proto/greet.proto
Co-authored-by: Copilot <[email protected]>
* Recompile the .proto file
* format imports
* fix: format imports
---------
Co-authored-by: Copilot <[email protected]>
---
registry/README.md | 1 +
registry/etcd/go-client/client.go | 66 +++++++++++++
registry/etcd/go-server/server.go | 71 ++++++++++++++
registry/etcd/proto/greet.pb.go | 189 ++++++++++++++++++++++++++++++++++++
registry/etcd/proto/greet.proto | 34 +++++++
registry/etcd/proto/greet.triple.go | 122 +++++++++++++++++++++++
6 files changed, 483 insertions(+)
diff --git a/registry/README.md b/registry/README.md
index bbffff55..4bebd01f 100644
--- a/registry/README.md
+++ b/registry/README.md
@@ -4,5 +4,6 @@ This directory contains a series of examples showing dubbo-go's
service discover
* [Zookeeper as registry](./zookeeper)
* [Nacos as registry](./nacos)
+* [Etcd as registry](./etcd)
[Service Discovery]:
https://dubbo-next.staged.apache.org/zh-cn/overview/mannual/golang-sdk/tutorial/service-discovery
\ No newline at end of file
diff --git a/registry/etcd/go-client/client.go
b/registry/etcd/go-client/client.go
new file mode 100644
index 00000000..c07f2a3d
--- /dev/null
+++ b/registry/etcd/go-client/client.go
@@ -0,0 +1,66 @@
+/*
+ * 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/registry"
+
+ "github.com/dubbogo/gost/log/logger"
+)
+
+import (
+ greet "github.com/apache/dubbo-go-samples/registry/etcd/proto"
+)
+
+func main() {
+ // global conception
+ // configure global configurations and common modules
+ ins, err := dubbo.NewInstance(
+ dubbo.WithName("dubbo_registry_etcd_client"),
+ dubbo.WithRegistry(
+ registry.WithEtcdV3(),
+ registry.WithAddress("127.0.0.1:2379"),
+ ),
+ )
+ if err != nil {
+ panic(err)
+ }
+ // configure the params that only client layer cares
+ cli, err := ins.NewClient()
+ if err != nil {
+ panic(err)
+ }
+
+ svc, err := greet.NewGreetService(cli)
+ if err != nil {
+ panic(err)
+ }
+
+ resp, err := svc.Greet(context.Background(), &greet.GreetRequest{Name:
"hello world"})
+ if err != nil {
+ logger.Error(err)
+ }
+ logger.Infof("Greet response: %s", resp)
+ select {}
+}
diff --git a/registry/etcd/go-server/server.go
b/registry/etcd/go-server/server.go
new file mode 100644
index 00000000..46b4f0a7
--- /dev/null
+++ b/registry/etcd/go-server/server.go
@@ -0,0 +1,71 @@
+/*
+ * 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/registry"
+
+ "github.com/dubbogo/gost/log/logger"
+)
+
+import (
+ greet "github.com/apache/dubbo-go-samples/registry/etcd/proto"
+)
+
+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_registry_etcd_server"),
+ dubbo.WithRegistry(
+ registry.WithEtcdV3(),
+ registry.WithAddress("127.0.0.1:2379"),
+ ),
+ 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{});
err != nil {
+ panic(err)
+ }
+
+ if err := srv.Serve(); err != nil {
+ logger.Error(err)
+ }
+}
diff --git a/registry/etcd/proto/greet.pb.go b/registry/etcd/proto/greet.pb.go
new file mode 100644
index 00000000..28532229
--- /dev/null
+++ b/registry/etcd/proto/greet.pb.go
@@ -0,0 +1,189 @@
+//
+// 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.36.9
+// protoc v3.21.12
+// source: greet.proto
+
+package greet
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+ unsafe "unsafe"
+)
+
+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 `protogen:"open.v1"`
+ Name string
`protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GreetRequest) Reset() {
+ *x = GreetRequest{}
+ mi := &file_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_greet_proto_msgTypes[0]
+ if 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_greet_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *GreetRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+type GreetResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Greeting string
`protobuf:"bytes,1,opt,name=greeting,proto3" json:"greeting,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GreetResponse) Reset() {
+ *x = GreetResponse{}
+ mi := &file_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_greet_proto_msgTypes[1]
+ if 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_greet_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *GreetResponse) GetGreeting() string {
+ if x != nil {
+ return x.Greeting
+ }
+ return ""
+}
+
+var File_greet_proto protoreflect.FileDescriptor
+
+const file_greet_proto_rawDesc = "" +
+ "\n" +
+ "\vgreet.proto\x12\x05greet\"\"\n" +
+ "\fGreetRequest\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\"+\n" +
+ "\rGreetResponse\x12\x1a\n" +
+ "\bgreeting\x18\x01 \x01(\tR\bgreeting2D\n" +
+ "\fGreetService\x124\n" +
+
"\x05Greet\x12\x13.greet.GreetRequest\x1a\x14.greet.GreetResponse\"\x00B>Z<github.com/apache/dubbo-go-samples/registry/etcd/proto;greetb\x06proto3"
+
+var (
+ file_greet_proto_rawDescOnce sync.Once
+ file_greet_proto_rawDescData []byte
+)
+
+func file_greet_proto_rawDescGZIP() []byte {
+ file_greet_proto_rawDescOnce.Do(func() {
+ file_greet_proto_rawDescData =
protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_greet_proto_rawDesc),
len(file_greet_proto_rawDesc)))
+ })
+ return file_greet_proto_rawDescData
+}
+
+var file_greet_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_greet_proto_goTypes = []any{
+ (*GreetRequest)(nil), // 0: greet.GreetRequest
+ (*GreetResponse)(nil), // 1: greet.GreetResponse
+}
+var file_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_greet_proto_init() }
+func file_greet_proto_init() {
+ if File_greet_proto != nil {
+ return
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor:
unsafe.Slice(unsafe.StringData(file_greet_proto_rawDesc),
len(file_greet_proto_rawDesc)),
+ NumEnums: 0,
+ NumMessages: 2,
+ NumExtensions: 0,
+ NumServices: 1,
+ },
+ GoTypes: file_greet_proto_goTypes,
+ DependencyIndexes: file_greet_proto_depIdxs,
+ MessageInfos: file_greet_proto_msgTypes,
+ }.Build()
+ File_greet_proto = out.File
+ file_greet_proto_goTypes = nil
+ file_greet_proto_depIdxs = nil
+}
diff --git a/registry/etcd/proto/greet.proto b/registry/etcd/proto/greet.proto
new file mode 100644
index 00000000..8c3036ff
--- /dev/null
+++ b/registry/etcd/proto/greet.proto
@@ -0,0 +1,34 @@
+/*
+ * 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/registry/etcd/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/registry/etcd/proto/greet.triple.go
b/registry/etcd/proto/greet.triple.go
new file mode 100644
index 00000000..6f906938
--- /dev/null
+++ b/registry/etcd/proto/greet.triple.go
@@ -0,0 +1,122 @@
+// Code generated by protoc-gen-triple. DO NOT EDIT.
+//
+// Source: greet.proto
+package greet
+
+import (
+ "context"
+)
+
+import (
+ "dubbo.apache.org/dubbo-go/v3"
+ "dubbo.apache.org/dubbo-go/v3/client"
+ "dubbo.apache.org/dubbo-go/v3/common"
+ "dubbo.apache.org/dubbo-go/v3/common/constant"
+ "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol"
+ "dubbo.apache.org/dubbo-go/v3/server"
+)
+
+// This is a compile-time assertion to ensure that this generated file and the
Triple package
+// are compatible. If you get a compiler error that this constant is not
defined, this code was
+// generated with a version of Triple newer than the one compiled into your
binary. You can fix the
+// problem by either regenerating this code with an older version of Triple or
updating the Triple
+// version compiled into your binary.
+const _ = triple_protocol.IsAtLeastVersion0_1_0
+
+const (
+ // GreetServiceName is the fully-qualified name of the GreetService
service.
+ GreetServiceName = "greet.GreetService"
+)
+
+// These constants are the fully-qualified names of the RPCs defined in this
package. They're
+// exposed at runtime as procedure and as the final two segments of the HTTP
route.
+//
+// Note that these are different from the fully-qualified method names used by
+// google.golang.org/protobuf/reflect/protoreflect. To convert from these
constants to
+// reflection-formatted method names, remove the leading slash and convert the
remaining slash to a
+// period.
+const (
+ // GreetServiceGreetProcedure is the fully-qualified name of the
GreetService's Greet RPC.
+ GreetServiceGreetProcedure = "/greet.GreetService/Greet"
+)
+
+var (
+ _ GreetService = (*GreetServiceImpl)(nil)
+)
+
+// GreetService is a client for the greet.GreetService service.
+type GreetService interface {
+ Greet(ctx context.Context, req *GreetRequest, opts
...client.CallOption) (*GreetResponse, error)
+}
+
+// NewGreetService constructs a client for the greet.GreetService service.
+func NewGreetService(cli *client.Client, opts ...client.ReferenceOption)
(GreetService, error) {
+ conn, err := cli.DialWithInfo("greet.GreetService",
&GreetService_ClientInfo, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &GreetServiceImpl{
+ conn: conn,
+ }, nil
+}
+
+func SetConsumerGreetService(srv common.RPCService) {
+ dubbo.SetConsumerServiceWithInfo(srv, &GreetService_ClientInfo)
+}
+
+// GreetServiceImpl implements GreetService.
+type GreetServiceImpl struct {
+ conn *client.Connection
+}
+
+func (c *GreetServiceImpl) Greet(ctx context.Context, req *GreetRequest, opts
...client.CallOption) (*GreetResponse, error) {
+ resp := new(GreetResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "Greet",
opts...); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+var GreetService_ClientInfo = client.ClientInfo{
+ InterfaceName: "greet.GreetService",
+ MethodNames: []string{"Greet"},
+ ConnectionInjectFunc: func(dubboCliRaw interface{}, conn
*client.Connection) {
+ dubboCli := dubboCliRaw.(*GreetServiceImpl)
+ dubboCli.conn = conn
+ },
+}
+
+// GreetServiceHandler is an implementation of the greet.GreetService service.
+type GreetServiceHandler interface {
+ Greet(context.Context, *GreetRequest) (*GreetResponse, error)
+}
+
+func RegisterGreetServiceHandler(srv *server.Server, hdlr GreetServiceHandler,
opts ...server.ServiceOption) error {
+ return srv.Register(hdlr, &GreetService_ServiceInfo, opts...)
+}
+
+func SetProviderGreetService(srv common.RPCService) {
+ dubbo.SetProviderServiceWithInfo(srv, &GreetService_ServiceInfo)
+}
+
+var GreetService_ServiceInfo = server.ServiceInfo{
+ InterfaceName: "greet.GreetService",
+ ServiceType: (*GreetServiceHandler)(nil),
+ Methods: []server.MethodInfo{
+ {
+ Name: "Greet",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(GreetRequest)
+ },
+ MethodFunc: func(ctx context.Context, args
[]interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*GreetRequest)
+ res, err :=
handler.(GreetServiceHandler).Greet(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },
+ },
+}