netx: Network Extensions for Go

中文 | English
netx is a zero-dependency, high-performance network layer extension library for Go.
Designed based on the Decorator Pattern, it aims to enhance the standard net.Listener and net.Conn. It provides Lifecycle Management, Overload Protection, Traffic Shaping, and Observability for the underlying network layer while maintaining perfect compatibility with the standard library.
Core Philosophies
- Mechanism over Policy:
netx only provides the underlying mechanisms for "how to limit rates" or "how to collect stats." Decisions on "what the rate limit is" or "where to send stats" are entirely controlled by the user via callbacks or factory injection.
- Onion Model & Context Penetration: Through a unified
Wrapper interface, it supports Context penetration from the outermost layer to the innermost layer, bridging the lifecycle between L4 (TCP) and L7 (Application).
- Zero Intrusion: All components return a standard
net.Listener, making them directly usable with http.Server, grpc.Server, or any framework that accepts a standard Listener.
Installation
go get github.com/oy3o/netx
Quick Start
Use Chain to combine multiple features like building blocks:
package main
import (
"net"
"net/http"
"time"
"github.com/oy3o/netx"
)
func main() {
// 1. Create a basic Listener
ln, _ := net.Listen("tcp", ":8080")
// 2. Wrap it like an onion
ln = netx.Chain(ln,
// [Performance] Enable TCP KeepAlive (Default: 3 minutes)
netx.WithKeepAlive(0),
// [Protection] Limit max concurrent connections to 10,000 to prevent OOM
netx.WithLimit(10000),
// [Lifecycle] Bind Context; auto-cancel Context when connection closes
netx.WithContext(nil),
)
// 3. Start standard HTTP Server
http.Serve(ln, nil)
}
Core Components
1. Lifecycle (Context & Lifecycle)
Introducing context.Context at the TCP layer is one of the most powerful features of netx.
- Function: Binds a Context to every connection. When the physical connection is closed (
Close), the Context is automatically cancelled (Done).
- Usage: Business logic can listen to the Context to implement graceful exits or resource cleanup.
ln = netx.WithContext(func(c net.Conn) context.Context {
// Optional: Inject TraceID or Logger here
return context.WithValue(context.Background(), "trace_id", uuid.NewString())
})
// Access in business code:
func HandleRequest(w http.ResponseWriter, r *http.Request) {
// GetContext can recursively find the deepest Context even through layers of wrappers
connContext := netx.GetContext(r.Context().Value(http.LocalAddrContextKey).(net.Conn))
select {
case <-connContext.Done():
println("TCP connection closed, stop processing")
}
}
2. Traffic Shaping
Implement complex rate-limiting logic (e.g., Global limits, Single IP limits, VIP bypass) through policy injection.
- Mechanism: Intercepts
Read/Write.
- Policy: User injected via
ShaperFactory.
// Define your rate limiting policy
factory := func(c net.Conn) (read, write netx.Bucket) {
ip := getIP(c.RemoteAddr())
if isVIP(ip) {
return nil, nil // No limit for VIPs
}
// Normal users use token bucket (requires implementing netx.Bucket interface)
return globalRateLimiter, globalRateLimiter
}
ln = netx.WithShaper(factory)
3. Overload Protection
- WithLimit(n): Uses a semaphore mechanism to limit the maximum number of concurrent connections. When the limit is reached,
Accept for new connections will block (handled by the kernel backlog), protecting the Server from being overwhelmed by traffic spikes.
4. Observability
netx does not bind to any specific metrics library (like Prometheus). Instead, it provides pure callback hooks.
ln = netx.WithObserve(func(c net.Conn, state netx.ConnState) {
if state == netx.StateOpen {
metrics.ActiveConns.Inc()
} else {
metrics.ActiveConns.Dec()
}
})
Best Practices
It is recommended to encapsulate default combination logic within your server package, following the "Default to Secure & Observable" principle:
func Listen(addr string) (net.Listener, error) {
l, err := net.Listen("tcp", addr)
if err != nil { return nil, err }
return netx.Chain(l,
netx.WithKeepAlive(0), // Always enable
netx.WithContext(nil), // Always bind lifecycle
netx.WithLimit(50000), // Always set safety limit
netx.WithObserve(myMetrics),// Always enable monitoring
), nil
}
Contribution
Issues and PRs are welcome to enrich netx capabilities (e.g., WithTLS, WithProxyProtocol, etc.). Please maintain the Zero Dependency principle.