Compare commits

..
Author SHA1 Message Date
mhxandClaude Opus 5 f359d5d935 cache: keep redis readers by pointer
A pooled SimpleRedis holds a sync.Mutex, so appending one into rc.readers
by value copies the lock and trips go vet's copylocks check. Keep the
readers by pointer instead; the round-robin over replicas is unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D95Nh68xKXhynPXHzozrXp
2026-08-25 19:40:35 +02:00
17 changed files with 37 additions and 32 deletions
+1 -1
View File
@@ -28,7 +28,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Run Renovate - name: Run Renovate
uses: renovatebot/github-action@v46.2.5 uses: renovatebot/github-action@v46.2.2
with: with:
token: ${{ secrets.RENOVATE_TOKEN }} token: ${{ secrets.RENOVATE_TOKEN }}
env: env:
+2 -2
View File
@@ -1,6 +1,6 @@
services: services:
traefik: traefik:
image: "traefik:v3.7.12" image: "traefik:v3.7.11"
container_name: "traefik" container_name: "traefik"
restart: unless-stopped restart: unless-stopped
command: command:
@@ -80,7 +80,7 @@ services:
- "traefik.http.routers.router-bar3.entrypoints=web" - "traefik.http.routers.router-bar3.entrypoints=web"
- "traefik.http.routers.router-bar3.middlewares=crowdsec2@docker" - "traefik.http.routers.router-bar3.middlewares=crowdsec2@docker"
crowdsec: crowdsec:
image: crowdsecurity/crowdsec:v1.8.0 image: crowdsecurity/crowdsec:v1.7.8
container_name: "crowdsec" container_name: "crowdsec"
restart: unless-stopped restart: unless-stopped
environment: environment:
+2 -2
View File
@@ -1,6 +1,6 @@
services: services:
traefik: traefik:
image: "traefik:v3.7.12" image: "traefik:v3.7.11"
container_name: "traefik" container_name: "traefik"
restart: unless-stopped restart: unless-stopped
command: command:
@@ -59,7 +59,7 @@ services:
- "traefik.http.middlewares.crowdsec.plugin.bouncer.forwardedheaderstrustedips=172.21.0.5" - "traefik.http.middlewares.crowdsec.plugin.bouncer.forwardedheaderstrustedips=172.21.0.5"
crowdsec: crowdsec:
image: crowdsecurity/crowdsec:v1.8.0 image: crowdsecurity/crowdsec:v1.7.8
container_name: "crowdsec" container_name: "crowdsec"
restart: unless-stopped restart: unless-stopped
environment: environment:
+2 -2
View File
@@ -1,6 +1,6 @@
services: services:
traefik: traefik:
image: "traefik:v3.7.12" image: "traefik:v3.7.11"
container_name: "traefik" container_name: "traefik"
restart: unless-stopped restart: unless-stopped
command: command:
@@ -47,7 +47,7 @@ services:
- "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecappsechost=crowdsec:7422" - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecappsechost=crowdsec:7422"
crowdsec: crowdsec:
image: crowdsecurity/crowdsec:v1.8.0 image: crowdsecurity/crowdsec:v1.7.8
container_name: "crowdsec" container_name: "crowdsec"
restart: unless-stopped restart: unless-stopped
environment: environment:
+3 -3
View File
@@ -1,6 +1,6 @@
services: services:
cloudflare: cloudflare:
image: "traefik:v3.7.12" image: "traefik:v3.7.11"
container_name: "cloudflare" container_name: "cloudflare"
restart: unless-stopped restart: unless-stopped
command: command:
@@ -19,7 +19,7 @@ services:
- 8080:8080 - 8080:8080
traefik: traefik:
image: "traefik:v3.7.12" image: "traefik:v3.7.11"
container_name: "traefik" container_name: "traefik"
restart: unless-stopped restart: unless-stopped
command: command:
@@ -79,7 +79,7 @@ services:
crowdsec: crowdsec:
image: crowdsecurity/crowdsec:v1.8.0 image: crowdsecurity/crowdsec:v1.7.8
container_name: "crowdsec" container_name: "crowdsec"
restart: unless-stopped restart: unless-stopped
environment: environment:
+2 -2
View File
@@ -1,6 +1,6 @@
services: services:
traefik: traefik:
image: "traefik:v3.7.12" image: "traefik:v3.7.11"
container_name: "traefik" container_name: "traefik"
restart: unless-stopped restart: unless-stopped
command: command:
@@ -55,7 +55,7 @@ services:
- "traefik.http.middlewares.crowdsec.plugin.bouncer.captchaHTMLFilePath=/captcha.html" - "traefik.http.middlewares.crowdsec.plugin.bouncer.captchaHTMLFilePath=/captcha.html"
crowdsec: crowdsec:
image: crowdsecurity/crowdsec:v1.8.0 image: crowdsecurity/crowdsec:v1.7.8
container_name: "crowdsec" container_name: "crowdsec"
restart: unless-stopped restart: unless-stopped
environment: environment:
+2 -2
View File
@@ -1,6 +1,6 @@
services: services:
traefik: traefik:
image: "traefik:v3.7.12" image: "traefik:v3.7.11"
container_name: "traefik" container_name: "traefik"
restart: unless-stopped restart: unless-stopped
command: command:
@@ -46,7 +46,7 @@ services:
- "traefik.http.middlewares.crowdsec.plugin.bouncer.banFilePath=/ban.html" - "traefik.http.middlewares.crowdsec.plugin.bouncer.banFilePath=/ban.html"
crowdsec: crowdsec:
image: crowdsecurity/crowdsec:v1.8.0 image: crowdsecurity/crowdsec:v1.7.8
container_name: "crowdsec" container_name: "crowdsec"
restart: unless-stopped restart: unless-stopped
environment: environment:
+2 -2
View File
@@ -1,6 +1,6 @@
services: services:
traefik: traefik:
image: "traefik:v3.7.12" image: "traefik:v3.7.11"
container_name: "traefik" container_name: "traefik"
restart: unless-stopped restart: unless-stopped
command: command:
@@ -59,7 +59,7 @@ services:
- "traefik.http.middlewares.crowdsec.plugin.bouncer.captchaHTMLFilePath=/captcha.html" - "traefik.http.middlewares.crowdsec.plugin.bouncer.captchaHTMLFilePath=/captcha.html"
crowdsec: crowdsec:
image: crowdsecurity/crowdsec:v1.8.0 image: crowdsecurity/crowdsec:v1.7.8
container_name: "crowdsec" container_name: "crowdsec"
restart: unless-stopped restart: unless-stopped
environment: environment:
+1 -1
View File
@@ -1,5 +1,5 @@
image: image:
tag: v1.8.0-2 tag: v1.7.8-2
agent: agent:
acquisition: acquisition:
+1 -1
View File
@@ -1,5 +1,5 @@
image: image:
tag: v3.7.12 tag: v3.7.11
logs: logs:
general: general:
+3 -3
View File
@@ -1,6 +1,6 @@
services: services:
traefik: traefik:
image: "traefik:v3.7.12" image: "traefik:v3.7.11"
container_name: "traefik" container_name: "traefik"
restart: unless-stopped restart: unless-stopped
command: command:
@@ -71,7 +71,7 @@ services:
crowdsec: crowdsec:
image: crowdsecurity/crowdsec:v1.8.0 image: crowdsecurity/crowdsec:v1.7.8
container_name: "crowdsec" container_name: "crowdsec"
restart: unless-stopped restart: unless-stopped
environment: environment:
@@ -87,7 +87,7 @@ services:
- "traefik.enable=false" - "traefik.enable=false"
redis-secure: redis-secure:
image: "redis:8.10.1-alpine" image: "redis:8.10.0-alpine"
container_name: "redis-secure" container_name: "redis-secure"
hostname: redis-secure hostname: redis-secure
restart: unless-stopped restart: unless-stopped
+1 -1
View File
@@ -1,6 +1,6 @@
services: services:
traefik: traefik:
image: "traefik:v3.7.12" image: "traefik:v3.7.11"
container_name: "traefik" container_name: "traefik"
restart: unless-stopped restart: unless-stopped
command: command:
+2 -2
View File
@@ -1,6 +1,6 @@
services: services:
traefik: traefik:
image: "traefik:v3.7.12" image: "traefik:v3.7.11"
container_name: "traefik" container_name: "traefik"
restart: unless-stopped restart: unless-stopped
command: command:
@@ -71,7 +71,7 @@ services:
# Define AppSec host and port informations # Define AppSec host and port informations
- "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecappsechost=crowdsec:7422" - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecappsechost=crowdsec:7422"
crowdsec: crowdsec:
image: crowdsecurity/crowdsec:v1.8.0 image: crowdsecurity/crowdsec:v1.7.8
container_name: "crowdsec" container_name: "crowdsec"
restart: unless-stopped restart: unless-stopped
environment: environment:
+2 -2
View File
@@ -1,6 +1,6 @@
services: services:
traefik: traefik:
image: "traefik:v3.7.12" image: "traefik:v3.7.11"
container_name: "traefik" container_name: "traefik"
restart: unless-stopped restart: unless-stopped
command: command:
@@ -65,7 +65,7 @@ services:
crowdsec: crowdsec:
image: crowdsecurity/crowdsec:v1.8.0 image: crowdsecurity/crowdsec:v1.7.8
container_name: "crowdsec" container_name: "crowdsec"
restart: unless-stopped restart: unless-stopped
environment: environment:
+5 -3
View File
@@ -52,7 +52,7 @@ func (localCache) delete(key string) {
type redisCache struct { type redisCache struct {
log *slog.Logger log *slog.Logger
writer simpleredis.SimpleRedis writer simpleredis.SimpleRedis
readers []simpleredis.SimpleRedis readers []*simpleredis.SimpleRedis
counter atomic.Uint64 counter atomic.Uint64
} }
@@ -62,7 +62,7 @@ func (rc *redisCache) nextReader() *simpleredis.SimpleRedis {
return &rc.writer return &rc.writer
} }
idx := rc.counter.Add(1) % uint64(n) idx := rc.counter.Add(1) % uint64(n)
return &rc.readers[idx] return rc.readers[idx]
} }
func (rc *redisCache) get(key string) (string, error) { func (rc *redisCache) get(key string) (string, error) {
@@ -115,7 +115,9 @@ func (c *Client) New(log *slog.Logger, isRedis bool, writeHost string, readHosts
rc := &redisCache{log: log} rc := &redisCache{log: log}
rc.writer.Init(writeHost, pass, database) rc.writer.Init(writeHost, pass, database)
for _, h := range readHosts { for _, h := range readHosts {
var r simpleredis.SimpleRedis // A pooled SimpleRedis holds a mutex, so it is kept by pointer:
// appending it by value would copy the lock along with it.
r := &simpleredis.SimpleRedis{}
r.Init(h, pass, database) r.Init(h, pass, database)
rc.readers = append(rc.readers, r) rc.readers = append(rc.readers, r)
} }
+5 -2
View File
@@ -130,7 +130,7 @@ func indexOfReader(rc *redisCache, r *simpleredis.SimpleRedis) int {
return -1 return -1
} }
for i := range rc.readers { for i := range rc.readers {
if r == &rc.readers[i] { if r == rc.readers[i] {
return i return i
} }
} }
@@ -151,7 +151,10 @@ func Test_nextReader(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
rc := &redisCache{log: logger.New("INFO", "")} rc := &redisCache{log: logger.New("INFO", "")}
rc.readers = make([]simpleredis.SimpleRedis, tt.readers) rc.readers = make([]*simpleredis.SimpleRedis, tt.readers)
for i := range rc.readers {
rc.readers[i] = &simpleredis.SimpleRedis{}
}
for call, want := range tt.want { for call, want := range tt.want {
if got := indexOfReader(rc, rc.nextReader()); got != want { if got := indexOfReader(rc, rc.nextReader()); got != want {
t.Errorf("call %d: nextReader() -> reader[%d], want reader[%d]", call, got, want) t.Errorf("call %d: nextReader() -> reader[%d], want reader[%d]", call, got, want)
+1 -1
View File
@@ -14,7 +14,7 @@
set -euo pipefail set -euo pipefail
# Pinned to match the Docker suite (tests/e2e/scenarios/*/docker-compose.yml). # Pinned to match the Docker suite (tests/e2e/scenarios/*/docker-compose.yml).
TRAEFIK_VERSION="${TRAEFIK_VERSION:-v3.7.12}" TRAEFIK_VERSION="${TRAEFIK_VERSION:-v3.7.11}"
WEB_PORT="${WEB_PORT:-8000}" WEB_PORT="${WEB_PORT:-8000}"
LAPI_PORT="${LAPI_PORT:-8090}" LAPI_PORT="${LAPI_PORT:-8090}"