- Fix handleConnection to use addr parameter for direct upstream map
lookup instead of always selecting the first upstream
- Add Server.Stop() for graceful shutdown with listener closing, UDP
server cleanup, health checker termination, and goroutine joining
- Add shutdownStream() to App and call it in SIGTERM/SIGQUIT/SIGUSR2
signal handlers to prevent goroutine and port leaks on shutdown
- Verify Least Time picks faster target consistently
- Verify Sticky fallback when target becomes unhealthy
- Test cookie encoding and session persistence
- Record headerTime when header is received
- Record lastByteTime when response is complete
- Use correct timing calculations (headerReceived/connectEnd/responseEnd)
- Add least_time and sticky to createBalancerByName
- Implement response time recording for Least Time
- Support StickySession in target selector with request context
- StickySession auto-starts when created
- Add least_time and sticky to valid algorithms list
- Add LeastTimeConfig and StickyConfig structures
- Update default config generation with new options
- Add configuration validation for new fields
- Add sync.Once to prevent double close of stopCh in Stop()
- Add nil fallback guard in NewStickySession (defaults to RoundRobin)
- Add atomic.Bool to make Start() idempotent
- Add tests for double Stop() and nil fallback scenarios
- Fix Select to check if cookie is expired before routing
- Add TestStickySession_ExpiredCookie test
- Expired cookies now trigger fallback + new cookie set
- Encode cookie as base64(target_url + | + timestamp) per spec
- Use cookie value (not targetURL) for shard key and session map keys
- Add missing sticky.Start() calls in tests
- Fix time precision in cookie encode/decode tests
- Add atomic EWMA Stats field to Target
- Implement LeastTime balancer with header_time and last_byte metrics
- Support Select and SelectExcluding with zero-lock design
- Add ResponseTimeRecorder interface for proxy integration
- Zero-lock atomic EWMA implementation using fixed-point arithmetic
- Supports header_time and last_byte_time tracking
- Concurrent-safe with CAS retry loop
- Auto-detect VERSION from git tags with fallback
- Extract mkdir as order-only prerequisite to eliminate duplication
- Add PERF_GCFLAGS/PERF_ASMFLAGS to cross-platform builds and install
- Merge bench-regression into bench-check, unify file naming
- Fix bench scope and sampling consistency (internal/ only, -run=^$)
- Fix test-cover scope to avoid un-tagged integration/e2e code
- Fix deprecated go get -u ./... to go get -u
- Add clean-mod target, clean benchmark artifacts in clean
- Remove phantom build-prod/build-perf from help
- Split docker long line for readability
- Add .PHONY declarations for all targets
Add matcher.ReleaseMatchResult(result) in the base handler to prevent
sync.Pool object leak. Every Match() call acquires from pool but the
caller never returned objects, causing unbounded pool growth.
Replace manual PEM text scanning with pem.Decode(). Returns proper
DER-encoded bytes instead of raw PEM text, fixing potential TLS
handshake failures with certificate chains.
Remove unused findMarker and matchMarker helpers.
- Check(): single GeoIP LookupCountry call, result reused for both
deny and allow checks. Removed goto label for structured flow.
- getClientIP(): single trusted proxy CIDR scan gates both
X-Forwarded-For and X-Real-IP processing.
- Pre-build extSet map for O(1) extension lookup instead of linear scan
- Replace bytes.ToLower allocation in supportsEncoding with
utils.BytesContainsFold for case-insensitive encoding detection
Add typesBytes and typesWildcardPrefix fields to Middleware, built once
at construction. isCompressible now uses pre-converted byte slices
instead of allocating []byte(t) per comparison per request.
Accept []byte directly instead of string, allowing callers to pass
fasthttp's ctx.Path() without string conversion. Internally uses
bytes.HasPrefix instead of strings.HasPrefix in radix tree search.
Three optimizations in the proxy cache hot path:
- Pre-build cacheIgnoreSet map once at Proxy creation instead of
per-response. Eliminates map allocation + linear scan per cached
response.
- Compute cache key once per request via computeCacheKey() closure.
Previously buildCacheKeyHash was called up to 5 times per request;
now computed on first access and reused.
- Pool UpstreamTiming objects with sync.Pool. Eliminates one heap
allocation per proxied request.
Replace string(connection)/strings.EqualFold/strings.ToLower with
bytes.EqualFold and utils.BytesContainsFold. Removes 2-4 heap
allocations per proxied request.
Replaces fnv.New64a() with direct inline hash computation over
fasthttp's []byte slices, eliminating 1 allocation per cache key
computation and 1 []byte(":") allocation.