mirror of
https://github.com/go-micro/go-micro.git
synced 2026-06-15 19:35:13 +02:00
Claude/update docs roadmap f zd2 j (#2872)
* docs: update all four documentation guides and mark Q2 complete - ai-native-services: add WithMCP one-liner, standalone gateway, WebSocket client example, and OpenTelemetry observability section - mcp-security: add OTel distributed tracing, WebSocket authentication (connection-level and per-message), DeniedReason audit field - tool-descriptions: add manual overrides with WithEndpointDocs and export formats section - agent-patterns: add LangChain/LlamaIndex SDK pattern and standalone gateway production pattern with Docker example - Update roadmap: mark Q2 documentation as complete, Q2 at 100% - Update status: reflect all recent completions, shift priorities https://claude.ai/code/session_01GkduEhcrqcG45rdfYh8dAc * feat: add agent demo example and blog post Add examples/agent-demo with a multi-service project management app (projects, tasks, team) that demonstrates AI agents interacting with Go Micro services through MCP. Includes seed data and example prompts. Add blog post 4 "Agents Meet Microservices: A Hands-On Demo" walking through the example code and showing cross-service agent workflows. https://claude.ai/code/session_01GkduEhcrqcG45rdfYh8dAc * feat: enable multiple services in a single binary Remove global state mutations from service and cmd option functions so that configuring one service no longer overwrites another's settings. Key changes: - service/options.go: remove all DefaultXxx global writes from option functions; newOptions() now creates fresh Server, Client, Store, and Cache per service while sharing Registry, Broker, and Transport - cmd/cmd.go: newCmd() uses local copies instead of pointers to package globals; Before() no longer mutates DefaultXxx vars - cmd/options.go: remove global mutations from all option functions - service/service.go: export ServiceImpl type for cross-package use - service/group.go: new Group type for multi-service lifecycle - micro.go: add Start/Stop to Service interface, expose Group and NewGroup convenience function - examples/multi-service: working example with two services https://claude.ai/code/session_01GkduEhcrqcG45rdfYh8dAc * docs: highlight multi-service binary support Add multi-service section to README with code example, update features list, add to examples index, and note in status summary. https://claude.ai/code/session_01GkduEhcrqcG45rdfYh8dAc --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -186,6 +186,7 @@ Build compelling examples and demos that show agents interacting with go-micro s
|
||||
- **Kubernetes Operator** - CRD-based deployment
|
||||
|
||||
### Recently Completed (March 2026)
|
||||
- **Multi-Service Binaries** - Run multiple services in a single binary with isolated state per service and shared lifecycle via `service.Group`. Modular monolith pattern: start together, split later.
|
||||
- **Documentation Guides** - All four guides complete: AI-native services, MCP security, tool descriptions, agent patterns
|
||||
- **WithMCP Convenience Option** - One-line MCP setup: `mcp.WithMCP(":3000")`
|
||||
- **Agent Playground Redesign** - Chat-focused UI with collapsible tool calls and real-time status
|
||||
|
||||
@@ -45,6 +45,10 @@ in the plugins repo. State and persistence becomes a core requirement beyond pro
|
||||
- **MCP Integration** - An MCP gateway you can integrate as a library, server or CLI command which automatically exposes services
|
||||
as tools for agents or other AI applications. Every service/endpoint get's converted into a callable tool.
|
||||
|
||||
- **Multi-Service Binaries** - Run multiple services in a single process with isolated state per service. Start as a modular monolith,
|
||||
split into separate deployments when you need independent scaling. Each service gets its own server, client, and store while sharing
|
||||
the registry and broker for inter-service communication.
|
||||
|
||||
- **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.
|
||||
|
||||
@@ -144,11 +148,32 @@ Use `micro mcp serve` for local AI tools like Claude Code, or connect any MCP-co
|
||||
|
||||
See the [MCP guide](https://go-micro.dev/docs/mcp.html) for authentication, scopes, and advanced usage.
|
||||
|
||||
## Multi-Service Binaries
|
||||
|
||||
Run multiple services in a single binary — start as a modular monolith, split into separate deployments later when you actually need to.
|
||||
|
||||
```go
|
||||
users := service.New(service.Name("users"), service.Address(":9001"))
|
||||
orders := service.New(service.Name("orders"), service.Address(":9002"))
|
||||
|
||||
users.Handle(new(Users))
|
||||
orders.Handle(new(Orders))
|
||||
|
||||
// Run all services together with shared lifecycle
|
||||
g := service.NewGroup(users, orders)
|
||||
g.Run()
|
||||
```
|
||||
|
||||
Each service gets its own server, client, store, and cache while sharing the registry, broker, and transport — so they can discover and call each other within the same process.
|
||||
|
||||
See the [multi-service example](examples/multi-service/) for a working demo.
|
||||
|
||||
## Examples
|
||||
|
||||
Check out [/examples](examples/) for runnable code:
|
||||
- [hello-world](examples/hello-world/) - Basic RPC service
|
||||
- [web-service](examples/web-service/) - HTTP REST API
|
||||
- [multi-service](examples/multi-service/) - Multiple services in one binary
|
||||
- [mcp](examples/mcp/) - MCP integration with AI agents
|
||||
|
||||
See [all examples](examples/README.md) for more.
|
||||
|
||||
+30
-30
@@ -299,20 +299,37 @@ func init() {
|
||||
}
|
||||
|
||||
func newCmd(opts ...Option) Cmd {
|
||||
// Create local copies so each cmd instance is isolated.
|
||||
// This allows multiple services in a single binary without
|
||||
// conflicting through shared global pointers.
|
||||
localAuth := auth.DefaultAuth
|
||||
localBroker := broker.DefaultBroker
|
||||
localClient := client.DefaultClient
|
||||
localRegistry := registry.DefaultRegistry
|
||||
localServer := server.DefaultServer
|
||||
localSelector := selector.DefaultSelector
|
||||
localTransport := transport.DefaultTransport
|
||||
localStore := store.DefaultStore
|
||||
localTracer := trace.DefaultTracer
|
||||
localProfile := profile.DefaultProfile
|
||||
localConfig := config.DefaultConfig
|
||||
localCache := cache.DefaultCache
|
||||
localStream := events.DefaultStream
|
||||
|
||||
options := Options{
|
||||
Auth: &auth.DefaultAuth,
|
||||
Broker: &broker.DefaultBroker,
|
||||
Client: &client.DefaultClient,
|
||||
Registry: ®istry.DefaultRegistry,
|
||||
Server: &server.DefaultServer,
|
||||
Selector: &selector.DefaultSelector,
|
||||
Transport: &transport.DefaultTransport,
|
||||
Store: &store.DefaultStore,
|
||||
Tracer: &trace.DefaultTracer,
|
||||
DebugProfile: &profile.DefaultProfile,
|
||||
Config: &config.DefaultConfig,
|
||||
Cache: &cache.DefaultCache,
|
||||
Stream: &events.DefaultStream,
|
||||
Auth: &localAuth,
|
||||
Broker: &localBroker,
|
||||
Client: &localClient,
|
||||
Registry: &localRegistry,
|
||||
Server: &localServer,
|
||||
Selector: &localSelector,
|
||||
Transport: &localTransport,
|
||||
Store: &localStore,
|
||||
Tracer: &localTracer,
|
||||
DebugProfile: &localProfile,
|
||||
Config: &localConfig,
|
||||
Cache: &localCache,
|
||||
Stream: &localStream,
|
||||
|
||||
Brokers: DefaultBrokers,
|
||||
Clients: DefaultClients,
|
||||
@@ -381,13 +398,9 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
return fmt.Errorf("failed to load local profile: %v", ierr)
|
||||
}
|
||||
*c.opts.Registry = imported.Registry
|
||||
registry.DefaultRegistry = imported.Registry
|
||||
*c.opts.Broker = imported.Broker
|
||||
broker.DefaultBroker = imported.Broker
|
||||
*c.opts.Store = imported.Store
|
||||
store.DefaultStore = imported.Store
|
||||
*c.opts.Transport = imported.Transport
|
||||
transport.DefaultTransport = imported.Transport
|
||||
case "nats":
|
||||
imported, ierr := mprofile.NatsProfile()
|
||||
if ierr != nil {
|
||||
@@ -428,7 +441,6 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
// only change if we have the client and type differs
|
||||
if cl, ok := c.opts.Clients[name]; ok && (*c.opts.Client).String() != name {
|
||||
*c.opts.Client = cl()
|
||||
client.DefaultClient = *c.opts.Client
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,7 +449,6 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
// only change if we have the server and type differs
|
||||
if s, ok := c.opts.Servers[name]; ok && (*c.opts.Server).String() != name {
|
||||
*c.opts.Server = s()
|
||||
server.DefaultServer = *c.opts.Server
|
||||
}
|
||||
}
|
||||
|
||||
@@ -449,7 +460,6 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
}
|
||||
|
||||
*c.opts.Store = s(store.WithClient(*c.opts.Client))
|
||||
store.DefaultStore = *c.opts.Store
|
||||
}
|
||||
|
||||
// Set the tracer
|
||||
@@ -460,7 +470,6 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
}
|
||||
|
||||
*c.opts.Tracer = r()
|
||||
trace.DefaultTracer = *c.opts.Tracer
|
||||
}
|
||||
|
||||
// Setup auth
|
||||
@@ -487,7 +496,6 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
}
|
||||
|
||||
*c.opts.Auth = r(authOpts...)
|
||||
auth.DefaultAuth = *c.opts.Auth
|
||||
}
|
||||
|
||||
// Set the registry
|
||||
@@ -509,7 +517,6 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
return fmt.Errorf("unsupported profile: %s", name)
|
||||
}
|
||||
*c.opts.DebugProfile = p()
|
||||
profile.DefaultProfile = *c.opts.DebugProfile
|
||||
}
|
||||
|
||||
// Set the broker
|
||||
@@ -534,7 +541,6 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
|
||||
// No server option here. Should there be?
|
||||
clientOpts = append(clientOpts, client.Selector(*c.opts.Selector))
|
||||
selector.DefaultSelector = *c.opts.Selector
|
||||
}
|
||||
|
||||
// Set the transport
|
||||
@@ -687,7 +693,6 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
logger.Fatalf("Error configuring config: %v", err)
|
||||
}
|
||||
*c.opts.Config = rc
|
||||
config.DefaultConfig = *c.opts.Config
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -709,7 +714,6 @@ func (c *cmd) setRegistry(r registry.Registry) ([]server.Option, []client.Option
|
||||
if err := (*c.opts.Broker).Init(broker.Registry(*c.opts.Registry)); err != nil {
|
||||
logger.Fatalf("Error configuring broker: %v", err)
|
||||
}
|
||||
registry.DefaultRegistry = *c.opts.Registry
|
||||
return serverOpts, clientOpts
|
||||
}
|
||||
func (c *cmd) setStream(s events.Stream) ([]server.Option, []client.Option) {
|
||||
@@ -720,7 +724,6 @@ func (c *cmd) setStream(s events.Stream) ([]server.Option, []client.Option) {
|
||||
// serverOpts = append(serverOpts, server.Registry(*c.opts.Registry))
|
||||
// clientOpts = append(clientOpts, client.Registry(*c.opts.Registry))
|
||||
|
||||
events.DefaultStream = *c.opts.Stream
|
||||
return serverOpts, clientOpts
|
||||
}
|
||||
|
||||
@@ -730,7 +733,6 @@ func (c *cmd) setBroker(b broker.Broker) ([]server.Option, []client.Option) {
|
||||
*c.opts.Broker = b
|
||||
serverOpts = append(serverOpts, server.Broker(*c.opts.Broker))
|
||||
clientOpts = append(clientOpts, client.Broker(*c.opts.Broker))
|
||||
broker.DefaultBroker = *c.opts.Broker
|
||||
return serverOpts, clientOpts
|
||||
}
|
||||
|
||||
@@ -738,7 +740,6 @@ func (c *cmd) setStore(s store.Store) ([]server.Option, []client.Option) {
|
||||
var serverOpts []server.Option
|
||||
var clientOpts []client.Option
|
||||
*c.opts.Store = s
|
||||
store.DefaultStore = *c.opts.Store
|
||||
return serverOpts, clientOpts
|
||||
}
|
||||
|
||||
@@ -748,7 +749,6 @@ func (c *cmd) setTransport(t transport.Transport) ([]server.Option, []client.Opt
|
||||
*c.opts.Transport = t
|
||||
serverOpts = append(serverOpts, server.Transport(*c.opts.Transport))
|
||||
clientOpts = append(clientOpts, client.Transport(*c.opts.Transport))
|
||||
transport.DefaultTransport = *c.opts.Transport
|
||||
return serverOpts, clientOpts
|
||||
}
|
||||
|
||||
|
||||
@@ -84,91 +84,78 @@ func Version(v string) Option {
|
||||
func Broker(b *broker.Broker) Option {
|
||||
return func(o *Options) {
|
||||
o.Broker = b
|
||||
broker.DefaultBroker = *b
|
||||
}
|
||||
}
|
||||
|
||||
func Cache(c *cache.Cache) Option {
|
||||
return func(o *Options) {
|
||||
o.Cache = c
|
||||
cache.DefaultCache = *c
|
||||
}
|
||||
}
|
||||
|
||||
func Config(c *config.Config) Option {
|
||||
return func(o *Options) {
|
||||
o.Config = c
|
||||
config.DefaultConfig = *c
|
||||
}
|
||||
}
|
||||
|
||||
func Selector(s *selector.Selector) Option {
|
||||
return func(o *Options) {
|
||||
o.Selector = s
|
||||
selector.DefaultSelector = *s
|
||||
}
|
||||
}
|
||||
|
||||
func Registry(r *registry.Registry) Option {
|
||||
return func(o *Options) {
|
||||
o.Registry = r
|
||||
registry.DefaultRegistry = *r
|
||||
}
|
||||
}
|
||||
|
||||
func Transport(t *transport.Transport) Option {
|
||||
return func(o *Options) {
|
||||
o.Transport = t
|
||||
transport.DefaultTransport = *t
|
||||
}
|
||||
}
|
||||
|
||||
func Client(c *client.Client) Option {
|
||||
return func(o *Options) {
|
||||
o.Client = c
|
||||
client.DefaultClient = *c
|
||||
}
|
||||
}
|
||||
|
||||
func Server(s *server.Server) Option {
|
||||
return func(o *Options) {
|
||||
o.Server = s
|
||||
server.DefaultServer = *s
|
||||
}
|
||||
}
|
||||
|
||||
func Store(s *store.Store) Option {
|
||||
return func(o *Options) {
|
||||
o.Store = s
|
||||
store.DefaultStore = *s
|
||||
}
|
||||
}
|
||||
|
||||
func Stream(s *events.Stream) Option {
|
||||
return func(o *Options) {
|
||||
o.Stream = s
|
||||
events.DefaultStream = *s
|
||||
}
|
||||
}
|
||||
|
||||
func Tracer(t *trace.Tracer) Option {
|
||||
return func(o *Options) {
|
||||
o.Tracer = t
|
||||
trace.DefaultTracer = *t
|
||||
}
|
||||
}
|
||||
|
||||
func Auth(a *auth.Auth) Option {
|
||||
return func(o *Options) {
|
||||
o.Auth = a
|
||||
auth.DefaultAuth = *a
|
||||
}
|
||||
}
|
||||
|
||||
func Profile(p *profile.Profile) Option {
|
||||
return func(o *Options) {
|
||||
o.DebugProfile = p
|
||||
profile.DefaultProfile = *p
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,19 @@ cd web-service
|
||||
go run .
|
||||
```
|
||||
|
||||
### [multi-service](./multi-service/)
|
||||
Multiple services in a single binary — the modular monolith pattern:
|
||||
- Isolated server, client, store, and cache per service
|
||||
- Shared registry and broker for inter-service communication
|
||||
- Coordinated lifecycle with `service.Group`
|
||||
- Start monolith, split later when you need to scale independently
|
||||
|
||||
**Run it:**
|
||||
```bash
|
||||
cd multi-service
|
||||
go run .
|
||||
```
|
||||
|
||||
## Coming Soon
|
||||
|
||||
The following examples are planned:
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
// Multi-service example: run multiple services in a single binary.
|
||||
//
|
||||
// Each service gets its own server, client, store, and cache while
|
||||
// sharing the registry, broker, and transport — so they can
|
||||
// discover and call each other within the same process.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"go-micro.dev/v5/service"
|
||||
)
|
||||
|
||||
// -- Users service --
|
||||
|
||||
type UserRequest struct {
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
type UserResponse struct {
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
type Users struct{}
|
||||
|
||||
func (u *Users) Lookup(ctx context.Context, req *UserRequest, rsp *UserResponse) error {
|
||||
log.Printf("[users] Lookup id=%s", req.Id)
|
||||
rsp.Name = "Alice"
|
||||
rsp.Email = "alice@example.com"
|
||||
return nil
|
||||
}
|
||||
|
||||
// -- Orders service --
|
||||
|
||||
type OrderRequest struct {
|
||||
UserId string `json:"user_id"`
|
||||
}
|
||||
|
||||
type OrderResponse struct {
|
||||
OrderId string `json:"order_id"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type Orders struct{}
|
||||
|
||||
func (o *Orders) Create(ctx context.Context, req *OrderRequest, rsp *OrderResponse) error {
|
||||
log.Printf("[orders] Create for user=%s", req.UserId)
|
||||
rsp.OrderId = "ORD-001"
|
||||
rsp.Status = "created"
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Create two services — each gets isolated server, client,
|
||||
// store, and cache instances automatically.
|
||||
users := service.New(
|
||||
service.Name("users"),
|
||||
service.Address(":9001"),
|
||||
)
|
||||
|
||||
orders := service.New(
|
||||
service.Name("orders"),
|
||||
service.Address(":9002"),
|
||||
)
|
||||
|
||||
// Register handlers
|
||||
if err := users.Handle(new(Users)); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := orders.Handle(new(Orders)); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Run both services together. The group handles signals
|
||||
// and stops all services when one exits.
|
||||
g := service.NewGroup(users, orders)
|
||||
|
||||
fmt.Println("Starting users (:9001) and orders (:9002) in a single binary")
|
||||
if err := g.Run(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -27,12 +27,19 @@ type Service interface {
|
||||
Client() client.Client
|
||||
// Server is for handling requests and events
|
||||
Server() server.Server
|
||||
// Run the service
|
||||
// Start the service
|
||||
Start() error
|
||||
// Stop the service
|
||||
Stop() error
|
||||
// Run the service (start, block on signal, then stop)
|
||||
Run() error
|
||||
// The service implementation
|
||||
String() string
|
||||
}
|
||||
|
||||
// Group is a set of services that share lifecycle management.
|
||||
type Group = service.Group
|
||||
|
||||
type Option = service.Option
|
||||
|
||||
type Options = service.Options
|
||||
@@ -58,6 +65,18 @@ func NewService(opts ...Option) Service {
|
||||
return service.New(opts...)
|
||||
}
|
||||
|
||||
// NewGroup creates a service group for running multiple services
|
||||
// in a single binary with shared lifecycle management.
|
||||
func NewGroup(svcs ...Service) *Group {
|
||||
var ss []*service.ServiceImpl
|
||||
for _, s := range svcs {
|
||||
if si, ok := s.(*service.ServiceImpl); ok {
|
||||
ss = append(ss, si)
|
||||
}
|
||||
}
|
||||
return service.NewGroup(ss...)
|
||||
}
|
||||
|
||||
// FromContext retrieves a Service from the Context.
|
||||
func FromContext(ctx context.Context) (Service, bool) {
|
||||
s, ok := ctx.Value(serviceKey{}).(Service)
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
|
||||
log "go-micro.dev/v5/logger"
|
||||
signalutil "go-micro.dev/v5/util/signal"
|
||||
)
|
||||
|
||||
// Group runs multiple services in a single binary with shared
|
||||
// lifecycle management. All services start together and stop
|
||||
// together on signal or context cancellation.
|
||||
type Group struct {
|
||||
services []*ServiceImpl
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
// NewGroup creates a new service group.
|
||||
func NewGroup(svcs ...*ServiceImpl) *Group {
|
||||
return &Group{
|
||||
services: svcs,
|
||||
logger: log.DefaultLogger,
|
||||
}
|
||||
}
|
||||
|
||||
// Add appends one or more services to the group.
|
||||
func (g *Group) Add(svcs ...*ServiceImpl) {
|
||||
g.services = append(g.services, svcs...)
|
||||
}
|
||||
|
||||
// Run starts all services concurrently and blocks until a signal
|
||||
// is received or the context is cancelled, then stops all services.
|
||||
func (g *Group) Run() error {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// Initialize all services (parses flags, etc.)
|
||||
for _, svc := range g.services {
|
||||
svc.opts.Signal = false // group handles signals
|
||||
svc.Init()
|
||||
}
|
||||
|
||||
g.logger.Logf(log.InfoLevel, "Starting service group with %d services", len(g.services))
|
||||
|
||||
// Start all services concurrently
|
||||
errCh := make(chan error, len(g.services))
|
||||
for _, svc := range g.services {
|
||||
g.logger.Logf(log.InfoLevel, "Starting [service] %s", svc.Name())
|
||||
if err := svc.Start(); err != nil {
|
||||
// If any service fails to start, stop the ones that did start
|
||||
cancel()
|
||||
g.stopAll()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for signal or context cancellation
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch, signalutil.Shutdown()...)
|
||||
|
||||
select {
|
||||
case <-ch:
|
||||
g.logger.Logf(log.InfoLevel, "Received signal, stopping all services")
|
||||
case <-ctx.Done():
|
||||
case err := <-errCh:
|
||||
cancel()
|
||||
g.stopAll()
|
||||
return err
|
||||
}
|
||||
|
||||
return g.stopAll()
|
||||
}
|
||||
|
||||
func (g *Group) stopAll() error {
|
||||
var (
|
||||
mu sync.Mutex
|
||||
lastErr error
|
||||
)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for _, svc := range g.services {
|
||||
wg.Add(1)
|
||||
go func(s *ServiceImpl) {
|
||||
defer wg.Done()
|
||||
g.logger.Logf(log.InfoLevel, "Stopping [service] %s", s.Name())
|
||||
if err := s.Stop(); err != nil {
|
||||
mu.Lock()
|
||||
lastErr = err
|
||||
mu.Unlock()
|
||||
}
|
||||
}(svc)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
return lastErr
|
||||
}
|
||||
+7
-17
@@ -56,12 +56,14 @@ func newOptions(opts ...Option) Options {
|
||||
opt := Options{
|
||||
Auth: auth.DefaultAuth,
|
||||
Broker: broker.DefaultBroker,
|
||||
Cache: cache.DefaultCache,
|
||||
Cmd: cmd.DefaultCmd,
|
||||
Cmd: cmd.NewCmd(),
|
||||
Config: config.DefaultConfig,
|
||||
Client: client.DefaultClient,
|
||||
Server: server.DefaultServer,
|
||||
Store: store.DefaultStore,
|
||||
// Per-service instances: each service gets its own server, client,
|
||||
// store, and cache to allow multiple services in a single binary.
|
||||
Client: client.NewClient(),
|
||||
Server: server.NewRPCServer(),
|
||||
Store: store.NewStore(),
|
||||
Cache: cache.NewCache(),
|
||||
Registry: registry.DefaultRegistry,
|
||||
Transport: transport.DefaultTransport,
|
||||
Context: context.Background(),
|
||||
@@ -83,14 +85,12 @@ func Broker(b broker.Broker) Option {
|
||||
// Update Client and Server
|
||||
o.Client.Init(client.Broker(b))
|
||||
o.Server.Init(server.Broker(b))
|
||||
broker.DefaultBroker = b
|
||||
}
|
||||
}
|
||||
|
||||
func Cache(c cache.Cache) Option {
|
||||
return func(o *Options) {
|
||||
o.Cache = c
|
||||
cache.DefaultCache = c
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,6 @@ func Cmd(c cmd.Cmd) Option {
|
||||
func Client(c client.Client) Option {
|
||||
return func(o *Options) {
|
||||
o.Client = c
|
||||
client.DefaultClient = c
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +137,6 @@ func HandleSignal(b bool) Option {
|
||||
func Profile(p profile.Profile) Option {
|
||||
return func(o *Options) {
|
||||
o.Profile = p
|
||||
profile.DefaultProfile = p
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +144,6 @@ func Profile(p profile.Profile) Option {
|
||||
func Server(s server.Server) Option {
|
||||
return func(o *Options) {
|
||||
o.Server = s
|
||||
server.DefaultServer = s
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,7 +151,6 @@ func Server(s server.Server) Option {
|
||||
func Store(s store.Store) Option {
|
||||
return func(o *Options) {
|
||||
o.Store = s
|
||||
store.DefaultStore = s
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +164,6 @@ func Registry(r registry.Registry) Option {
|
||||
o.Server.Init(server.Registry(r))
|
||||
// Update Broker
|
||||
o.Broker.Init(broker.Registry(r))
|
||||
broker.DefaultBroker = o.Broker
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,8 +179,6 @@ func Tracer(t trace.Tracer) Option {
|
||||
func Auth(a auth.Auth) Option {
|
||||
return func(o *Options) {
|
||||
o.Auth = a
|
||||
auth.DefaultAuth = a
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,7 +186,6 @@ func Auth(a auth.Auth) Option {
|
||||
func Config(c config.Config) Option {
|
||||
return func(o *Options) {
|
||||
o.Config = c
|
||||
config.DefaultConfig = c
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,7 +193,6 @@ func Config(c config.Config) Option {
|
||||
func Selector(s selector.Selector) Option {
|
||||
return func(o *Options) {
|
||||
o.Client.Init(client.Selector(s))
|
||||
selector.DefaultSelector = s
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,7 +204,6 @@ func Transport(t transport.Transport) Option {
|
||||
// Update Client and Server
|
||||
o.Client.Init(client.Transport(t))
|
||||
o.Server.Init(server.Transport(t))
|
||||
transport.DefaultTransport = t
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+16
-13
@@ -14,26 +14,29 @@ import (
|
||||
signalutil "go-micro.dev/v5/util/signal"
|
||||
)
|
||||
|
||||
type service struct {
|
||||
// ServiceImpl is the concrete service implementation. It is exported
|
||||
// to allow the micro package to construct Groups, but users should
|
||||
// generally interact through the Service interface.
|
||||
type ServiceImpl struct {
|
||||
opts Options
|
||||
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
func New(opts ...Option) *service {
|
||||
return &service{
|
||||
func New(opts ...Option) *ServiceImpl {
|
||||
return &ServiceImpl{
|
||||
opts: newOptions(opts...),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *service) Name() string {
|
||||
func (s *ServiceImpl) Name() string {
|
||||
return s.opts.Server.Options().Name
|
||||
}
|
||||
|
||||
// Init initializes options. Additionally it calls cmd.Init
|
||||
// which parses command line flags. cmd.Init is only called
|
||||
// on first Init.
|
||||
func (s *service) Init(opts ...Option) {
|
||||
func (s *ServiceImpl) Init(opts ...Option) {
|
||||
// process options
|
||||
for _, o := range opts {
|
||||
o(&s.opts)
|
||||
@@ -69,23 +72,23 @@ func (s *service) Init(opts ...Option) {
|
||||
})
|
||||
}
|
||||
|
||||
func (s *service) Options() Options {
|
||||
func (s *ServiceImpl) Options() Options {
|
||||
return s.opts
|
||||
}
|
||||
|
||||
func (s *service) Client() client.Client {
|
||||
func (s *ServiceImpl) Client() client.Client {
|
||||
return s.opts.Client
|
||||
}
|
||||
|
||||
func (s *service) Server() server.Server {
|
||||
func (s *ServiceImpl) Server() server.Server {
|
||||
return s.opts.Server
|
||||
}
|
||||
|
||||
func (s *service) String() string {
|
||||
func (s *ServiceImpl) String() string {
|
||||
return "micro"
|
||||
}
|
||||
|
||||
func (s *service) Start() error {
|
||||
func (s *ServiceImpl) Start() error {
|
||||
for _, fn := range s.opts.BeforeStart {
|
||||
if err := fn(); err != nil {
|
||||
return err
|
||||
@@ -105,7 +108,7 @@ func (s *service) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *service) Stop() error {
|
||||
func (s *ServiceImpl) Stop() error {
|
||||
var err error
|
||||
|
||||
for _, fn := range s.opts.BeforeStop {
|
||||
@@ -123,13 +126,13 @@ func (s *service) Stop() error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *service) Handle(v interface{}) error {
|
||||
func (s *ServiceImpl) Handle(v interface{}) error {
|
||||
return s.opts.Server.Handle(
|
||||
s.opts.Server.NewHandler(v),
|
||||
)
|
||||
}
|
||||
|
||||
func (s *service) Run() (err error) {
|
||||
func (s *ServiceImpl) Run() (err error) {
|
||||
logger := s.opts.Logger
|
||||
|
||||
// exit when help flag is provided
|
||||
|
||||
Reference in New Issue
Block a user