fix(cache): remove sync.Pool for Yaegi compatibility (#121)

- [x] Remove sync.Pool implementation that causes reflection panics
- [x] Replace pool-based NewRESPWriter with direct instantiation
- [x] Replace pool-based NewRESPReader with direct instantiation
- [x] Convert Release() methods to no-ops for API compatibility
- [x] Add documentation explaining sync.Pool removal for Yaegi
- [x] Remove "sync" import

Resolves #120
This commit is contained in:
2026-01-19 17:52:31 +00:00
committed by GitHub
parent 9d52f1b018
commit de4b4d7258
+15 -34
View File
@@ -7,52 +7,34 @@ import (
"io" "io"
"strconv" "strconv"
"strings" "strings"
"sync"
) )
// RESP (REdis Serialization Protocol) implementation // RESP (REdis Serialization Protocol) implementation
// Pure Go implementation compatible with Yaegi interpreter (no unsafe package) // Pure Go implementation compatible with Yaegi interpreter (no unsafe package)
//
// NOTE: sync.Pool was intentionally removed for Yaegi compatibility.
// Yaegi (Traefik's Go interpreter) has issues with sync.Pool and reflection
// that cause "reflect: call of reflect.Value.Field on zero Value" panics.
// See: https://github.com/lukaszraczylo/traefikoidc/issues/120
var ( var (
ErrInvalidRESP = errors.New("invalid RESP response") ErrInvalidRESP = errors.New("invalid RESP response")
ErrNilResponse = errors.New("nil response") ErrNilResponse = errors.New("nil response")
) )
// Object pools for memory optimization - reduces allocations by 50-70%
var (
readerPool = sync.Pool{
New: func() interface{} {
return &RESPReader{
r: bufio.NewReaderSize(nil, 4096),
}
},
}
writerPool = sync.Pool{
New: func() interface{} {
return &RESPWriter{
w: nil,
}
},
}
)
// RESPWriter writes RESP protocol messages // RESPWriter writes RESP protocol messages
type RESPWriter struct { type RESPWriter struct {
w io.Writer w io.Writer
} }
// NewRESPWriter creates a new RESP writer from the pool (memory optimized) // NewRESPWriter creates a new RESP writer
func NewRESPWriter(w io.Writer) *RESPWriter { func NewRESPWriter(w io.Writer) *RESPWriter {
writer, _ := writerPool.Get().(*RESPWriter) return &RESPWriter{w: w}
writer.w = w
return writer
} }
// Release returns the writer to the pool for reuse // Release is a no-op for API compatibility (pooling removed for Yaegi compatibility)
func (w *RESPWriter) Release() { func (w *RESPWriter) Release() {
w.w = nil // No-op: pooling removed for Yaegi compatibility
writerPool.Put(w)
} }
// WriteCommand writes a Redis command in RESP array format // WriteCommand writes a Redis command in RESP array format
@@ -78,17 +60,16 @@ type RESPReader struct {
r *bufio.Reader r *bufio.Reader
} }
// NewRESPReader creates a new RESP reader from the pool (memory optimized) // NewRESPReader creates a new RESP reader
func NewRESPReader(r io.Reader) *RESPReader { func NewRESPReader(r io.Reader) *RESPReader {
reader, _ := readerPool.Get().(*RESPReader) return &RESPReader{
reader.r.Reset(r) r: bufio.NewReaderSize(r, 4096),
return reader }
} }
// Release returns the reader to the pool for reuse // Release is a no-op for API compatibility (pooling removed for Yaegi compatibility)
func (r *RESPReader) Release() { func (r *RESPReader) Release() {
r.r.Reset(nil) // No-op: pooling removed for Yaegi compatibility
readerPool.Put(r)
} }
// ReadResponse reads a RESP response and returns the parsed value // ReadResponse reads a RESP response and returns the parsed value