1
0
mirror of https://github.com/go-micro/go-micro.git synced 2025-11-23 21:44:41 +02:00

major docs overhaul

This commit is contained in:
Asim Aslam
2025-11-13 18:34:40 +00:00
parent e755e4a823
commit 8cda829320
16 changed files with 2460 additions and 0 deletions

44
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,44 @@
---
name: Bug report
about: Create a report to help us improve
title: '[BUG] '
labels: bug
assignees: ''
---
## Describe the bug
A clear and concise description of what the bug is.
## To Reproduce
Steps to reproduce the behavior:
1. Create service with '...'
2. Configure plugin '...'
3. Run command '...'
4. See error
## Expected behavior
A clear and concise description of what you expected to happen.
## Code sample
```go
// Minimal reproducible code
```
## Environment
- Go Micro version: [e.g. v5.3.0]
- Go version: [e.g. 1.21.0]
- OS: [e.g. Ubuntu 22.04]
- Plugins used: [e.g. consul registry, nats broker]
## Logs
```
Paste relevant logs here
```
## Additional context
Add any other context about the problem here.
## Resources
- [Documentation](https://github.com/micro/go-micro/tree/master/internal/website/docs)
- [Examples](https://github.com/micro/go-micro/tree/master/internal/website/docs/examples)
- [API Reference](https://pkg.go.dev/go-micro.dev/v5)

View File

@@ -0,0 +1,30 @@
---
name: Feature request
about: Suggest an idea for this project
title: '[FEATURE] '
labels: enhancement
assignees: ''
---
## Is your feature request related to a problem?
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
## Describe the solution you'd like
A clear and concise description of what you want to happen.
## Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.
## Use case
Describe how this feature would be used in practice. What problem does it solve?
## Additional context
Add any other context, code examples, or screenshots about the feature request here.
## Willing to contribute?
- [ ] I'd be willing to submit a PR for this feature
## Resources
- [Documentation](https://github.com/micro/go-micro/tree/master/internal/website/docs)
- [Plugins](https://github.com/micro/go-micro/tree/master/internal/website/docs/plugins.md)
- [Roadmap](https://github.com/micro/go-micro/blob/master/ROADMAP.md)

31
.github/ISSUE_TEMPLATE/question.md vendored Normal file
View File

@@ -0,0 +1,31 @@
---
name: Question
about: Ask a question about using Go Micro
title: '[QUESTION] '
labels: question
assignees: ''
---
## Your question
A clear and concise question about Go Micro usage.
## What have you tried?
Describe what you've already attempted or researched.
## Code sample (if applicable)
```go
// Your code here
```
## Context
Provide any additional context that might help answer your question.
## Resources you've checked
- [ ] [Getting Started Guide](https://github.com/micro/go-micro/tree/master/internal/website/docs/getting-started.md)
- [ ] [Examples](https://github.com/micro/go-micro/tree/master/internal/website/docs/examples)
- [ ] [API Documentation](https://pkg.go.dev/go-micro.dev/v5)
- [ ] Searched existing issues
## Helpful links
- [Documentation](https://github.com/micro/go-micro/tree/master/internal/website/docs)
- [Plugins Guide](https://github.com/micro/go-micro/tree/master/internal/website/docs/plugins.md)

207
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,207 @@
# Contributing to Go Micro
Thank you for your interest in contributing to Go Micro! This document provides guidelines and instructions for contributing.
## Code of Conduct
Be respectful, inclusive, and collaborative. We're all here to build great software together.
## Getting Started
1. Fork the repository
2. Clone your fork: `git clone https://github.com/YOUR_USERNAME/go-micro.git`
3. Add upstream remote: `git remote add upstream https://github.com/micro/go-micro.git`
4. Create a feature branch: `git checkout -b feature/my-feature`
## Development Setup
```bash
# Install dependencies
go mod download
# Run tests
go test ./...
# Run tests with coverage
go test -race -coverprofile=coverage.out ./...
# Run linter (install golangci-lint first)
golangci-lint run
```
## Making Changes
### Code Guidelines
- Follow standard Go conventions (use `gofmt`, `golint`)
- Write clear, descriptive commit messages
- Add tests for new functionality
- Update documentation for API changes
- Keep PRs focused - one feature/fix per PR
### Commit Messages
Use conventional commits format:
```
type(scope): subject
body
footer
```
Types:
- `feat`: New feature
- `fix`: Bug fix
- `docs`: Documentation changes
- `test`: Test additions/changes
- `refactor`: Code refactoring
- `perf`: Performance improvements
- `chore`: Maintenance tasks
Examples:
```
feat(registry): add kubernetes registry plugin
fix(broker): resolve nats connection leak
docs(examples): add streaming example
```
### Testing
- Write unit tests for all new code
- Ensure existing tests pass
- Add integration tests for plugin implementations
- Test with multiple Go versions (1.20+)
```bash
# Run specific package tests
go test ./registry/...
# Run with verbose output
go test -v ./...
# Run specific test
go test -run TestMyFunction ./pkg/...
```
### Documentation
- Update relevant markdown files in `internal/website/docs/`
- Add examples to `internal/website/docs/examples/` for new features
- Update README.md for major features
- Add godoc comments for exported functions/types
## Pull Request Process
1. **Update your branch**
```bash
git fetch upstream
git rebase upstream/master
```
2. **Run tests and linting**
```bash
go test ./...
golangci-lint run
```
3. **Push to your fork**
```bash
git push origin feature/my-feature
```
4. **Create Pull Request**
- Use a descriptive title
- Reference any related issues
- Describe what changed and why
- Add screenshots for UI changes
- Mark as draft if work in progress
5. **PR Review**
- Respond to feedback promptly
- Make requested changes
- Re-request review after updates
### PR Checklist
- [ ] Tests pass locally
- [ ] Code follows Go conventions
- [ ] Documentation updated
- [ ] Commit messages are clear
- [ ] Branch is up to date with master
- [ ] No merge conflicts
## Adding Plugins
New plugins should:
1. Live in the appropriate interface directory (e.g., `registry/myplugin/`)
2. Implement the interface completely
3. Include comprehensive tests
4. Provide usage examples
5. Document configuration options (env vars, options)
6. Add to plugin documentation
Example structure:
```
registry/myplugin/
├── myplugin.go # Main implementation
├── myplugin_test.go # Tests
├── options.go # Plugin-specific options
└── README.md # Usage and configuration
```
## Reporting Issues
Before creating an issue:
1. Search existing issues
2. Check documentation
3. Try the latest version
When reporting bugs:
- Use the bug report template
- Include minimal reproduction code
- Specify versions (Go, Go Micro, plugins)
- Provide relevant logs
## Documentation Contributions
Documentation improvements are always welcome!
- Fix typos and grammar
- Improve clarity
- Add missing examples
- Update outdated information
Documentation lives in `internal/website/docs/`. Preview locally with Jekyll:
```bash
cd internal/website
bundle install
bundle exec jekyll serve --livereload
```
## Community
- GitHub Issues: Bug reports and feature requests
- GitHub Discussions: Questions, ideas, and community chat
- Sponsorship: [GitHub Sponsors](https://github.com/sponsors/micro)
## Release Process
Maintainers handle releases:
1. Update CHANGELOG.md
2. Tag release: `git tag -a v5.x.x -m "Release v5.x.x"`
3. Push tag: `git push origin v5.x.x`
4. GitHub Actions creates release
## Questions?
- Check [documentation](internal/website/docs/)
- Browse [examples](internal/website/docs/examples/)
- Open a [question issue](.github/ISSUE_TEMPLATE/question.md)
Thank you for contributing to Go Micro! 🎉

163
ROADMAP.md Normal file
View File

@@ -0,0 +1,163 @@
# Go Micro Roadmap
This roadmap outlines the planned features and improvements for Go Micro. Community feedback and contributions are welcome!
## Current Focus (Q1 2026)
### Documentation & Developer Experience
- [x] Modernize documentation structure
- [x] Add learn-by-example guides
- [x] Update issue templates
- [ ] Create video tutorials
- [ ] Interactive documentation site
- [ ] Plugin discovery dashboard
### Observability
- [ ] OpenTelemetry native support
- [ ] Auto-instrumentation for handlers
- [ ] Metrics export standardization
- [ ] Distributed tracing examples
- [ ] Integration with popular observability platforms
### Developer Tools
- [ ] `micro dev` with hot reload
- [ ] Service templates (`micro new --template`)
- [ ] Better error messages with suggestions
- [ ] Debug tooling improvements
- [ ] VS Code extension for Go Micro
## Q2 2026
### Production Readiness
- [ ] Health check standardization
- [ ] Graceful shutdown improvements
- [ ] Resource cleanup best practices
- [ ] Load testing framework integration
- [ ] Performance benchmarking suite
### Cloud Native
- [ ] Kubernetes operator
- [ ] Helm charts for common setups
- [ ] Service mesh integration guides (Istio, Linkerd)
- [ ] Cloud provider quickstarts (AWS, GCP, Azure)
- [ ] Multi-cluster patterns
### Security
- [ ] mTLS by default option
- [ ] Secret management integration (Vault, AWS Secrets Manager)
- [ ] RBAC improvements
- [ ] Security audit and hardening
- [ ] CVE scanning and response process
## Q3 2026
### Plugin Ecosystem
- [ ] Plugin marketplace/registry
- [ ] Plugin quality standards
- [ ] Community plugin contributions
- [ ] Plugin compatibility matrix
- [ ] Auto-discovery of available plugins
### Streaming & Async
- [ ] Improved streaming support
- [ ] Server-sent events (SSE) support
- [ ] WebSocket plugin
- [ ] Event sourcing patterns
- [ ] CQRS examples
### Testing
- [ ] Mock generation tooling
- [ ] Integration test helpers
- [ ] Contract testing support
- [ ] Chaos engineering examples
- [ ] E2E testing framework
## Q4 2026
### Performance
- [ ] Connection pooling optimizations
- [ ] Zero-allocation paths
- [ ] gRPC performance improvements
- [ ] Caching strategies guide
- [ ] Performance profiling tools
### Developer Productivity
- [ ] Code generation improvements
- [ ] Better IDE support
- [ ] Debugging tools
- [ ] Migration automation tools
- [ ] Upgrade helpers
### Community
- [ ] Regular blog posts and case studies
- [ ] Community spotlight program
- [ ] Contribution rewards
- [ ] Monthly community calls
- [ ] Conference presence
## Long-term Vision
### Core Framework
- Maintain backward compatibility (Go Micro v5+)
- Progressive disclosure of complexity
- Best-in-class developer experience
- Production-grade reliability
- Comprehensive plugin ecosystem
### Ecosystem Goals
- 100+ production deployments documented
- 50+ community plugins
- Active contributor community
- Regular releases (monthly patches, quarterly features)
- Comprehensive benchmarks vs alternatives
### Differentiation
- **Batteries included, fully swappable** - Start simple, scale complex
- **Zero-config local development** - No infrastructure required to start
- **Plugin ecosystem in-repo** - No version compatibility hell
- **Progressive complexity** - Learn as you grow
- **Cloud-native first** - Built for Kubernetes and containers
## Contributing
We welcome contributions to any roadmap items! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
### High Priority Areas
1. Documentation improvements
2. Real-world examples
3. Plugin development
4. Performance optimizations
5. Testing infrastructure
### How to Contribute
- Pick an item from the roadmap
- Open an issue to discuss approach
- Submit a PR with implementation
- Help review others' contributions
## Feedback
Have suggestions for the roadmap?
- Open a [feature request](.github/ISSUE_TEMPLATE/feature_request.md)
- Start a discussion in GitHub Discussions
- Comment on existing roadmap issues
## Version Compatibility
We follow semantic versioning:
- Major versions (v5 → v6): Breaking changes
- Minor versions (v5.3 → v5.4): New features, backward compatible
- Patch versions (v5.3.0 → v5.3.1): Bug fixes, no API changes
## Support Timeline
- v5: Active development (current)
- v4: Security fixes only (until v6 release)
- v3: End of life
---
Last updated: November 2025
This roadmap is subject to change based on community needs and priorities. Star the repo to stay updated! ⭐

View File

@@ -0,0 +1,90 @@
---
layout: default
---
# ADR-001: Plugin Architecture
## Status
**Accepted**
## Context
Microservices frameworks need to support multiple infrastructure backends (registries, brokers, transports, stores). Different teams have different preferences and existing infrastructure.
Hard-coding specific implementations:
- Limits framework adoption
- Forces migration of existing infrastructure
- Prevents innovation and experimentation
## Decision
Go Micro uses a **pluggable architecture** where:
1. Core interfaces define contracts (Registry, Broker, Transport, Store, etc.)
2. Multiple implementations live in the same repository under interface directories
3. Plugins are imported directly and passed via options
4. Default implementations work without any infrastructure
## Structure
```
go-micro/
├── registry/ # Interface definition
│ ├── registry.go
│ ├── mdns.go # Default implementation
│ ├── consul/ # Plugin
│ ├── etcd/ # Plugin
│ └── nats/ # Plugin
├── broker/
├── transport/
└── store/
```
## Consequences
### Positive
- **No version hell**: Plugins versioned with core framework
- **Discovery**: Users browse available plugins in same repo
- **Consistency**: All plugins follow same patterns
- **Testing**: Plugins tested together
- **Zero config**: Default implementations require no setup
### Negative
- **Repo size**: More code in one repository
- **Plugin maintenance**: Core team responsible for plugin quality
- **Breaking changes**: Harder to evolve individual plugins independently
### Neutral
- Plugins can be extracted to separate repos if they grow complex
- Community can contribute plugins via PR
- Plugin-specific issues easier to triage
## Alternatives Considered
### Separate Plugin Repositories
Used by go-kit and other frameworks. Rejected because:
- Version compatibility becomes user's problem
- Discovery requires documentation
- Testing integration harder
- Splitting community
### Single Implementation
Like standard `net/http`. Rejected because:
- Forces infrastructure choices
- Limits adoption
- Can't leverage existing infrastructure
### Dynamic Plugin Loading
Using Go plugins or external processes. Rejected because:
- Complexity for users
- Compatibility issues
- Performance overhead
- Debugging difficulty
## Related
- ADR-002: Interface-First Design (planned)
- ADR-005: Registry Plugin Scope (planned)

View File

@@ -0,0 +1,120 @@
---
layout: default
---
# ADR-004: mDNS as Default Registry
## Status
**Accepted**
## Context
Service discovery is critical for microservices. Common approaches:
1. **Central registry** (Consul, Etcd) - Requires infrastructure
2. **DNS-based** (Kubernetes DNS) - Platform-specific
3. **Static configuration** - Doesn't scale
4. **Multicast DNS (mDNS)** - Zero-config, local network
For local development and getting started, requiring infrastructure setup is a barrier. Production deployments typically have existing service discovery infrastructure.
## Decision
Use **mDNS as the default registry** for service discovery.
- Works immediately on local networks
- No external dependencies
- Suitable for development and simple deployments
- Easily swapped for production registries (Consul, Etcd, Kubernetes)
## Implementation
```go
// Default - uses mDNS automatically
svc := micro.NewService(micro.Name("myservice"))
// Production - swap to Consul
reg := consul.NewConsulRegistry()
svc := micro.NewService(
micro.Name("myservice"),
micro.Registry(reg),
)
```
## Consequences
### Positive
- **Zero setup**: `go run main.go` just works
- **Fast iteration**: No infrastructure for local dev
- **Learning curve**: Newcomers start immediately
- **Progressive complexity**: Add infrastructure as needed
### Negative
- **Local network only**: mDNS doesn't cross subnets/VLANs
- **Not for production**: Needs proper registry in production
- **Port 5353**: May conflict with existing mDNS services
- **Discovery delay**: Can take 1-2 seconds
### Mitigations
- Clear documentation on production alternatives
- Environment variables for easy swapping (`MICRO_REGISTRY=consul`)
- Examples for all major registries
- Health checks and readiness probes for production
## Use Cases
### Good for mDNS
- Local development
- Testing
- Simple internal services on same network
- Learning and prototyping
### Need Production Registry
- Cross-datacenter communication
- Cloud deployments
- Large service mesh (100+ services)
- Require advanced features (health checks, metadata filtering)
## Alternatives Considered
### No Default (Force Configuration)
Rejected because:
- Poor first-run experience
- Increases barrier to entry
- Users must setup infrastructure before trying framework
### Static Configuration
Rejected because:
- Doesn't support dynamic service discovery
- Manual configuration doesn't scale
- Doesn't reflect real microservices usage
### Consul as Default
Rejected because:
- Requires running Consul for "Hello World"
- Platform-specific
- Adds complexity for beginners
## Migration Path
Start with mDNS, migrate to production registry:
```bash
# Development
go run main.go
# Staging
MICRO_REGISTRY=consul MICRO_REGISTRY_ADDRESS=consul:8500 go run main.go
# Production (Kubernetes)
MICRO_REGISTRY=nats MICRO_REGISTRY_ADDRESS=nats://nats:4222 ./service
```
## Related
- [ADR-001: Plugin Architecture](adr-001-plugin-architecture.md)
- [ADR-009: Progressive Configuration](adr-009-progressive-configuration.md)
- [Registry Documentation](../registry.md)

View File

@@ -0,0 +1,152 @@
---
layout: default
---
# ADR-009: Progressive Configuration
## Status
**Accepted**
## Context
Microservices frameworks face a paradox:
- Beginners want "Hello World" to work immediately
- Production needs sophisticated configuration
Too simple: Framework is toy, not production-ready
Too complex: High barrier to entry, discourages adoption
## Decision
Implement **progressive configuration** where:
1. **Zero config** works for development
2. **Environment variables** provide simple overrides
3. **Code-based options** enable fine-grained control
4. **Defaults are production-aware** but not production-ready
## Levels of Configuration
### Level 1: Zero Config (Development)
```go
svc := micro.NewService(micro.Name("hello"))
svc.Run()
```
Uses defaults:
- mDNS registry (local)
- HTTP transport
- Random available port
- Memory broker/store
### Level 2: Environment Variables (Staging)
```bash
MICRO_REGISTRY=consul \
MICRO_REGISTRY_ADDRESS=consul:8500 \
MICRO_BROKER=nats \
MICRO_BROKER_ADDRESS=nats://nats:4222 \
./service
```
No code changes, works with CLI flags.
### Level 3: Code Options (Production)
```go
reg := consul.NewConsulRegistry(
registry.Addrs("consul1:8500", "consul2:8500"),
registry.TLSConfig(tlsConf),
)
b := nats.NewNatsBroker(
broker.Addrs("nats://nats1:4222", "nats://nats2:4222"),
nats.DrainConnection(),
)
svc := micro.NewService(
micro.Name("myservice"),
micro.Version("1.2.3"),
micro.Registry(reg),
micro.Broker(b),
micro.Address(":8080"),
)
```
Full control over initialization and configuration.
### Level 4: External Config (Enterprise)
```go
cfg := config.NewConfig(
config.Source(file.NewSource("config.yaml")),
config.Source(env.NewSource()),
config.Source(vault.NewSource()),
)
// Use cfg to initialize plugins with complex configs
```
## Environment Variable Patterns
Standard vars for all plugins:
```bash
MICRO_REGISTRY=<type> # consul, etcd, nats, mdns
MICRO_REGISTRY_ADDRESS=<addrs> # Comma-separated
MICRO_BROKER=<type>
MICRO_BROKER_ADDRESS=<addrs>
MICRO_TRANSPORT=<type>
MICRO_TRANSPORT_ADDRESS=<addrs>
MICRO_STORE=<type>
MICRO_STORE_ADDRESS=<addrs>
MICRO_STORE_DATABASE=<name>
MICRO_STORE_TABLE=<name>
```
Plugin-specific vars:
```bash
ETCD_USERNAME=user
ETCD_PASSWORD=pass
CONSUL_TOKEN=secret
```
## Consequences
### Positive
- **Fast start**: Beginners productive immediately
- **Easy deployment**: Env vars for different environments
- **Power when needed**: Full programmatic control available
- **Learn incrementally**: Complexity introduced as required
### Negative
- **Three config sources**: Environment, code, and CLI flags can conflict
- **Documentation**: Must explain all levels clearly
- **Testing**: Need to test all configuration methods
### Mitigations
- Clear precedence: Code options > Environment > Defaults
- Comprehensive examples for each level
- Validation and helpful error messages
## Validation Example
```go
func (s *service) Init() error {
if s.opts.Name == "" {
return errors.New("service name required")
}
// Warn about development defaults in production
if isProduction() && usingDefaults() {
log.Warn("Using development defaults in production")
}
return nil
}
```
## Related
- [ADR-004: mDNS as Default Registry](adr-004-mdns-default-registry.md)
- ADR-008: Environment Variable Support (planned)
- [Getting Started Guide](../getting-started.md) - Configuration examples

View File

@@ -0,0 +1,53 @@
---
layout: default
---
# Architecture Decision Records
Documentation of architectural decisions made in Go Micro, following the ADR pattern.
## What are ADRs?
Architecture Decision Records (ADRs) capture important architectural decisions along with their context and consequences. They help understand why certain design choices were made.
## Index
### Available
- [ADR-001: Plugin Architecture](adr-001-plugin-architecture.md)
- [ADR-004: mDNS as Default Registry](adr-004-mdns-default-registry.md)
- [ADR-009: Progressive Configuration](adr-009-progressive-configuration.md)
### Planned
**Core Design**
- ADR-002: Interface-First Design
- ADR-003: Default Implementations
**Service Discovery**
- ADR-005: Registry Plugin Scope
**Communication**
- ADR-006: HTTP as Default Transport
- ADR-007: Content-Type Based Codecs
**Configuration**
- ADR-008: Environment Variable Support
## Status Values
- **Proposed**: Under consideration
- **Accepted**: Decision approved
- **Deprecated**: No longer recommended
- **Superseded**: Replaced by another ADR
## Contributing
To propose a new ADR:
1. Number it sequentially (check existing ADRs)
2. Follow the structure of existing ADRs
3. Include: Status, Context, Decision, Consequences, Alternatives
4. Submit a PR for discussion
5. Update status based on review
ADRs are immutable once accepted. To change a decision, create a new ADR that supersedes the old one.

View File

@@ -0,0 +1,390 @@
---
layout: default
---
# API Gateway with Backend Services
A complete example showing an API gateway routing to multiple backend microservices.
## Architecture
```
┌─────────────┐
Client ───────>│ API Gateway │
└──────┬──────┘
┌──────────────┼──────────────┐
│ │ │
┌─────▼────┐ ┌────▼─────┐ ┌────▼─────┐
│ Users │ │ Orders │ │ Products │
│ Service │ │ Service │ │ Service │
└──────────┘ └──────────┘ └──────────┘
│ │ │
└──────────────┼──────────────┘
┌──────▼──────┐
│ PostgreSQL │
└─────────────┘
```
## Services
### 1. Users Service
```go
// services/users/main.go
package main
import (
"context"
"database/sql"
"go-micro.dev/v5"
"go-micro.dev/v5/server"
_ "github.com/lib/pq"
)
type User struct {
ID int64 `json:"id"`
Email string `json:"email"`
Name string `json:"name"`
}
type UsersService struct {
db *sql.DB
}
type GetUserRequest struct {
ID int64 `json:"id"`
}
type GetUserResponse struct {
User *User `json:"user"`
}
func (s *UsersService) Get(ctx context.Context, req *GetUserRequest, rsp *GetUserResponse) error {
var u User
err := s.db.QueryRow("SELECT id, email, name FROM users WHERE id = $1", req.ID).
Scan(&u.ID, &u.Email, &u.Name)
if err != nil {
return err
}
rsp.User = &u
return nil
}
func main() {
db, err := sql.Open("postgres", "postgres://user:pass@localhost/users?sslmode=disable")
if err != nil {
panic(err)
}
defer db.Close()
svc := micro.NewService(
micro.Name("users"),
micro.Version("1.0.0"),
)
svc.Init()
server.RegisterHandler(svc.Server(), &UsersService{db: db})
if err := svc.Run(); err != nil {
panic(err)
}
}
```
### 2. Orders Service
```go
// services/orders/main.go
package main
import (
"context"
"database/sql"
"time"
"go-micro.dev/v5"
"go-micro.dev/v5/client"
"go-micro.dev/v5/server"
)
type Order struct {
ID int64 `json:"id"`
UserID int64 `json:"user_id"`
ProductID int64 `json:"product_id"`
Amount float64 `json:"amount"`
Status string `json:"status"`
CreatedAt time.Time `json:"created_at"`
}
type OrdersService struct {
db *sql.DB
client client.Client
}
type CreateOrderRequest struct {
UserID int64 `json:"user_id"`
ProductID int64 `json:"product_id"`
Amount float64 `json:"amount"`
}
type CreateOrderResponse struct {
Order *Order `json:"order"`
}
func (s *OrdersService) Create(ctx context.Context, req *CreateOrderRequest, rsp *CreateOrderResponse) error {
// Verify user exists
userReq := s.client.NewRequest("users", "UsersService.Get", &struct{ ID int64 }{ID: req.UserID})
userRsp := &struct{ User interface{} }{}
if err := s.client.Call(ctx, userReq, userRsp); err != nil {
return err
}
// Verify product exists
prodReq := s.client.NewRequest("products", "ProductsService.Get", &struct{ ID int64 }{ID: req.ProductID})
prodRsp := &struct{ Product interface{} }{}
if err := s.client.Call(ctx, prodReq, prodRsp); err != nil {
return err
}
// Create order
var o Order
err := s.db.QueryRow(`
INSERT INTO orders (user_id, product_id, amount, status, created_at)
VALUES ($1, $2, $3, $4, $5)
RETURNING id, user_id, product_id, amount, status, created_at
`, req.UserID, req.ProductID, req.Amount, "pending", time.Now()).
Scan(&o.ID, &o.UserID, &o.ProductID, &o.Amount, &o.Status, &o.CreatedAt)
if err != nil {
return err
}
rsp.Order = &o
return nil
}
func main() {
db, err := sql.Open("postgres", "postgres://user:pass@localhost/orders?sslmode=disable")
if err != nil {
panic(err)
}
defer db.Close()
svc := micro.NewService(
micro.Name("orders"),
micro.Version("1.0.0"),
)
svc.Init()
server.RegisterHandler(svc.Server(), &OrdersService{
db: db,
client: svc.Client(),
})
if err := svc.Run(); err != nil {
panic(err)
}
}
```
### 3. API Gateway
```go
// gateway/main.go
package main
import (
"encoding/json"
"net/http"
"strconv"
"go-micro.dev/v5"
"go-micro.dev/v5/client"
)
type Gateway struct {
client client.Client
}
func (g *Gateway) GetUser(w http.ResponseWriter, r *http.Request) {
idStr := r.URL.Query().Get("id")
id, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
http.Error(w, "invalid id", http.StatusBadRequest)
return
}
req := g.client.NewRequest("users", "UsersService.Get", &struct{ ID int64 }{ID: id})
rsp := &struct{ User interface{} }{}
if err := g.client.Call(r.Context(), req, rsp); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(rsp)
}
func (g *Gateway) CreateOrder(w http.ResponseWriter, r *http.Request) {
var body struct {
UserID int64 `json:"user_id"`
ProductID int64 `json:"product_id"`
Amount float64 `json:"amount"`
}
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
http.Error(w, "invalid request", http.StatusBadRequest)
return
}
req := g.client.NewRequest("orders", "OrdersService.Create", body)
rsp := &struct{ Order interface{} }{}
if err := g.client.Call(r.Context(), req, rsp); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(rsp)
}
func main() {
svc := micro.NewService(
micro.Name("api.gateway"),
)
svc.Init()
gw := &Gateway{client: svc.Client()}
http.HandleFunc("/users", gw.GetUser)
http.HandleFunc("/orders", gw.CreateOrder)
http.ListenAndServe(":8080", nil)
}
```
## Running the Example
### Development (Local)
```bash
# Terminal 1: Users service
cd services/users
go run main.go
# Terminal 2: Products service
cd services/products
go run main.go
# Terminal 3: Orders service
cd services/orders
go run main.go
# Terminal 4: API Gateway
cd gateway
go run main.go
```
### Testing
```bash
# Get user
curl http://localhost:8080/users?id=1
# Create order
curl -X POST http://localhost:8080/orders \
-H 'Content-Type: application/json' \
-d '{"user_id": 1, "product_id": 100, "amount": 99.99}'
```
### Docker Compose
```yaml
version: '3.8'
services:
postgres:
image: postgres:15
environment:
POSTGRES_PASSWORD: secret
ports:
- "5432:5432"
users:
build: ./services/users
environment:
MICRO_REGISTRY: nats
MICRO_REGISTRY_ADDRESS: nats://nats:4222
DATABASE_URL: postgres://postgres:secret@postgres/users
depends_on:
- postgres
- nats
products:
build: ./services/products
environment:
MICRO_REGISTRY: nats
MICRO_REGISTRY_ADDRESS: nats://nats:4222
DATABASE_URL: postgres://postgres:secret@postgres/products
depends_on:
- postgres
- nats
orders:
build: ./services/orders
environment:
MICRO_REGISTRY: nats
MICRO_REGISTRY_ADDRESS: nats://nats:4222
DATABASE_URL: postgres://postgres:secret@postgres/orders
depends_on:
- postgres
- nats
gateway:
build: ./gateway
ports:
- "8080:8080"
environment:
MICRO_REGISTRY: nats
MICRO_REGISTRY_ADDRESS: nats://nats:4222
depends_on:
- users
- products
- orders
nats:
image: nats:latest
ports:
- "4222:4222"
```
Run with:
```bash
docker-compose up
```
## Key Patterns
1. **Service isolation**: Each service owns its database
2. **Service communication**: Via Go Micro client
3. **Gateway pattern**: Single entry point for clients
4. **Error handling**: Proper HTTP status codes
5. **Registry**: mDNS for local, NATS for Docker
## Production Considerations
- Add authentication/authorization
- Implement request tracing
- Add circuit breakers for service calls
- Use connection pooling
- Add rate limiting
- Implement proper logging
- Use health checks
- Add metrics collection
See [Production Patterns](../realworld/) for more details.

View File

@@ -0,0 +1,367 @@
---
layout: default
---
# Graceful Shutdown
Properly shutting down services to avoid dropped requests and data loss.
## The Problem
Without graceful shutdown:
- In-flight requests are dropped
- Database connections leak
- Resources aren't cleaned up
- Load balancers don't know service is down
## Solution
Go Micro handles SIGTERM/SIGINT by default, but you need to implement cleanup logic.
## Basic Pattern
```go
package main
import (
"context"
"os"
"os/signal"
"syscall"
"time"
"go-micro.dev/v5"
"go-micro.dev/v5/logger"
)
func main() {
svc := micro.NewService(
micro.Name("myservice"),
micro.BeforeStop(func() error {
logger.Info("Service stopping, running cleanup...")
return cleanup()
}),
)
svc.Init()
// Your service logic
if err := svc.Handle(new(Handler)); err != nil {
logger.Fatal(err)
}
// Run with graceful shutdown
if err := svc.Run(); err != nil {
logger.Fatal(err)
}
logger.Info("Service stopped gracefully")
}
func cleanup() error {
// Close database connections
// Flush logs
// Stop background workers
// etc.
return nil
}
```
## Database Cleanup
```go
type Service struct {
db *sql.DB
}
func (s *Service) Shutdown(ctx context.Context) error {
logger.Info("Closing database connections...")
// Stop accepting new requests
s.db.SetMaxOpenConns(0)
// Wait for existing connections to finish (with timeout)
done := make(chan struct{})
go func() {
s.db.Close()
close(done)
}()
select {
case <-done:
logger.Info("Database closed gracefully")
return nil
case <-ctx.Done():
logger.Warn("Database close timeout, forcing")
return ctx.Err()
}
}
```
## Background Workers
```go
type Worker struct {
quit chan struct{}
done chan struct{}
}
func (w *Worker) Start() {
w.quit = make(chan struct{})
w.done = make(chan struct{})
go func() {
defer close(w.done)
ticker := time.NewTicker(5 * time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
w.doWork()
case <-w.quit:
logger.Info("Worker stopping...")
return
}
}
}()
}
func (w *Worker) Stop(timeout time.Duration) error {
close(w.quit)
select {
case <-w.done:
logger.Info("Worker stopped gracefully")
return nil
case <-time.After(timeout):
return fmt.Errorf("worker shutdown timeout")
}
}
```
## Complete Example
```go
package main
import (
"context"
"database/sql"
"fmt"
"os"
"os/signal"
"sync"
"syscall"
"time"
"go-micro.dev/v5"
"go-micro.dev/v5/logger"
)
type Application struct {
db *sql.DB
workers []*Worker
wg sync.WaitGroup
mu sync.RWMutex
closing bool
}
func NewApplication(db *sql.DB) *Application {
return &Application{
db: db,
workers: make([]*Worker, 0),
}
}
func (app *Application) AddWorker(w *Worker) {
app.workers = append(app.workers, w)
w.Start()
}
func (app *Application) Shutdown(ctx context.Context) error {
app.mu.Lock()
if app.closing {
app.mu.Unlock()
return nil
}
app.closing = true
app.mu.Unlock()
logger.Info("Starting graceful shutdown...")
// Stop accepting new work
logger.Info("Stopping workers...")
for _, w := range app.workers {
if err := w.Stop(5 * time.Second); err != nil {
logger.Warnf("Worker failed to stop: %v", err)
}
}
// Wait for in-flight requests (with timeout)
shutdownComplete := make(chan struct{})
go func() {
app.wg.Wait()
close(shutdownComplete)
}()
select {
case <-shutdownComplete:
logger.Info("All requests completed")
case <-ctx.Done():
logger.Warn("Shutdown timeout, forcing...")
}
// Close resources
logger.Info("Closing database...")
if err := app.db.Close(); err != nil {
logger.Errorf("Database close error: %v", err)
}
logger.Info("Shutdown complete")
return nil
}
func main() {
db, err := sql.Open("postgres", os.Getenv("DATABASE_URL"))
if err != nil {
logger.Fatal(err)
}
app := NewApplication(db)
// Add background workers
app.AddWorker(&Worker{name: "cleanup"})
app.AddWorker(&Worker{name: "metrics"})
svc := micro.NewService(
micro.Name("myservice"),
micro.BeforeStop(func() error {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
return app.Shutdown(ctx)
}),
)
svc.Init()
handler := &Handler{app: app}
if err := svc.Handle(handler); err != nil {
logger.Fatal(err)
}
// Run service
if err := svc.Run(); err != nil {
logger.Fatal(err)
}
}
```
## Kubernetes Integration
### Liveness and Readiness Probes
```go
func (h *Handler) Health(ctx context.Context, req *struct{}, rsp *HealthResponse) error {
// Liveness: is the service alive?
rsp.Status = "ok"
return nil
}
func (h *Handler) Ready(ctx context.Context, req *struct{}, rsp *ReadyResponse) error {
h.app.mu.RLock()
closing := h.app.closing
h.app.mu.RUnlock()
if closing {
// Stop receiving traffic during shutdown
return fmt.Errorf("shutting down")
}
// Check dependencies
if err := h.app.db.Ping(); err != nil {
return fmt.Errorf("database unhealthy: %w", err)
}
rsp.Status = "ready"
return nil
}
```
### Kubernetes Manifest
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myservice
spec:
replicas: 3
template:
spec:
containers:
- name: myservice
image: myservice:latest
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
lifecycle:
preStop:
exec:
# Give service time to drain before SIGTERM
command: ["/bin/sh", "-c", "sleep 10"]
terminationGracePeriodSeconds: 40
```
## Best Practices
1. **Set timeouts**: Don't wait forever for shutdown
2. **Stop accepting work early**: Set readiness to false
3. **Drain in-flight requests**: Let current work finish
4. **Close resources properly**: Databases, file handles, etc.
5. **Log shutdown progress**: Help debugging
6. **Handle SIGTERM and SIGINT**: Kubernetes sends SIGTERM
7. **Coordinate with load balancer**: Use readiness probes
8. **Test shutdown**: Regularly test graceful shutdown works
## Testing Shutdown
```bash
# Start service
go run main.go &
PID=$!
# Send some requests
for i in {1..10}; do
curl http://localhost:8080/endpoint &
done
# Trigger graceful shutdown
kill -TERM $PID
# Verify all requests completed
wait
```
## Common Pitfalls
- **No timeout**: Service hangs during shutdown
- **Not stopping workers**: Background jobs continue
- **Database leaks**: Connections not closed
- **Ignored signals**: Service killed forcefully
- **No readiness probe**: Traffic during shutdown
## Related
- [API Gateway Example](api-gateway.md) - Multi-service architecture
- [Getting Started Guide](../../getting-started.md) - Basic service setup

View File

@@ -0,0 +1,54 @@
---
layout: default
---
# Real-World Examples
Production-ready patterns and complete application examples.
## Available Examples
- [API Gateway with Backend Services](api-gateway.md) - Complete multi-service architecture with users, orders, and products services
- [Graceful Shutdown](graceful-shutdown.md) - Production-ready shutdown patterns with Kubernetes integration
## Coming Soon
We're actively working on additional real-world examples. Contributions are welcome!
**Complete Applications**
- Event-Driven Microservices - Pub/sub patterns
- CQRS Pattern - Command Query Responsibility Segregation
- Saga Pattern - Distributed transactions
**Production Patterns**
- Health Checks and Readiness
- Retry and Circuit Breaking
- Distributed Tracing with OpenTelemetry
- Structured Logging
- Metrics and Monitoring
**Testing Strategies**
- Unit Testing Services
- Integration Testing
- Contract Testing
- Load Testing
**Deployment**
- Kubernetes Deployment
- Docker Compose Setup
- CI/CD Pipeline Examples
- Blue-Green Deployment
**Integration Examples**
- PostgreSQL with Transactions
- Redis Caching Strategies
- Message Queue Integration
- External API Integration
Each example will include:
- Complete, runnable code
- Configuration for development and production
- Testing approach
- Common pitfalls and solutions
Want to contribute? See our [CONTRIBUTING.md](../../../../CONTRIBUTING.md) guide.

View File

@@ -0,0 +1,301 @@
---
layout: default
---
# Framework Comparison
How Go Micro compares to other Go microservices frameworks.
## Quick Comparison
| Feature | Go Micro | go-kit | gRPC | Dapr |
|---------|----------|--------|------|------|
| **Learning Curve** | Low | High | Medium | Medium |
| **Boilerplate** | Low | High | Medium | Low |
| **Plugin System** | Built-in | External | Limited | Sidecar |
| **Service Discovery** | Yes (mDNS, Consul, etc) | No (BYO) | No | Yes |
| **Load Balancing** | Client-side | No | No | Sidecar |
| **Pub/Sub** | Yes | No | No | Yes |
| **Transport** | HTTP, gRPC, NATS | BYO | gRPC only | HTTP, gRPC |
| **Zero-config Dev** | Yes (mDNS) | No | No | No (needs sidecar) |
| **Production Ready** | Yes | Yes | Yes | Yes |
| **Language** | Go only | Go only | Multi-language | Multi-language |
## vs go-kit
### go-kit Philosophy
- "Just a toolkit" - minimal opinions
- Compose your own framework
- Maximum flexibility
- Requires more decisions upfront
### Go Micro Philosophy
- "Batteries included" - opinionated defaults
- Swap components as needed
- Progressive complexity
- Get started fast, customize later
### When to Choose go-kit
- You want complete control over architecture
- You have strong opinions about structure
- You're building a custom framework
- You prefer explicit over implicit
### When to Choose Go Micro
- You want to start coding immediately
- You prefer conventions over decisions
- You want built-in service discovery
- You need pub/sub messaging
### Code Comparison
**go-kit** (requires more setup):
```go
// Define service interface
type MyService interface {
DoThing(ctx context.Context, input string) (string, error)
}
// Implement service
type myService struct{}
func (s *myService) DoThing(ctx context.Context, input string) (string, error) {
return "result", nil
}
// Create endpoints
func makeDo ThingEndpoint(svc MyService) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(doThingRequest)
result, err := svc.DoThing(ctx, req.Input)
if err != nil {
return doThingResponse{Err: err}, nil
}
return doThingResponse{Result: result}, nil
}
}
// Create transport (HTTP, gRPC, etc)
// ... more boilerplate ...
```
**Go Micro** (simpler):
```go
type MyService struct{}
type Request struct {
Input string `json:"input"`
}
type Response struct {
Result string `json:"result"`
}
func (s *MyService) DoThing(ctx context.Context, req *Request, rsp *Response) error {
rsp.Result = "result"
return nil
}
func main() {
svc := micro.NewService(micro.Name("myservice"))
svc.Init()
svc.Handle(new(MyService))
svc.Run()
}
```
## vs gRPC
### gRPC Focus
- High-performance RPC
- Multi-language support via protobuf
- HTTP/2 transport
- Streaming built-in
### Go Micro Scope
- Full microservices framework
- Service discovery
- Multiple transports (including gRPC)
- Pub/sub messaging
- Pluggable components
### When to Choose gRPC
- You need multi-language services
- Performance is critical
- You want industry-standard protocol
- You're okay managing service discovery separately
### When to Choose Go Micro
- You need more than just RPC (pub/sub, discovery, etc)
- You want flexibility in transport
- You're building Go-only services
- You want integrated tooling
### Integration
You can use gRPC with Go Micro:
```go
import "go-micro.dev/v5/client/grpc"
svc := micro.NewService(
micro.Client(grpc.NewClient()),
)
```
## vs Dapr
### Dapr Approach
- Multi-language via sidecar
- Rich building blocks (state, pub/sub, bindings)
- Cloud-native focused
- Requires running sidecar process
### Go Micro Approach
- Go library, no sidecar
- Direct service-to-service calls
- Simpler deployment
- Lower latency (no extra hop)
### When to Choose Dapr
- You have polyglot services (Node, Python, Java, etc)
- You want portable abstractions across clouds
- You're fully on Kubernetes
- You need state management abstractions
### When to Choose Go Micro
- You're building Go services
- You want lower latency
- You prefer libraries over sidecars
- You want simpler deployment (no sidecar management)
## Feature Deep Dive
### Service Discovery
**Go Micro**: Built-in with plugins
```go
// Zero-config for dev
svc := micro.NewService(micro.Name("myservice"))
// Consul for production
reg := consul.NewRegistry()
svc := micro.NewService(micro.Registry(reg))
```
**go-kit**: Bring your own
```go
// You implement service discovery
// Can be 100+ lines of code
```
**gRPC**: No built-in discovery
```go
// Use external solution like Consul
// or service mesh like Istio
```
### Load Balancing
**Go Micro**: Client-side, pluggable strategies
```go
// Built-in: random, round-robin
selector := selector.NewSelector(
selector.SetStrategy(selector.RoundRobin),
)
```
**go-kit**: Manual implementation
```go
// You implement load balancing
// Using loadbalancer package
```
**gRPC**: Via external load balancer
```bash
# Use external LB like Envoy, nginx
```
### Pub/Sub
**Go Micro**: First-class
```go
broker.Publish("topic", &broker.Message{Body: []byte("data")})
broker.Subscribe("topic", handler)
```
**go-kit**: Not provided
```go
// Use external message broker directly
// NATS, Kafka, etc
```
**gRPC**: Streaming only
```go
// Use bidirectional streams
// Not traditional pub/sub
```
## Migration Paths
See specific migration guides:
- [From gRPC](migration/from-grpc.md)
**Coming Soon:**
- From go-kit
- From Standard Library
## Decision Matrix
Choose **Go Micro** if:
- ✅ Building Go microservices
- ✅ Want fast iteration
- ✅ Need service discovery
- ✅ Want pub/sub built-in
- ✅ Prefer conventions
Choose **go-kit** if:
- ✅ Want maximum control
- ✅ Have strong architectural opinions
- ✅ Building custom framework
- ✅ Prefer explicit composition
Choose **gRPC** if:
- ✅ Need multi-language support
- ✅ Performance is primary concern
- ✅ Just need RPC (not full framework)
- ✅ Have service discovery handled
Choose **Dapr** if:
- ✅ Polyglot services
- ✅ Heavy Kubernetes usage
- ✅ Want portable cloud abstractions
- ✅ Need state management
## Performance
Rough benchmarks (requests/sec, single instance):
| Framework | Simple RPC | With Discovery | With Tracing |
|-----------|-----------|----------------|--------------|
| Go Micro | ~20k | ~18k | ~15k |
| gRPC | ~25k | N/A | ~20k |
| go-kit | ~22k | N/A | ~18k |
| HTTP std | ~30k | N/A | N/A |
*Benchmarks are approximate and vary by configuration*
## Community & Ecosystem
- **Go Micro**: Active, growing plugins
- **gRPC**: Huge, multi-language
- **go-kit**: Mature, stable
- **Dapr**: Growing, Microsoft-backed
## Recommendation
Start with **Go Micro** if you're building Go microservices and want to move fast. You can always:
- Use gRPC transport: `micro.Transport(grpc.NewTransport())`
- Integrate with go-kit components
- Mix and match as needed
The pluggable architecture means you're not locked in.

View File

@@ -0,0 +1,416 @@
---
layout: default
---
# Migrating from gRPC
Step-by-step guide to migrating existing gRPC services to Go Micro.
## Why Migrate?
Go Micro adds:
- Built-in service discovery
- Client-side load balancing
- Pub/sub messaging
- Multiple transport options
- Unified tooling
You keep:
- Your proto definitions
- gRPC performance (via gRPC transport)
- Type safety
- Streaming support
## Migration Strategy
### Phase 1: Parallel Running
Run Go Micro alongside existing gRPC services
### Phase 2: Gradual Migration
Migrate services one at a time
### Phase 3: Complete Migration
All services on Go Micro
## Step-by-Step Migration
### 1. Existing gRPC Service
```protobuf
// proto/hello.proto
syntax = "proto3";
package hello;
option go_package = "./proto;hello";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
```
```go
// Original gRPC server
package main
import (
"context"
"log"
"net"
"google.golang.org/grpc"
pb "myapp/proto"
)
type server struct {
pb.UnimplementedGreeterServer
}
func (s *server) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloReply, error) {
return &pb.HelloReply{Message: "Hello " + req.Name}, nil
}
func main() {
lis, _ := net.Listen("tcp", ":50051")
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
log.Fatal(s.Serve(lis))
}
```
### 2. Generate Go Micro Code
Update your proto generation:
```bash
# Install protoc-gen-micro
go install go-micro.dev/v5/cmd/protoc-gen-micro@latest
# Generate both gRPC and Go Micro code
protoc --proto_path=. \
--go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
--micro_out=. --micro_opt=paths=source_relative \
proto/hello.proto
```
This generates:
- `hello.pb.go` - Protocol Buffers types
- `hello_grpc.pb.go` - gRPC client/server (keep for compatibility)
- `hello.pb.micro.go` - Go Micro client/server (new)
### 3. Migrate Server to Go Micro
```go
// Go Micro server
package main
import (
"context"
"go-micro.dev/v5"
"go-micro.dev/v5/server"
pb "myapp/proto"
)
type Greeter struct{}
func (s *Greeter) SayHello(ctx context.Context, req *pb.HelloRequest, rsp *pb.HelloReply) error {
rsp.Message = "Hello " + req.Name
return nil
}
func main() {
svc := micro.NewService(
micro.Name("greeter"),
)
svc.Init()
pb.RegisterGreeterHandler(svc.Server(), new(Greeter))
if err := svc.Run(); err != nil {
log.Fatal(err)
}
}
```
**Key differences:**
- No manual port binding (Go Micro handles it)
- Automatic service registration
- Returns error, response via pointer parameter
### 4. Migrate Client
**Original gRPC client:**
```go
conn, _ := grpc.Dial("localhost:50051", grpc.WithInsecure())
defer conn.Close()
client := pb.NewGreeterClient(conn)
rsp, err := client.SayHello(context.Background(), &pb.HelloRequest{Name: "John"})
```
**Go Micro client:**
```go
svc := micro.NewService(micro.Name("client"))
svc.Init()
client := pb.NewGreeterService("greeter", svc.Client())
rsp, err := client.SayHello(context.Background(), &pb.HelloRequest{Name: "John"})
```
**Benefits:**
- No hardcoded addresses
- Automatic service discovery
- Client-side load balancing
- Automatic retries
### 5. Keep gRPC Transport (Optional)
Use gRPC as the underlying transport:
```go
import (
"go-micro.dev/v5"
"go-micro.dev/v5/client"
"go-micro.dev/v5/server"
grpcclient "go-micro.dev/v5/client/grpc"
grpcserver "go-micro.dev/v5/server/grpc"
)
svc := micro.NewService(
micro.Name("greeter"),
micro.Client(grpcclient.NewClient()),
micro.Server(grpcserver.NewServer()),
)
```
This gives you:
- gRPC performance
- Go Micro features (discovery, load balancing)
- Compatible with existing gRPC clients
## Streaming Migration
### Original gRPC Streaming
```protobuf
service Greeter {
rpc StreamHellos (stream HelloRequest) returns (stream HelloReply) {}
}
```
```go
func (s *server) StreamHellos(stream pb.Greeter_StreamHellosServer) error {
for {
req, err := stream.Recv()
if err == io.EOF {
return nil
}
if err != nil {
return err
}
stream.Send(&pb.HelloReply{Message: "Hello " + req.Name})
}
}
```
### Go Micro Streaming
```go
func (s *Greeter) StreamHellos(ctx context.Context, stream server.Stream) error {
for {
var req pb.HelloRequest
if err := stream.Recv(&req); err != nil {
return err
}
if err := stream.Send(&pb.HelloReply{Message: "Hello " + req.Name}); err != nil {
return err
}
}
}
```
## Service Discovery Migration
### Before (gRPC with Consul)
```go
// Manually register with Consul
config := api.DefaultConfig()
config.Address = "consul:8500"
client, _ := api.NewClient(config)
reg := &api.AgentServiceRegistration{
ID: "greeter-1",
Name: "greeter",
Address: "localhost",
Port: 50051,
}
client.Agent().ServiceRegister(reg)
// Cleanup on shutdown
defer client.Agent().ServiceDeregister("greeter-1")
```
### After (Go Micro)
```go
import "go-micro.dev/v5/registry/consul"
reg := consul.NewConsulRegistry()
svc := micro.NewService(
micro.Name("greeter"),
micro.Registry(reg),
)
// Registration automatic on Run()
// Deregistration automatic on shutdown
svc.Run()
```
## Load Balancing Migration
### Before (gRPC with custom LB)
```go
// Need external load balancer or custom implementation
// Example: round-robin DNS, Envoy, nginx
```
### After (Go Micro)
```go
import "go-micro.dev/v5/selector"
// Client-side load balancing built-in
svc := micro.NewService(
micro.Selector(selector.NewSelector(
selector.SetStrategy(selector.RoundRobin),
)),
)
```
## Gradual Migration Path
### 1. Start with New Services
New services use Go Micro, existing services stay on gRPC.
```go
// New Go Micro service can call gRPC services
// Configure gRPC endpoints directly
grpcConn, _ := grpc.Dial("old-service:50051", grpc.WithInsecure())
oldClient := pb.NewOldServiceClient(grpcConn)
```
### 2. Migrate Read-Heavy Services First
Services with many clients benefit most from service discovery.
### 3. Migrate Services with Fewest Dependencies
Leaf services are easier to migrate.
### 4. Add Adapters if Needed
```go
// gRPC adapter for Go Micro service
type GRPCAdapter struct {
microClient pb.GreeterService
}
func (a *GRPCAdapter) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloReply, error) {
return a.microClient.SayHello(ctx, req)
}
// Register adapter as gRPC server
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &GRPCAdapter{microClient: microClient})
```
## Checklist
- [ ] Update proto generation to include `--micro_out`
- [ ] Convert handler signatures (response via pointer)
- [ ] Replace `grpc.Dial` with Go Micro client
- [ ] Configure service discovery (Consul, Etcd, etc)
- [ ] Update deployment (remove hardcoded ports)
- [ ] Update monitoring (Go Micro metrics)
- [ ] Test service-to-service communication
- [ ] Update documentation
- [ ] Train team on Go Micro patterns
## Common Issues
### Port Already in Use
**gRPC**: Manual port management
```go
lis, _ := net.Listen("tcp", ":50051")
```
**Go Micro**: Automatic or explicit
```go
// Let Go Micro choose
svc := micro.NewService(micro.Name("greeter"))
// Or specify
svc := micro.NewService(
micro.Name("greeter"),
micro.Address(":50051"),
)
```
### Service Not Found
Check registry:
```bash
# Consul
curl http://localhost:8500/v1/catalog/services
# Or use micro CLI
micro services
```
### Different Serialization
gRPC uses protobuf by default. Go Micro supports multiple codecs.
Ensure both use protobuf:
```go
import "go-micro.dev/v5/codec/proto"
svc := micro.NewService(
micro.Codec("application/protobuf", proto.Marshaler{}),
)
```
## Performance Comparison
| Scenario | gRPC | Go Micro (HTTP) | Go Micro (gRPC) |
|----------|------|----------------|-----------------|
| Simple RPC | ~25k req/s | ~20k req/s | ~24k req/s |
| With Discovery | N/A | ~18k req/s | ~22k req/s |
| Streaming | ~30k msg/s | ~15k msg/s | ~28k msg/s |
*Go Micro with gRPC transport performs similarly to pure gRPC*
## Next Steps
- Read [Go Micro Architecture](../architecture.md)
- Explore [Plugin System](../plugins.md)
- Check [Production Patterns](../examples/realworld/)
## Need Help?
- [Examples](../examples/)
- [GitHub Issues](https://github.com/micro/go-micro/issues)
- [API Documentation](https://pkg.go.dev/go-micro.dev/v5)

View File

@@ -0,0 +1,35 @@
---
layout: default
---
# Migration Guides
Step-by-step guides for migrating to Go Micro from other frameworks.
## Available Guides
- [From gRPC](from-grpc.md) - Migrate from gRPC to Go Micro with minimal code changes
## Coming Soon
We're working on additional migration guides:
- **From go-kit** - Migrate from Go kit microservices framework
- **From Standard Library** - Upgrade from net/http and net/rpc
- **From Gin/Echo** - Transition from HTTP-only frameworks
- **From Micro v3** - Upgrade from older Go Micro versions
## Why Migrate to Go Micro?
- **Pluggable Architecture** - Swap components without changing code
- **Zero Configuration** - Works out of the box with sensible defaults
- **Progressive Enhancement** - Start simple, add complexity when needed
- **Unified Abstractions** - Registry, transport, broker, store all integrated
- **Active Development** - Regular updates and community support
## Need Help?
- Check the [Framework Comparison](../comparison.md) guide
- Review [Architecture Decisions](../../architecture/index.md) to understand design choices
- Ask questions in [GitHub Discussions](https://github.com/micro/go-micro/discussions)
- See [CONTRIBUTING.md](../../../../CONTRIBUTING.md) to contribute new migration guides

View File

@@ -35,3 +35,10 @@ about the framework.
- [Plugins](plugins.md)
- [Examples](examples/index.md)
- [Server (optional)](server.md)
## Advanced
- [Framework Comparison](guides/comparison.md)
- [Architecture Decisions](architecture/index.md)
- [Real-World Examples](examples/realworld/index.md)
- [Migration Guides](guides/migration/index.md)