Coder Social home page Coder Social logo

plugins's Introduction

Go Micro Go.Dev reference Go Report Card

Go Micro is a framework for distributed systems development.

Overview

Go Micro provides the core requirements for distributed systems development including RPC and Event driven communication. The Go Micro philosophy is sane defaults with a pluggable architecture. We provide defaults to get you started quickly but everything can be easily swapped out.

Features

Go Micro abstracts away the details of distributed systems. Here are the main features.

  • Authentication - Auth is built in as a first class citizen. Authentication and authorization enable secure zero trust networking by providing every service an identity and certificates. This additionally includes rule based access control.

  • Dynamic Config - Load and hot reload dynamic config from anywhere. The config interface provides a way to load application level config from any source such as env vars, file, etcd. You can merge the sources and even define fallbacks.

  • Data Storage - A simple data store interface to read, write and delete records. It includes support for memory, file and CockroachDB by default. State and persistence becomes a core requirement beyond prototyping and Micro looks to build that into the framework.

  • Service Discovery - Automatic service registration and name resolution. Service discovery is at the core of micro service development. When service A needs to speak to service B it needs the location of that service. The default discovery mechanism is multicast DNS (mdns), a zeroconf system.

  • Load Balancing - Client side load balancing built on service discovery. Once we have the addresses of any number of instances of a service we now need a way to decide which node to route to. We use random hashed load balancing to provide even distribution across the services and retry a different node if there's a problem.

  • Message Encoding - Dynamic message encoding based on content-type. The client and server will use codecs along with content-type to seamlessly encode and decode Go types for you. Any variety of messages could be encoded and sent from different clients. The client and server handle this by default. This includes protobuf and json by default.

  • RPC Client/Server - RPC based request/response with support for bidirectional streaming. We provide an abstraction for synchronous communication. A request made to a service will be automatically resolved, load balanced, dialled and streamed.

  • Async Messaging - PubSub is built in as a first class citizen for asynchronous communication and event driven architectures. Event notifications are a core pattern in micro service development. The default messaging system is a HTTP event message broker.

  • Event Streaming - PubSub is great for async notifications but for more advanced use cases event streaming is preferred. Offering persistent storage, consuming from offsets and acking. Go Micro includes support for NATS Jetstream and Redis streams.

  • Synchronization - Distributed systems are often built in an eventually consistent manner. Support for distributed locking and leadership are built in as a Sync interface. When using an eventually consistent database or scheduling use the Sync interface.

  • Pluggable Interfaces - Go Micro makes use of Go interfaces for each distributed system abstraction. Because of this these interfaces are pluggable and allows Go Micro to be runtime agnostic. You can plugin any underlying technology.

Getting Started

To make use of Go Micro import it

import "go-micro.dev/v5"

Define a handler (protobuf is optionally supported - see example)

type Request struct {
        Name string `json:"name"`
}

type Response struct {
        Message string `json:"message"`
}

type Helloworld struct{}

func (h *Helloworld) Greeting(ctx context.Context, req *Request, rsp *Response) error {
        rsp.Message = "Hello " + req.Name
        return nil
}

Create, initialise and run the service

// create a new service
service := micro.NewService(
    micro.Name("helloworld"),
    micro.Handle(new(Helloworld)),
)

// initialise flags
service.Init()

// start the service
service.Run()

Optionally set fixed address

service := micro.NewService(
    // set address
    micro.Address(":8080"),
)

Call it via curl

curl -XPOST \
     -H 'Content-Type: application/json' \
     -H 'Micro-Endpoint: Helloworld.Greeting' \
     -d '{"name": "alice"}' \
      http://localhost:8080

See the examples for detailed information on usage.

Toolkit

See github.com/go-micro for tooling.

License

Business Source License 1.1

Purchase a license through the Github Sponsorship Page

plugins's People

Contributors

aduffeck avatar alexlast avatar asim avatar asynxc avatar butonic avatar davincible avatar dbereza-machinify avatar dragonchaser avatar esivres avatar jochumdev avatar keepstep avatar kobergj avatar kuri-su avatar mamadeusia avatar medivh-jay avatar opvexe avatar petrchalov avatar qianwj avatar quexer avatar r3eg avatar rhafer avatar scs-11 avatar scukerman avatar super-zhw avatar wkloucek avatar xiaomiusa87 avatar xpunch avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

plugins's Issues

plugins/client/grpc Cannot be used according to Usage

go: finding module for package github.com/micro/go-plugins/client/grpc
api/logics imports
github.com/micro/go-plugins/client/grpc: module github.com/micro/go-plugins@latest found (v1.5.1), but does not contain package github.com/micro/go-plugins/client/grpc

plugins/v4/wrapper/breaker/hystrix/ readMe

hystrix.NewClientWrapper(hystrix.WithFilter(func(c context.Context, e error) error {
if e == ErrLetItPass {
return nil
}
return e
})

should be:
hystrix.NewClientWrapper(hystrix.WithFilter(func(c context.Context, e error) bool{
if e == ErrLetItPass {
return true
}
return false
})

[FEATURE] v4/broker/rabbitmq - parallel message handling

Is your feature request related to a problem? Please describe.
Enhance v4/broker/rabbitmq plugin to allow for handling incoming broker messages in parallel.

Describe the solution you'd like
Currently, it seems the v4/broker/rabbitmq plugin processes messages serially, based on the code below:

for d := range sub {
s.r.wg.Add(1)
s.fn(d)
s.r.wg.Done()
}

This is not ideal for throughput, particularly for messages that take time to process or their handlers end up blocking.

Additional context
This could be tied to the rabbitmq.PrefetchCount broker option, since that's a limitation of the max number of messages that are retrieved but not acknowledged at a time, but for backwards compatibility another option should probably be provided to enable parallelism.

registry watch don't work ?why ?

func TestConsulRegistryWatcher(t *testing.T) {
	reg := consul.NewRegistry()

	go func() {
		time.Sleep(10 * time.Second)
		fmt.Println("====1000")
		err := reg.Register(&registry2.Service{
			Name:    "test.service",
			Version: "latest",
			Nodes: []*registry2.Node{
				{
					Id:      "test.node10",
					Address: "localhost:8080",
				},
			},
		})
		if err != nil {
			t.Fatalf("无法注册服务: %v", err)
		}
	}()

	go func() {
		time.Sleep(5 * time.Second)
		fmt.Println("====55")
		err := reg.Register(&registry2.Service{
			Name:    "test.service",
			Version: "latest",
			Nodes: []*registry2.Node{
				{
					Id:      "test.node12",
					Address: "localhost:8080",
				},
			},
		})
		if err != nil {
			t.Fatalf("无法更新服务: %v", err)
		}
	}()

	watcher, err := reg.Watch(registry2.WatchService("test.service"))
	if err != nil {
		t.Fatalf("无法创建Watcher: %v", err)
	}
	defer watcher.Stop()

	list, err := reg.GetService("test.service")
	assert.NoError(t, err)
	t.Log(list)

	for {
		fmt.Println("-----")
		event, err := watcher.Next()
		fmt.Println("++++++++")
		if err != nil {
			t.Fatalf("Watcher错误: %v", err)
		}
		t.Logf("收到Watcher事件: %v", event)
	}
}

[FEATURE] v4/sync/etcd - add username/password options

Is your feature request related to a problem? Please describe.
Currently, the v4/sync/etcd plugin does not allow passing in a username/password for RBAC authentication with etcd, either embedded in the endpoint URL or as separate custom options.

Describe the solution you'd like
The etcd client library expects the username/password for RBAC authentication passed in the config, which is being defined here:

c, err := clientv3.New(clientv3.Config{
Endpoints: endpoints,
TLS: options.TLSConfig,
})

Currently, the username / password are not being defined here, and embedding the username/password into the endpoint URL does not cause the etcd client to parse them out and use them for RBAC auth.

As such, the username/password could be parsed out of the sync.Nodes sync option, which isn't super ideal, or new etcd-specific credential options could be created and stored/retrieved from the option context.

Additional context
N/A

Wrong returning value

The injectTraceIntoCtx function is supposed to inject the trace into the context. But instead of that it just returns with the same context.

func injectTraceIntoCtx(ctx context.Context, span *trace.Span) context.Context {
spanCtx := propagation.Binary(span.SpanContext())
metadata.Set(ctx, TracePropagationField, base64.RawStdEncoding.EncodeToString(spanCtx))
return ctx
}

The metadata.Set function returns with the new context not modifying the parameter
https://github.com/asim/go-micro/blob/master/metadata/metadata.go#L54-L65

I think this is how it is supposed to be:

ctx = metadata.Set(ctx, TracePropagationField, base64.RawStdEncoding.EncodeToString(spanCtx))

With this change, the trace is sent between the microservices and I can see them in Jaeger:
Screen Shot 2022-05-26 at 2 20 48 PM

Without the change:
Screen Shot 2022-05-26 at 2 21 05 PM

[FEATURE] Add support for grpc reflection

Is your feature request related to a problem? Please describe.

Add ability for grpc reflection to support web ui/grpc curl

Describe the solution you'd like
Should have some flag to pass to service.New to register reflection service on gRPC server Reference: https://github.com/grpc/grpc/blob/master/doc/server-reflection.md

Additional context
This is a duplicate for previous feature request: go-micro/go-micro#1181, But other one seems to have been closed without any merge into master

[BUG] etcd plugin errors out on new project

Describe the bug

  1. What are you trying to do?
    I'm trying to use go-micro with the etcd registry
  2. What did you expect to happen?
    I expected the etcd plugin to be bundled with go-micro. I also expected it to work after pulling it in from the plugins explicitly.
  3. What happens instead?
    The error below

How to reproduce the bug:

If possible, please include a minimal code snippet here.

$ micro new service my_service
$ make proto update tidy
$ cd my_service
$ go run *.go --registry etcd
Registry etcd not found
exit status 1
$ go get github.com/asim/go-micro/plugins/registry/etcd/v4
<add to plugins.go>
$ go run *.go --registry etcd
# go.etcd.io/etcd/client/v3
../../go/pkg/mod/go.etcd.io/etcd/client/[email protected]/client.go:251:28: undefined: grpc.WithResolvers
../../go/pkg/mod/go.etcd.io/etcd/client/[email protected]/client.go:276:29: undefined: grpc.WithResolvers

Environment:
Go Version: please paste go version output here

go version go1.18.1 darwin/arm64

[BUG]Issue with the nacos registry in web.NewService()

That reports an error when I use nacos registry in web.NewService():
panic: assignment to entry in nil map
My code:

package main

import (
	"user/config/config"
	"go-micro.dev/v4/web"
)

var (
	service = "go-layout"
	version = "latest"
)

func main() {
	srv := web.NewService(
		web.Name(service),
		web.Version(version),
		web.Registry(config.NewRegistry()),
		// web.Metadata(map[string]string{"version": version}),
	)
	srv.Run()
}
package config

import (
	"github.com/asim/go-micro/plugins/registry/nacos/v4"
	"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
	"go-micro.dev/v4/registry"
)

func NewRegistry() registry.Registry {
	DefaultClientConfig := constant.ClientConfig{
		NamespaceId: "45d1be27-88ab-487d-b0ba-c09557fcaf29",
	}
	r := nacos.NewRegistry(
		nacos.WithClientConfig(DefaultClientConfig),
		nacos.WithAddress([]string{
			"127.0.0.1:8848",
		}))
	return r
}

go.mod

module user

go 1.18

require (
	github.com/asim/go-micro/plugins/registry/nacos/v4 v4.0.0-20220404185419-6dedee5d8c2c
	github.com/nacos-group/nacos-sdk-go/v2 v2.0.1
	go-micro.dev/v4 v4.2.1
)

Debug code,I find it will be ok to add web.Metadat option in web.NewService().

Environment:
Go Version: go version go1.18 windows/amd64

plugins/blob/main/v4/config/source/consul/watcher.go watcher err

As I usage, ACL is enabled, where the token parameter type is missing, the watcher fails, or Plan constructed parameters should be provided where possible

wp, err := watch.Parse(map[string]interface{}{"type": "keyprefix", "prefix": key})

like this:

wp, err := watch.Parse(map[string]interface{}{"type": "keyprefix", "prefix": key,"token":token})

Cannot import plugins/v4/server/grpc

When importing plugins/v4/server/grpc, I get following message:

go: finding module for package github.com/go-micro/plugins/v4/client/grpc/v4
go: finding module for package github.com/go-micro/plugins/v4/server/grpc
go: found github.com/go-micro/plugins/v4/server/grpc in github.com/go-micro/plugins/v4/server/grpc v1.0.0
go: downloading github.com/go-micro/plugins/v4/transport/grpc v0.0.0
github.com/owncloud/ocis/ocis-pkg/service/grpc imports
	github.com/go-micro/plugins/v4/server/grpc tested by
	github.com/go-micro/plugins/v4/server/grpc.test imports
	github.com/go-micro/plugins/v4/transport/grpc: reading github.com/go-micro/plugins/v4/transport/grpc/v4/transport/grpc/go.mod at revision v4/transport/grpc/v0.0.0: unknown revision v4/transport/grpc/v0.0.0

This is because of these lines:

github.com/go-micro/plugins/v4/client/grpc v0.0.0
github.com/go-micro/plugins/v4/transport/grpc v0.0.0

Ideally, they should also point to v1.0.0 (the most recent version) but I don't know how that fit's in the release process!? Do you plan to always tag all plugins at the same time or will they get separate releases? If the second option is the case, we should be able to fix it once and then get Dependabot / RenovateBot PRs to update the transport plugin automatically after a release.

CC @xpunch

package "go-micro.dev/v4/cmd" unavailable yet

package "go-micro.dev/v4/cmd" removed from latest version of go-micro

imported in:

v4/cache/redis/redis.go: "go-micro.dev/v4/cmd"
v4/client/grpc/grpc.go: "go-micro.dev/v4/cmd"
v4/client/http/http.go: "go-micro.dev/v4/cmd"
v4/client/mucp/mucp.go: "go-micro.dev/v4/cmd"
v4/transport/quic/quic.go: "go-micro.dev/v4/cmd"
v4/transport/utp/utp.go: "go-micro.dev/v4/cmd"
v4/transport/memory/memory.go: "go-micro.dev/v4/cmd"
v4/transport/rabbitmq/rabbitmq.go: "go-micro.dev/v4/cmd"
v4/transport/grpc/grpc.go: "go-micro.dev/v4/cmd"
v4/transport/tcp/tcp.go: "go-micro.dev/v4/cmd"
v4/transport/nats/nats.go: "go-micro.dev/v4/cmd"
v4/server/grpc/grpc.go: "go-micro.dev/v4/cmd"
v4/server/http/http.go: "go-micro.dev/v4/cmd"
v4/server/mucp/mucp.go: "go-micro.dev/v4/cmd"
v4/broker/sqs/sqs.go: "go-micro.dev/v4/cmd"
v4/broker/snssqs/snssqs.go: "go-micro.dev/v4/cmd"
v4/broker/memory/memory.go: "go-micro.dev/v4/cmd"
v4/broker/googlepubsub/googlepubsub.go: "go-micro.dev/v4/cmd"
v4/broker/rabbitmq/rabbitmq.go: "go-micro.dev/v4/cmd"
v4/broker/stomp/stomp.go: "go-micro.dev/v4/cmd"
v4/broker/stan/stan.go: "go-micro.dev/v4/cmd"
v4/broker/grpc/grpc.go: "go-micro.dev/v4/cmd"
v4/broker/http/http.go: "go-micro.dev/v4/cmd"
v4/broker/nsq/nsq.go: "go-micro.dev/v4/cmd"
v4/broker/proxy/proxy.go: "go-micro.dev/v4/cmd"
v4/broker/segmentio/segmentio.go: "go-micro.dev/v4/cmd"
v4/broker/redis/redis.go: "go-micro.dev/v4/cmd"
v4/broker/kafka/kafka.go: "go-micro.dev/v4/cmd"
v4/broker/gocloud/gocloud.go: "go-micro.dev/v4/cmd"
v4/broker/mqtt/mqtt.go: "go-micro.dev/v4/cmd"
v4/broker/nats/nats.go: "go-micro.dev/v4/cmd"
v4/auth/jwt/jwt.go: "go-micro.dev/v4/cmd"
v4/store/cockroach/cockroach.go: "go-micro.dev/v4/cmd"
v4/store/mysql/mysql.go: "go-micro.dev/v4/cmd"
v4/store/file/file.go: "go-micro.dev/v4/cmd"
v4/store/memory/memory.go: "go-micro.dev/v4/cmd"
v4/store/nats-js/nats.go: "go-micro.dev/v4/cmd"
v4/store/memcached/memcached.go: "go-micro.dev/v4/cmd"
v4/store/consul/consul.go: "go-micro.dev/v4/cmd"
v4/store/redis/redis.go: "go-micro.dev/v4/cmd"
v4/registry/etcd/etcd.go: "go-micro.dev/v4/cmd"
v4/registry/mdns/mdns.go: "go-micro.dev/v4/cmd"
v4/registry/gossip/gossip.go: "go-micro.dev/v4/cmd"
v4/registry/eureka/eureka.go: "go-micro.dev/v4/cmd"
v4/registry/proxy/proxy.go: "go-micro.dev/v4/cmd"
v4/registry/nacos/nacos.go: "go-micro.dev/v4/cmd"
v4/registry/consul/consul.go: "go-micro.dev/v4/cmd"
v4/registry/kubernetes/kubernetes.go: "go-micro.dev/v4/cmd"
v4/registry/zookeeper/zookeeper.go: "go-micro.dev/v4/cmd"
v4/registry/nats/nats.go: "go-micro.dev/v4/cmd"
v4/selector/static/static.go: "go-micro.dev/v4/cmd"
v4/selector/registry/registry.go: "go-micro.dev/v4/cmd"
v4/selector/label/label.go: "go-micro.dev/v4/cmd"
v4/config/source/mucp/mucp.go: "go-micro.dev/v4/cmd"

RabbitMQ reconnect causes multiple connections to be created

The reconnecting triggered after the RabbitMQ channel is closed will cause the client side and server level to maintain multiple connections simultaneously.

When chanNotifyClose receives an error, the RabbitMQ connection isn't closed. It immediately establishes a new connection and subsequently recreates a channel based on this new connection.

case err := <-chanNotifyClose:

This can result in the client and server simultaneously holding both old and new connection resources. In this scenario, we can either manually close the old connection before reconnecting or reuse the existing connection resources.

how can i set the nacos GroupName

i use the [email protected] in my project , with nacos registry plugins, the question is how can i set the nacos client GroupName
my main.go code like this , i not found how can set that option.

clientConfig := *constant.NewClientConfig(
		constant.WithNotLoadCacheAtStart(true),
		constant.WithNamespaceId(global.RegistrySetting.NamespaceId),
		constant.WithCacheDir(global.RegistrySetting.CacheDir),
		constant.WithLogDir(global.RegistrySetting.LogDir),
	)
	registry := nacos.NewRegistry(nacos.WithClientConfig(clientConfig), nacos.WithAddress([]string{global.RegistrySetting.Host + ":" + strconv.Itoa(global.RegistrySetting.Port)}))


svc := micro.NewService(
		micro.Name(serviceName),
		micro.Registry(registry),
		micro.Config(serviceConfig),
	)

TCP transport race condition

WARNING: DATA RACE
Read at 0x00c0008508a8 by goroutine 142813:
  bufio.(*Writer).Available()
      /usr/lib/go/src/bufio/bufio.go:646 +0xef
  bufio.(*Writer).Write()
      /usr/lib/go/src/bufio/bufio.go:664 +0x26
  encoding/gob.(*Encoder).writeMessage()
      /usr/lib/go/src/encoding/gob/encoder.go:82 +0x774
  encoding/gob.(*Encoder).EncodeValue()
      /usr/lib/go/src/encoding/gob/encoder.go:253 +0x84a
  encoding/gob.(*Encoder).Encode()
      /usr/lib/go/src/encoding/gob/encoder.go:176 +0x15a
  github.com/go-micro/plugins/v4/transport/tcp.(*tcpTransportSocket).Send()
      /home/tyler/go/pkg/mod/github.com/go-micro/plugins/v4/transport/[email protected]/tcp.go:107 +0xfe
  go-micro.dev/v4/server.(*rpcServer).ServeConn.func3()
      /home/tyler/Launchpad/Micro/go-micro/server/rpc_server.go:353 +0x487
  go-micro.dev/v4/server.(*rpcServer).ServeConn.func5()
      /home/tyler/Launchpad/Micro/go-micro/server/rpc_server.go:357 +0x47

Previous write at 0x00c0008508a8 by goroutine 142778:
  bufio.(*Writer).Flush()
      /usr/lib/go/src/bufio/bufio.go:641 +0x328
  github.com/go-micro/plugins/v4/transport/tcp.(*tcpTransportSocket).Send()
      /home/tyler/go/pkg/mod/github.com/go-micro/plugins/v4/transport/[email protected]/tcp.go:110 +0x146
  go-micro.dev/v4/server.(*rpcServer).ServeConn.func3()
      /home/tyler/Launchpad/Micro/go-micro/server/rpc_server.go:353 +0x487
  go-micro.dev/v4/server.(*rpcServer).ServeConn.func5()
      /home/tyler/Launchpad/Micro/go-micro/server/rpc_server.go:357 +0x47

Goroutine 142813 (running) created at:
  go-micro.dev/v4/server.(*rpcServer).ServeConn()
      /home/tyler/Launchpad/Micro/go-micro/server/rpc_server.go:325 +0x205b
  go-micro.dev/v4/server.(*rpcServer).ServeConn-fm()
      <autogenerated>:1 +0x4d
  github.com/go-micro/plugins/v4/transport/tcp.(*tcpTransportListener).Accept.func1()
      /home/tyler/go/pkg/mod/github.com/go-micro/plugins/v4/transport/[email protected]/tcp.go:164 +0x81

Goroutine 142778 (finished) created at:
  go-micro.dev/v4/server.(*rpcServer).ServeConn()
      /home/tyler/Launchpad/Micro/go-micro/server/rpc_server.go:325 +0x205b
  go-micro.dev/v4/server.(*rpcServer).ServeConn-fm()
      <autogenerated>:1 +0x4d
  github.com/go-micro/plugins/v4/transport/tcp.(*tcpTransportListener).Accept.func1()
      /home/tyler/go/pkg/mod/github.com/go-micro/plugins/v4/transport/[email protected]/tcp.go:164 +0x81

[BUG] v4/server/grpc - Broker address is logged raw, potentially exposing credentials in logs

Describe the bug

  1. What are you trying to do?
    Utilize go-micro v4 with the grpc server/rabbitmq broker plugins, connecting to a broker authenticated with a username/password.

  2. What did you expect to happen?
    When the framework logs the broker address upon connection / disconnection, either the address should be omitted, or any embedded credentials should be redacted.

  3. What happens instead?
    The full address is logged upon connect / disconnect, as shown in the example below:

Broker [rabbitmq] Connected to amqp://<username>:<password>@localhost:5672

How to reproduce the bug:
Setup a broker with an address that embeds credentials, seems like the lines in question can be found here:

if logger.V(logger.InfoLevel, logger.DefaultLogger) {
logger.Infof("Broker [%s] Connected to %s", config.Broker.String(), config.Broker.Address())
}

plugins/v4/server/grpc/grpc.go

Lines 1015 to 1017 in 0ed40ba

if logger.V(logger.InfoLevel, logger.DefaultLogger) {
logger.Infof("Broker [%s] Disconnected from %s", config.Broker.String(), config.Broker.Address())
}

Environment:
Go Version: please paste go version output here

GO111MODULE=""
GOARCH="arm64"
GOBIN=""
GOCACHE="/Users/davidbereza/Library/Caches/go-build"
GOENV="/Users/davidbereza/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/davidbereza/go/pkg/mod"
GONOPROXY="github.com/vlognow/*"
GONOSUMDB="github.com/vlognow/*"
GOOS="darwin"
GOPATH="/Users/davidbereza/go"
GOPRIVATE="github.com/vlognow/*"
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/opt/homebrew/Cellar/go/1.18.4/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/opt/homebrew/Cellar/go/1.18.4/libexec/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.18.4"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/dev/null"
GOWORK=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/s_/p4h9rj3d2h3gjsw4ngyvb2kw0000gn/T/go-build1917015884=/tmp/go-build -gno-record-gcc-switches -fno-common"

nacos can not work

Before asking, please check if your question has already been answered:

service := micro.NewService(
		micro.Server(srv),
		micro.Registry(nacos.NewRegistry(registry.Addrs("192.168.144.17:8888"))),
	)

I have set addr 192.168.144.17:8888

BUT still
Try to connect to server on start up, server: {serverIp:127.0.0.1 serverPort:8848}

error message:

2022-01-25T12:22:20.516+0800	�[34mINFO�[0m	Local IP:192.168.144.17
2022-01-25T12:22:22.502+0800	�[33mWARN�[0m	[RpcClient.Start] 5c6b766a-ca55-4798-9f7c-608f93b64ad6 Fail to connect to server on start up, error message=rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing dial tcp 127.0.0.1:9848: connectex: No connection could be made because the target machine actively refused it.", start up retry times left=2
2022-01-25T12:22:22.502+0800	�[34mINFO�[0m	[RpcClient.Start] 5c6b766a-ca55-4798-9f7c-608f93b64ad6 Try to connect to server on start up, server: {serverIp:127.0.0.1 serverPort:8848}
2022-01-25T12:22:24.515+0800	�[33mWARN�[0m	[RpcClient.Start] 5c6b766a-ca55-4798-9f7c-608f93b64ad6 Fail to connect to server on start up, error message=rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing dial tcp 127.0.0.1:9848: connectex: No connection could be made because the target machine actively refused it.", start up retry times left=1
2022-01-25T12:22:24.515+0800	�[34mINFO�[0m	[RpcClient.Start] 5c6b766a-ca55-4798-9f7c-608f93b64ad6 Try to connect to server on start up, server: {serverIp:127.0.0.1 serverPort:8848}
2022-01-25T12:22:26.517+0800	�[33mWARN�[0m	[RpcClient.Start] 5c6b766a-ca55-4798-9f7c-608f93b64ad6 Fail to connect to server on start up, error message=rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing dial tcp 127.0.0.1:9848: connectex: No connection could be made because the target machine actively refused it.", start up retry times left=0
2022-01-25T12:22:26.517+0800	�[34mINFO�[0m	5c6b766a-ca55-4798-9f7c-608f93b64ad6 Register server push request:NotifySubscriberRequest handler:&{ServiceInfoHolder:0xc000086300}
2022-01-25T12:22:26.517+0800	�[34mINFO�[0m	5c6b766a-ca55-4798-9f7c-608f93b64ad6 try to re connect to a new server ,server is  not appointed,will choose a random server.
2022-01-25T12:22:26.517+0800	�[34mINFO�[0m	5c6b766a-ca55-4798-9f7c-608f93b64ad6 Register connection listener [&{clientProxy:0xc000490140 registeredInstanceCached:[0xc0000bcf20 0xc0000bcf40 0xc0000bcf60 0xc0000bcf80 0xc0000bcfa0 0xc0000bcfc0 0xc0000bcfe0 0xc0000bd000 0xc0000bd020 0xc0000bd040 0xc0000bd060 0xc0000bd080 0xc0000bd0a0 0xc0000bd0c0 0xc0000bd0e0 0xc0000bd100 0xc0000bd120 0xc0000bd140 0xc0000bd160 0xc0000bd180 0xc0000bd1a0 0xc0000bd1c0 0xc0000bd1e0 0xc0000bd200 0xc0000bd220 0xc0000bd240 0xc0000bd260 0xc0000bd280 0xc0000bd2a0 0xc0000bd2c0 0xc0000bd2e0 0xc0000bd300] subscribes:[0xc0000bd320 0xc0000bd340 0xc0000bd360 0xc0000bd380 0xc0000bd3a0 0xc0000bd3c0 0xc0000bd3e0 0xc0000bd400 0xc0000bd420 0xc0000bd440 0xc0000bd460 0xc0000bd480 0xc0000bd4a0 0xc0000bd4c0 0xc0000bd4e0 0xc0000bd500 0xc0000bd520 0xc0000bd540 0xc0000bd560 0xc0000bd580 0xc0000bd5a0 0xc0000bd5c0 0xc0000bd5e0 0xc0000bd600 0xc0000bd620 0xc0000bd640 0xc0000bd660 0xc0000bd680 0xc0000bd6a0 0xc0000bd6c0 0xc0000bd6e0 0xc0000bd700]}] to current client
2022-01-25T12:22:26.518+0800	�[31mERROR�[0m	Send request fail, request=&{NamingRequest:0xc0000700a0 Clusters: HealthyOnly:false UdpPort:0}, retryTimes=0xc00002a050,error=Client not connected,current status:1
2022-01-25T12:22:26.535+0800	�[34mINFO�[0m	register instance namespaceId:<public>,serviceName:<helloworld> with instance:<{"instanceId":"","ip":"192.168.144.17","port":80,"weight":1,"healthy":true,"enabled":true,"ephemeral":true,"clusterName":"","serviceName":"","metadata":{"broker":"http","protocol":"http","registry":"nacos","server":"http","version":"latest"},"instanceHeartBeatInterval":0,"ipDeleteTimeout":0,"instanceHeartBeatTimeOut":0}>
2022-01-25T12:22:26.535+0800	�[31mERROR�[0m	Send request fail, request=&{NamingRequest:0xc0003e0320 Type:registerInstance Instance:{InstanceId: Ip:192.168.144.17 Port:80 Weight:1 Healthy:true Enable:true Ephemeral:true ClusterName: ServiceName: Metadata:map[broker:http protocol:http registry:nacos server:http version:latest] InstanceHeartBeatInterval:0 IpDeleteTimeout:0 InstanceHeartBeatTimeOut:0}}, retryTimes=0xc0000ab220,error=Client not connected,current status:1
2022-01-25T12:22:26.618+0800	�[31mERROR�[0m	Send request fail, request=&{NamingRequest:0xc0000700a0 Clusters: HealthyOnly:false UdpPort:0}, retryTimes=0xc00002a050,error=Client not connected,current status:1
2022-01-25T12:22:26.636+0800	�[31mERROR�[0m	Send request fail, request=&{NamingRequest:0xc0003e0320 Type:registerInstance Instance:{InstanceId: Ip:192.168.144.17 Port:80 Weight:1 Healthy:true Enable:true Ephemeral:true ClusterName: ServiceName: Metadata:map[broker:http protocol:http registry:nacos server:http version:latest] InstanceHeartBeatInterval:0 IpDeleteTimeout:0 InstanceHeartBeatTimeOut:0}}, retryTimes=0xc0000ab220,error=Client not connected,current status:1
2022-01-25T12:22:26.719+0800	�[31mERROR�[0m	Send request fail, request=&{NamingRequest:0xc0000700a0 Clusters: HealthyOnly:false UdpPort:0}, retryTimes=0xc00002a050,error=Client not connected,current status:1
2022-01-25T12:22:26.737+0800	�[31mERROR�[0m	Send request fail, request=&{NamingRequest:0xc0003e0320 Type:registerInstance Instance:{InstanceId: Ip:192.168.144.17 Port:80 Weight:1 Healthy:true Enable:true Ephemeral:true ClusterName: ServiceName: Metadata:map[broker:http protocol:http registry:nacos server:http version:latest] InstanceHeartBeatInterval:0 IpDeleteTimeout:0 InstanceHeartBeatTimeOut:0}}, retryTimes=0xc0000ab220,error=Client not connected,current status:1
2022-01-25T12:22:26.820+0800	�[31mERROR�[0m	QueryList return error!serviceName:helloworld cluster: err:Client not connected,current status:1

consul plugin does not implement if the service is blank in watchOption

in the registry option define

type WatchOptions struct {
// Specify a service to watch
// If blank, the watch is for all services
Service string
// Other options for implementations of the interface
// can be stored in a context
Context context.Context
}

but consul plugin seems not implement this

func newConsulWatcher(cr *consulRegistry, opts ...registry.WatchOption) (registry.Watcher, error) {
var wo registry.WatchOptions
for _, o := range opts {
o(&wo)
}
cw := &consulWatcher{
r: cr,
wo: wo,
exit: make(chan bool),
next: make(chan *registry.Result, 10),
watchers: make(map[string]*watch.Plan),
services: make(map[string][]*registry.Service),
}
wp, err := watch.Parse(map[string]interface{}{
"service": wo.Service,
"type": "service",
})
if err != nil {
return nil, err
}
wp.Handler = cw.handle
go wp.RunWithClientAndHclog(cr.Client(), wp.Logger)
cw.wp = wp
return cw, nil
}

[BUG] Issues with store plugin redis

Describe the bug

In github.com/asim/go-micro/plugins/store/redis/v4 package :

  • List doesn't filter by table (ListFrom) . Also doesn't remove the table prefix in the return.
  • Read with ReadPrefix option doesn't fill the keys

How to reproduce the bug:

package main

import (
	"reflect"
	"testing"

	redisStore "github.com/asim/go-micro/plugins/store/redis/v4"
	"go-micro.dev/v4/store"
)

func init() {
	store.DefaultStore = redisStore.NewStore(store.Nodes("redis://redis:6379"))
}

func Test_store(t *testing.T) {
	store.DefaultStore.Write(
		&store.Record{Key: "key1", Value: []byte("val1")},
		store.WriteTo("", "table-a"),
	)
	store.DefaultStore.Write(
		&store.Record{Key: "key2", Value: []byte("val2")},
		store.WriteTo("", "table-b"),
	)
	store.DefaultStore.Write(
		&store.Record{Key: "key3", Value: []byte("val3")},
		store.WriteTo("", "table-a"),
	)

	gotList, _ := store.DefaultStore.List(store.ListFrom("", "table-a"))
	wantList := []string{"key1"}
	if !reflect.DeepEqual(gotList, wantList) {
		t.Errorf("DefaultStore.List() = %#v; want %#v", gotList, wantList)
	}

	gotRead, _ := store.DefaultStore.Read("", store.ReadFrom("", "table-a"), store.ReadPrefix())
	wantRead := []*store.Record{
		{Key: "key3", Value: []byte("val3"), Expiry: -1},
		{Key: "key1", Value: []byte("val1"), Expiry: -1},
	}
	if !reflect.DeepEqual(gotRead, wantRead) {
		t.Errorf("DefaultStore.Read() = %#v; want %#v", gotRead, wantRead)
		t.Errorf("DefaultStore.Read()[0] = %#v; want %#v", gotRead[0], wantRead[0])
		t.Errorf("DefaultStore.Read()[1] = %#v; want %#v", gotRead[1], wantRead[1])
	}

	gotRead, _ = store.DefaultStore.Read("key1", store.ReadFrom("", "table-a"))
	wantRead = []*store.Record{
		{Key: "key1", Value: []byte("val1"), Expiry: -1},
	}
	if !reflect.DeepEqual(gotRead, wantRead) {
		t.Errorf("DefaultStore.Read() = %#v; want %#v", gotRead, wantRead)
		t.Errorf("DefaultStore.Read()[0] = %#v; want %#v", gotRead[0], wantRead[0])
	}
}

Returns:

=== RUN   Test_store
    store_test.go:32: DefaultStore.List() = []string{"table-akey3", "table-bkey2", "table-akey1"}; want []string{"key1"}
    store_test.go:41: DefaultStore.Read() = []*store.Record{(*store.Record)(0xc000150000), (*store.Record)(0xc00007a000)}; want []*store.Record{(*store.Record)(0xc00007a040), (*store.Record)(0xc00007a080)}
    store_test.go:42: DefaultStore.Read()[0] = &store.Record{Key:"", Value:[]uint8{0x76, 0x61, 0x6c, 0x33}, Metadata:map[string]interface {}(nil), Expiry:-1}; want &store.Record{Key:"key3", Value:[]uint8{0x76, 0x61, 0x6c, 0x33}, Metadata:map[string]interface {}(nil), Expiry:-1}
    store_test.go:43: DefaultStore.Read()[1] = &store.Record{Key:"", Value:[]uint8{0x76, 0x61, 0x6c, 0x31}, Metadata:map[string]interface {}(nil), Expiry:-1}; want &store.Record{Key:"key1", Value:[]uint8{0x76, 0x61, 0x6c, 0x31}, Metadata:map[string]interface {}(nil), Expiry:-1}
--- FAIL: Test_store (0.06s)

Environment:

go version go1.16.14 linux/amd64

GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.16.14"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/workspace/data_management/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build2927763455=/tmp/go-build -gno-record-gcc-switches"

[BUG] github.com/asim/go-bson not found

go: downloading github.com/asim/go-bson v0.0.0-20160318195205-84522947cabd
bsonrpc.go:9:2: github.com/asim/[email protected]: invalid version: git fetch -f origin refs/heads/*:refs/heads/* refs/tags/*:refs/tags/* in /home/runner/go/pkg/mod/cache/vcs/21e914b1748907782789d893db54028cff7d9114adadce64be54e5c2b588956f: exit status 128:
	fatal: could not read Username for 'https://github.com/': terminal prompts disabled
Error: Process completed with exit code 1.

Add an option for consul http check

Currently there are only options to enable TCP/TTL service level checks in consul plugin. Need to extend it to support HTTP health checks as well

plugins/v4/config/source/configmap list/watch error

When I use ConfigMap as my config plugin, I found that the REST client for List/Watch is missing the GroupVersion information.

my configmap code is

err := config.DefaultConfig.Load(configmap.NewSource(configmap.WithName("auth-config"), configmap.WithNamespace("yunhang"), configmap.WithConfigPath("~/.kube/config")))

and the error log is

W0324 16:05:11.020136   88445 reflector.go:424] pkg/mod/k8s.io/[email protected]/tools/cache/reflector.go:169: failed to list *v1.ConfigMap: the server could not find the requested resource (get configmaps.meta.k8s.io)
E0324 16:05:11.020164   88445 reflector.go:140] pkg/mod/k8s.io/[email protected]/tools/cache/reflector.go:169: Failed to watch *v1.ConfigMap: failed to list *v1.ConfigMap: the server could not find the requested resource (get configmaps.meta.k8s.io)

and than i found list/watch url is

https://kubernetes.docker.internal:6443/namespaces/yunhang/configmaps

the correct url should be that.(miss api/v1)

https://kubernetes.docker.internal:6443/api/v1/namespaces/yunhang/configmaps

lw := cache.NewListWatchFromClient(w.client.RESTClient(), "configmaps", w.namespace, fields.OneTermEqualSelector("metadata.name", w.name))

I think the code might be like that, or do you have any better ideas?

 lw := cache.NewListWatchFromClient(w.client.CoreV1().RESTClient(), "configmaps", w.namespace, fields.OneTermEqualSelector("metadata.name", w.name))

[BUG] invalid character '-' in numeric literal.

Describe the bug

I've recently switched the to go-micro v4 & started getting this error while using the function config.Load().

It was supposed to load the config instead I am getting this error -> invalid character '-' in numeric literal

How to reproduce the bug

func loadConfigFile() error {
	enc := yaml.NewEncoder()

	// Configmap Path
	configMapPath, set := common.GetEnvVar("CONFIGMAP_PATH", "./testdata", true)
	if !set {
		return common.GetErrEnvVar("CONFIGMAP_PATH")
	}
	// Configmap yaml file name
	configMapFile, set := common.GetEnvVar("CONFIGMAP_FILE", "data.yml", true)
	if !set {
		return common.GetErrEnvVar("CONFIGMAP_FILE")
	}
	// Secret Path
	secretPath, set := common.GetEnvVar("SECRET_PATH", "./testdata", true)
	if !set {
		return common.GetErrEnvVar("SECRET_PATH")
	}
	// Secret yaml file name
	secretFile, set := common.GetEnvVar("SECRET_FILE", "secrets.yml", true)
	if !set {
		return common.GetErrEnvVar("SECRET_FILE")
	}

	// Load config sources
	if err := config.Load(
		file.NewSource(
			file.WithPath(configMapPath+"/"+configMapFile),
			source.WithEncoder(enc)),
		file.NewSource(
			file.WithPath(secretPath+"/"+secretFile),
			source.WithEncoder(enc),
		)); err != nil {
		        fmt.Println(err)
		)
		return errLoadConfigFile
	}

	// Watch a value for changes
	watcher, err := config.Watch()
	if err != nil {
	       fmt.Println("Error 2!")
		)
		return errWatchFileError
	}

	go processConfig(watcher)
	return nil
}

Here's my sample struct file.

package structs

// Config structure that holds Configurations for Bot Components
type Config struct {
	Channels  []Channel `json:"channels"`
	Constants Constants `json:"constants"`
	Bot       Bot       `json:"tbot"`
	Views     []View    `json:"views"`
	// Secrets
	Readme  string `json:"README"`
	Project string `json:"project_id"`
}

type Channel struct {
	ID          string      `json:"id"`
	Bot         Bot         `json:"bot"`
	PagerDuty   PagerDuty   `json:"pagerduty"`
	XMatters    XMatters    `json:"xmatters"`
	Enps        Enps        `json:"enps"`
	IssueType   IssueType   `json:"issuetype"`
	Support     Support     `json:"support"`
	Suggestions Suggestions `json:"suggestions"`
	Core        string      `json:"core"`
	Views       []View      `json:"views"`
}

type Support struct {
	MessageOnly         bool          `json:"messageOnly"`
	IgnoreCode          string        `json:"ignorecode"`
	AckCode             string        `json:"ackcode"`
	ResolveCode         string        `json:"resolvecode"`
	ChannelsToJoin      []string      `json:"channelstojoin"`
	ResolveReactionName string        `json:"resolvereactionname"`
	MaximumMessages     int           `json:"maximummessages"`
	MessagesPerWarning  int           `json:"messagesperwarning"`
	CronConfig          []CronSetting `json:"cronconfig"`
	ThreadEmoji         string        `json:"threadEmoji"`
	NoOfMsgForHistory   int           `json:"noOfMsgForHistory"`
	RespondToHere       bool          `json:"respondToHere"`
	RespondToChannel    bool          `json:"respondToChannel"`
	SlashCommand        SlashCommand  `json:"slashCommand"`
}

type Suggestions struct {
	SlackSuggest           bool     `json:"slackSuggest"`        // Turns on Slack Suggestions for threads
	SearchChannelName      []string `json:"searchChannelName"`   // The channel names you want to search
	SearchChannelID        []string `json:"searchChannelID"`     // The channel ID's you want to search
	SearchMessageCount     []int    `json:"searchMessageCount"`  // The count for threads you want per channel
	Keywords               []string `json:"keywords"`            // The keywords you want to use for a custom message
	KeywordTemplateID      []string `json:"keywordTemplateID"`   // The template for the keywords for a custom message
	KeysForThreadSearch    []string `json:"keysForThreadSearch"` // The keywords for thread search
	ThreadSearchCharacters int      `json:"threadSearchCharacters"`
}

type SlashCommand struct {
	OnCall      string `json:"onCall"`
	MyOnCall    string `json:"myOnCall"`
	OpenTickets string `json:"openTickets"`
	TbotHelp    string `json:"tbotHelp"`
}

type PagerDuty struct {
	PagerDutyServiceID               string `json:"pagerdutyserviceid"`
	PagerDutyDefaultServiceID        string `json:"pagerdutydefaultserviceid"`
	PagerDutyIncidentUrgency         string `json:"pagerdutyincidenturgency"`
	PagerDutyIncidentDefaultUrgency  string `json:"pagerdutyincidentdefaulturgency"`
	PagerDutyIncidentPriority        string `json:"pagerdutyincidentpriority"`
	PagerDutyIncidentDefaultPriority string `json:"pagerdutyincidentdefaultpriority"`
	PagerDutyScheduleID              string `json:"pagerdutyscheduleid"`
	PagerDutyTeamID                  string `json:"pagerdutyteamid"`
}

type XMatters struct {
	HostName    string `json:"hostName"`
	GroupName   string `json:"groupID"`
	ServiceName string `json:"serviceName"`
	Severity    string `json:"severity"`
}

type Enps struct {
	Enable    bool   `json:"enable"`
	TableName string `json:"tableName"`
}

type IssueType struct {
	Enable    bool   `json:"enable"`
	TableName string `json:"tableName"`
}

// Bot structure that holds Configuration Bot Configuration
type Bot struct {
	Name           string `json:"name"`
	AppMention     string `json:"appmention"`
	ChannelName    string `json:"channelName"`
	IconURL        string `json:"iconurl"`
	EnableWebhooks bool   `json:"enablewebhooks"`
}

// Constants structure that holds constants
type Constants struct {
	Ack          string `json:"ack"`
	Resolve      string `json:"resolve"`
	Note         string `json:"note"`
	CreateTicket string `json:"create_ticket,omitempty"`
}

// View structure that holds view
type View struct {
	ID       string `json:"id"`
	Template string `json:"template"`
}

Here's the sample yaml file.

---
data:
    channels:
        - ID: "CHANNEL_ID"
          bot:
              appmention: "@bot"
              channelName: "#testing-channel"
              name: "bot"
              EnableWebhooks: false
          xmatters:
              HostName: "xmatters.com"
              GroupName: "xMatters-service" Test Team"
              ServiceName: "xMatters-service"
              Severity: ""
          support:
              IgnoreCode: ":tmobile:"
              NoOfMessageHistory: 0
              ThreadEmoji: "thread-please"
              slashCommand:
                  Help: "/slack-slash"
          suggestions:
              SlackSuggest: false
              ThreadSearchCharacters: 40
              SearchChannelName:
                  - "#slack-channel-name"
              SearchChannelID:
                  - "SOME_CHANNEL"
              SearchMessageCount:
                  - 1
          enps:
              enable: false
              tableName: "enps"
          issueType:
              enable: true
              tableName: "issueTeams"
          core: "support"
          views:
              - id: "welcome.json"
                template: |
                    {
                            "blocks": [
                                {
                                    "type": "section",
                                    "text": {
                                        "type": "mrkdwn",
                                        "text": "Hi <@{{ .User }}> :wave: Welcome to the Support Channel."
                                    }
                                },
                                {
                                    "type": "section",
                                    "text": {
                                        "type": "mrkdwn",
                                        "text": "Please select from the dropdown box and click submit! Then, please read the documentation before creating a ticket. Thank you!"
                                    }
                                }
                            ]
                    }

Environment

Go Version: please paste go version output here

GOVERSION="go1.19.5"

micro service reg consul by extranet ip

I have two micro services deployed on different pc, the two services reg the same consul by extranet ip. However, the second service can't access to first service by rpc.

consul start-up: consul agent -server -ui -bootstrap-expect=1 -data-dir=/data/consul -node=hostname -bind=0.0.0.0 -advertise=49.234.57.x -client=0.0.0.0

first service(go-micro-v3):

func main() {
    service := micro.NewService(
        micro.Name("first"),
        micro.Registry(consul.NewRegistry(registry.Addrs("49.234.57.x:8500"))),
    )
    service.Init()
    pb.RegisterFirstHandler(service.Server(), new(handler.First))
    service.Run()
}

second service(go-micro-v3):

func main() {
    service := micro.NewService(
        micro.Name("second"),
        micro.Registry(consul.NewRegistry(registry.Addrs("49.234.57.x:8500"))),
    )
    service.Init()
    firstCli := pb.NewFirstService("first", service.Client())
    go func() {
        time.Sleep(1*time.Second)
        obj := &pb.Response{}
        data, err := firstCli.Hello(context.Background(), &pb.Request{})
        if err != nil {
             fmt.Println(err)
        } else {
            types.UnmarshalAny(data.GetData(), obj)
            fmt.Println(obj)
        }
    }
    service.Run()
}

Test:

  1. If the first/second server deployed on the same cloud pc, the second server can get data from the first server by rpc.
  2. If the first/second server deployed on different cloud pc(Both pc have access to all ports), I will get error:
    {"id":"go.micro.client","code":408,"detail":"call timeout: context deadline exceeded","status":"Request Timeout"}","time":"x"}

the second service(ip: 52.81.x.x) can get data from the first server(ip: 49.234.57.x) by extranet ip reg consul?

grpc shutdown advice

1680787350076

It is more appropriate to customize the timeout period here? Like net/HTTP, not all responses can be completed within 1 second

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.