micro--go-micro
d2036b880d
* 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 * feat: unify service API and clean up developer experience - Unified service creation: micro.New("name", opts...) as canonical API - Clean handler registration: service.Handle(handler, opts...) accepts server.HandlerOption args directly, no need to reach through Server() - Unexported serviceImpl: users interact through Service interface only - Service groups use Service interface (not concrete type) - Fixed Stop() to properly propagate BeforeStop/AfterStop errors - Fixed store init: error-level log instead of fatal on init failure - Updated all examples to use consistent patterns - Updated README, getting-started, MCP docs, and guides - Added blog post about the DX cleanup https://claude.ai/code/session_01GkduEhcrqcG45rdfYh8dAc --------- Co-authored-by: Claude <noreply@anthropic.com>
99 行
2.1 KiB
Go
99 行
2.1 KiB
Go
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 []Service
|
|
logger log.Logger
|
|
}
|
|
|
|
// NewGroup creates a new service group.
|
|
func NewGroup(svcs ...Service) *Group {
|
|
return &Group{
|
|
services: svcs,
|
|
logger: log.DefaultLogger,
|
|
}
|
|
}
|
|
|
|
// Add appends one or more services to the group.
|
|
func (g *Group) Add(svcs ...Service) {
|
|
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. Disable per-service signal handling
|
|
// since the group manages signals.
|
|
for _, svc := range g.services {
|
|
svc.Init(HandleSignal(false))
|
|
}
|
|
|
|
g.logger.Logf(log.InfoLevel, "Starting service group with %d services", len(g.services))
|
|
|
|
// Start all services
|
|
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 {
|
|
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 Service) {
|
|
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
|
|
}
|