Skip to main content

go-zero v1.9.0 ๐Ÿš€

Welcome to go-zero v1.9.0! This release brings powerful new features, important fixes, and performance improvements to enhance your microservices development experience.

๐Ÿ†• New Features

1. Data Masking in Logging (logx)

Enhanced security for sensitive data logging

What's New: Support for masking sensitive data in log output by implementing the MaskSensitive() any method on data types.

Quick Start:

package main

import "github.com/zeromicro/go-zero/core/logx"

// Define a struct with sensitive data
type UserInfo struct {
Username string `json:"username"`
Password string `json:"password"`
Email string `json:"email"`
}

// Implement MaskSensitive method to control what gets logged
func (u UserInfo) MaskSensitive() any {
return UserInfo{
Username: u.Username,
Password: "***", // Mask the password
Email: maskEmail(u.Email), // Partially mask email
}
}

func maskEmail(email string) string {
parts := strings.Split(email, "@")
if len(parts) != 2 {
return "***"
}
return parts[0][:1] + "***@" + parts[1]
}

func main() {
user := UserInfo{
Username: "john",
Password: "secret123",
Email: "john@example.com",
}

// This will automatically use MaskSensitive() method
logx.Infow("User login", logx.Field("user", user))
// Output: {"user":{"username":"john","password":"***","email":"j***@example.com"}}
}

2. Field Tag Skip Logic in sqlx

Improved database field handling with skip tags

What's New: Support for - field tag to skip fields during database operations.

Quick Start:

type User struct {
ID int64 `db:"id"`
Name string `db:"name"`
Password string `db:"-"` // This field will be skipped
Internal string `db:"-"` // This field will be skipped
Email string `db:"email"`
}

// Usage in queries - skipped fields are automatically ignored
var user User
err := sqlx.QueryRow(&user, "SELECT id, name, email FROM users WHERE id = ?", 1)

3. MongoDB Driver v2 Upgrade

Modern MongoDB integration with improved performance

What's New: Upgraded to mongo-driver v2 with v1 moved to zero-contrib for backward compatibility.

Migration Guide:

// Old way (v1 - now in zero-contrib)
import "github.com/zeromicro/zero-contrib/stores/mongo"

// New way (v2 - built-in)
import "github.com/zeromicro/go-zero/core/stores/mongo"

func main() {
// New v2 API with improved performance
client := mongo.MustNewModel("mongodb://localhost:27017", "mydb", "users")

// Enhanced query capabilities
var users []User
err := client.Find(context.Background(), &users, bson.M{"status": "active"})
}

4. Generic TypedSet with 2x Performance

High-performance generic set implementation

What's New: Generic TypedSet with compile-time safety and 2x performance improvement.

Quick Start:

import "github.com/zeromicro/go-zero/core/collection"

func main() {
// Create a typed set for strings
stringSet := collection.NewTypedSet[string]()

// Add items
stringSet.Add("user1", "user2", "user3")

// Check membership (2x faster than previous implementation)
if stringSet.Contains("user1") {
fmt.Println("User found!")
}

// Work with integers
intSet := collection.NewTypedSet[int]()
intSet.Add(1, 2, 3)

// Set operations
union := stringSet.Union(otherStringSet)
intersection := stringSet.Intersect(otherStringSet)
}

5. Gateway Custom Middleware (Onion Model)

Flexible middleware architecture for API gateways

What's New: Support for custom middleware with onion model architecture in API gateways.

Quick Start:

import "github.com/zeromicro/go-zero/gateway"

// Define custom middleware
func authMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Authentication logic
token := r.Header.Get("Authorization")
if !validateToken(token) {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
next(w, r)
}
}

func rateLimitMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Rate limiting logic
if !checkRateLimit(r.RemoteAddr) {
http.Error(w, "Rate limit exceeded", http.StatusTooManyRequests)
return
}
next(w, r)
}
}

// Configure gateway with middleware stack
func main() {
gw := gateway.MustNewServer(gateway.GatewayConf{
Name: "api-gateway",
Port: 8080,
Upstreams: []gateway.Upstream{
{
Name: "user-service",
Mapping: "/api/users",
Target: "http://localhost:8081",
},
},
// Middleware stack (onion model - outer to inner)
Middlewares: []gateway.Middleware{
rateLimitMiddleware, // Outer layer
authMiddleware, // Inner layer
},
})

gw.Start()
}

6. Redis Consumer Groups

Advanced Redis stream processing with consumer groups

What's New: Native support for Redis consumer groups for scalable stream processing.

Quick Start:

import "github.com/zeromicro/go-zero/core/stores/redis"

func main() {
rds := redis.MustNewRedis(redis.RedisConf{
Host: "localhost:6379",
})

// Create consumer group
err := rds.XGroupCreate("events", "processors", "0", true)
if err != nil {
log.Fatal(err)
}

// Consumer function
go func() {
for {
// Read from consumer group
streams, err := rds.XReadGroup(&redis.XReadGroupArgs{
Group: "processors",
Consumer: "worker-1",
Streams: []string{"events", ">"},
Count: 10,
Block: time.Second * 5,
})

if err != nil {
log.Printf("Error reading: %v", err)
continue
}

// Process messages
for _, stream := range streams {
for _, message := range stream.Messages {
processMessage(message)
// Acknowledge message
rds.XAck("events", "processors", message.ID)
}
}
}
}()
}

func processMessage(msg redis.XMessage) {
fmt.Printf("Processing message %s: %v\n", msg.ID, msg.Values)
}

7. Gateway Request Parsing Enhancement

Improved flexibility with unknown field handling

What's New: Gateway now ignores unknown fields in request parsing, improving API compatibility.

Benefits:

  • Backward Compatibility: Older clients can send requests with deprecated fields
  • Forward Compatibility: Newer clients can send additional fields safely
  • Graceful Degradation: Services continue working despite schema mismatches

Example:

// Service expects this structure
type UserRequest struct {
Name string `json:"name"`
Email string `json:"email"`
}

// Client sends this (extra fields are now ignored, not rejected)
{
"name": "John Doe",
"email": "john@example.com",
"deprecated_field": "old_value", // Ignored gracefully
"future_field": "new_value" // Ignored gracefully
}

8. Gateway gRPC Metadata Forwarding

Enhanced gRPC metadata forwarding to HTTP headers in gateway

What's New: Gateway now automatically forwards gRPC metadata (headers and trailers) from backend services to HTTP response headers.

Benefits:

  • Full Metadata Propagation: All gRPC headers and trailers are forwarded to HTTP clients
  • Tracing Support: Trace IDs and debugging information flow through the gateway
  • Custom Headers: Backend services can set custom headers that reach frontend clients
  • Seamless Integration: Works with existing gateway configurations

Quick Start:

// Backend gRPC service setting metadata
func (s *Service) SomeMethod(ctx context.Context, req *pb.Request) (*pb.Response, error) {
// Set headers that will be forwarded to HTTP response
err := grpc.SendHeader(ctx, metadata.Pairs(
"X-Custom-Header", "custom-value",
"X-Trace-ID", "trace-12345",
))
if err != nil {
return nil, err
}

// Set trailers that will also be forwarded
grpc.SetTrailer(ctx, metadata.Pairs(
"X-Server-Info", "grpc-backend-v1",
"X-Processing-Time", "150ms",
))

return &pb.Response{}, nil
}

// Frontend HTTP client will now receive these headers:
// X-Custom-Header: custom-value
// X-Trace-ID: trace-12345
// X-Server-Info: grpc-backend-v1
// X-Processing-Time: 150ms

๐Ÿ› Bug Fixes

1. ETCD Auto-Registration Fix

Resolved service discovery reliability issues

Problem Fixed: Services failing to auto-re-register when ETCD keys disappeared.

Impact: Improved service discovery reliability and automatic recovery.

Before vs After:

// Before: Manual re-registration required
// After: Automatic recovery
config := etcd.EtcdConf{
Hosts: []string{"localhost:2379"},
Key: "user.rpc",
// Auto-recovery now works reliably
}

2. SSE Timeout Configuration

Fixed Server-Sent Events timeout handling

Problem Fixed: SSE connections affected by http.Server's WriteTimeout causing premature disconnections.

Solution: SSE now properly handles timeouts independently of server write timeout.

// SSE now works correctly with server timeouts
server := &http.Server{
WriteTimeout: 10 * time.Second, // Won't affect SSE
}

// SSE connections maintain their own timeout handling
http.HandleFunc("/events", func(w http.ResponseWriter, r *http.Request) {
// SSE stream works regardless of server WriteTimeout
sse.StreamEvents(w, r, eventSource)
})

3. Environment Variable Unmarshaling

Fixed configuration loading from environment variables

Problem Fixed: Issues with unmarshaling environment variables for type time.Duration.

Example Fix:

type Config struct {
Timeout time.Duration `json:",env=TIMEOUT"` // Now works correctly
}

4. Memory Optimization for Large Requests

Reduced memory usage in detailed request logging

Problem Fixed: Large memory consumption when logging POST request details.

Impact: Significantly reduced memory footprint for applications with large request bodies when setting log to verbose.


5. JSON Serialization HTML Escaping

Fixed HTML escaping issues in httpx responses

Problem Fixed: Unwanted HTML escaping during JSON serialization causing malformed responses.

Before:

{"message": "Hello \\u003cworld\\u003e"}  // Incorrect escaping

After:

{"message": "Hello <world>"}  // Correct output

6. Concurrent Resource Access Fix

Fixed race conditions in ImmutableResource

Problem Fixed: Concurrent access to ImmutableResource could lead to empty results.

Impact: Improved thread safety and reliability in high-concurrency scenarios.

โšก Performance Improvements

Optimized Field Logging

Enhanced logging performance with structured field handling.

Improvement: Faster log processing with reduced allocations.

Usage:

// Optimized field logging
logx.Infow("User action",
logx.Field("user_id", userID),
logx.Field("action", "login"),
logx.Field("timestamp", time.Now()),
)

๐ŸŽฏ Migration Guide

From v1.8.5 to v1.9.0

  1. Update Dependencies:
go get github.com/zeromicro/go-zero@v1.9.0
  1. MongoDB Driver:

    • Update imports from zero-contrib if using MongoDB v1
    • Consider migrating to v2 for better performance
  2. Consumer Groups:

    • Update Redis stream processing to use new consumer group APIs

๐Ÿ™ New Contributors

Welcome to our amazing new contributors who made their first contributions:

๐Ÿ“š Additional Resources


Happy coding with go-zero v1.9.0! ๐ŸŽ‰