Compare commits

..
Author SHA1 Message Date
maxlerebourg 022747488c Adjust lease duration to prevent cache update conflicts
Updated lease duration logic to ensure a minimum of 1 second.
2026-08-07 12:12:59 +02:00
mhx 0ed8154340 🐛 keep the stream lease alive when updateIntervalSeconds is 1
handleStreamCache takes a lease so a single node polls LAPI per interval,
and stores it for updateInterval-1 seconds. The e2e stream scenario now
sets updateIntervalSeconds to 1, which makes that a 0 second duration:
golang-ttl-map returns early on a zero ttl (map.go:114) and redis rejects
a non positive EX, so the lease is never stored and the guard silently
does nothing.

Floor the duration at 1 second. At an interval of 1 the lease can survive
a tick that fires slightly early and cost one skipped poll, which is far
better than every node polling every tick against a shared redis.
2026-08-03 13:47:43 +02:00
18 changed files with 34 additions and 39 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
steps:
- uses: actions/checkout@v7
- name: Set up Go
uses: actions/setup-go@v7
uses: actions/setup-go@v6
with:
# Track go.mod (Go 1.22) — the plugin's yaegi-bound floor. Keeps the
# single source of truth and builds the mock on the supported version.
+1 -1
View File
@@ -32,7 +32,7 @@ jobs:
# https://github.com/marketplace/actions/setup-go-environment
- name: Set up Go ${{ env.GO_VERSION }}
uses: actions/setup-go@v7
uses: actions/setup-go@v6
with:
go-version: ${{ env.GO_VERSION }}
+1 -1
View File
@@ -28,7 +28,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Run Renovate
uses: renovatebot/github-action@v46.2.2
uses: renovatebot/github-action@v46.1.21
with:
token: ${{ secrets.RENOVATE_TOKEN }}
env:
+1 -1
View File
@@ -1,6 +1,6 @@
services:
traefik:
image: "traefik:v3.7.11"
image: "traefik:v3.7.9"
container_name: "traefik"
restart: unless-stopped
command:
+2 -2
View File
@@ -1,6 +1,6 @@
services:
traefik:
image: "traefik:v3.7.11"
image: "traefik:v3.7.9"
container_name: "traefik"
restart: unless-stopped
command:
@@ -12,7 +12,7 @@ services:
- "--entrypoints.web.address=:80"
- "--experimental.plugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
- "--experimental.plugins.bouncer.version=v1.7.1"
- "--experimental.plugins.bouncer.version=v1.7.0"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
# - './ban.html:/ban.html:ro'
+2 -2
View File
@@ -1,6 +1,6 @@
services:
traefik:
image: "traefik:v3.7.11"
image: "traefik:v3.7.9"
container_name: "traefik"
restart: unless-stopped
command:
@@ -13,7 +13,7 @@ services:
- "--entrypoints.web.address=:80"
- "--experimental.plugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
- "--experimental.plugins.bouncer.version=v1.7.1"
- "--experimental.plugins.bouncer.version=v1.7.0"
# - "--experimental.localplugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
+3 -3
View File
@@ -1,6 +1,6 @@
services:
cloudflare:
image: "traefik:v3.7.11"
image: "traefik:v3.7.9"
container_name: "cloudflare"
restart: unless-stopped
command:
@@ -19,7 +19,7 @@ services:
- 8080:8080
traefik:
image: "traefik:v3.7.11"
image: "traefik:v3.7.9"
container_name: "traefik"
restart: unless-stopped
command:
@@ -33,7 +33,7 @@ services:
- "--entrypoints.web.forwardedheaders.trustedips=172.21.0.5"
- "--experimental.plugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
- "--experimental.plugins.bouncer.version=v1.7.1"
- "--experimental.plugins.bouncer.version=v1.7.0"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- logs-traefik:/var/log/traefik
+2 -2
View File
@@ -1,6 +1,6 @@
services:
traefik:
image: "traefik:v3.7.11"
image: "traefik:v3.7.9"
container_name: "traefik"
restart: unless-stopped
command:
@@ -13,7 +13,7 @@ services:
- "--entrypoints.web.address=:80"
- "--experimental.plugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
- "--experimental.plugins.bouncer.version=v1.7.1"
- "--experimental.plugins.bouncer.version=v1.7.0"
# - "--experimental.localplugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
+2 -2
View File
@@ -1,6 +1,6 @@
services:
traefik:
image: "traefik:v3.7.11"
image: "traefik:v3.7.9"
container_name: "traefik"
restart: unless-stopped
command:
@@ -13,7 +13,7 @@ services:
- "--entrypoints.web.address=:80"
- "--experimental.plugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
- "--experimental.plugins.bouncer.version=v1.7.1"
- "--experimental.plugins.bouncer.version=v1.7.0"
# - "--experimental.localplugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
+2 -2
View File
@@ -1,6 +1,6 @@
services:
traefik:
image: "traefik:v3.7.11"
image: "traefik:v3.7.9"
container_name: "traefik"
restart: unless-stopped
command:
@@ -14,7 +14,7 @@ services:
- "--entrypoints.web.forwardedheaders.trustedips=172.18.0.0/24"
- "--experimental.plugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
- "--experimental.plugins.bouncer.version=v1.7.1"
- "--experimental.plugins.bouncer.version=v1.7.0"
# - "--experimental.localplugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
+2 -2
View File
@@ -1,5 +1,5 @@
image:
tag: v3.7.11
tag: v3.7.9
logs:
general:
@@ -15,4 +15,4 @@ experimental:
plugins:
bouncer:
moduleName: "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
version: "v1.7.1"
version: "v1.7.0"
+3 -3
View File
@@ -1,6 +1,6 @@
services:
traefik:
image: "traefik:v3.7.11"
image: "traefik:v3.7.9"
container_name: "traefik"
restart: unless-stopped
command:
@@ -13,7 +13,7 @@ services:
- "--entrypoints.web.address=:80"
- "--experimental.plugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
- "--experimental.plugins.bouncer.version=v1.7.1"
- "--experimental.plugins.bouncer.version=v1.7.0"
# - "--experimental.localplugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
@@ -87,7 +87,7 @@ services:
- "traefik.enable=false"
redis-secure:
image: "redis:8.10.0-alpine"
image: "redis:8.8.1-alpine"
container_name: "redis-secure"
hostname: redis-secure
restart: unless-stopped
+2 -2
View File
@@ -1,6 +1,6 @@
services:
traefik:
image: "traefik:v3.7.11"
image: "traefik:v3.7.9"
container_name: "traefik"
restart: unless-stopped
command:
@@ -13,7 +13,7 @@ services:
- "--entrypoints.web.address=:80"
- "--experimental.plugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
- "--experimental.plugins.bouncer.version=v1.7.1"
- "--experimental.plugins.bouncer.version=v1.7.0"
# - "--experimental.localplugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
+2 -2
View File
@@ -1,6 +1,6 @@
services:
traefik:
image: "traefik:v3.7.11"
image: "traefik:v3.7.9"
container_name: "traefik"
restart: unless-stopped
command:
@@ -13,7 +13,7 @@ services:
- "--entrypoints.web.address=:80"
- "--experimental.plugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
- "--experimental.plugins.bouncer.version=v1.7.1"
- "--experimental.plugins.bouncer.version=v1.7.0"
# - "--experimental.localplugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
+2 -2
View File
@@ -1,6 +1,6 @@
services:
traefik:
image: "traefik:v3.7.11"
image: "traefik:v3.7.9"
container_name: "traefik"
restart: unless-stopped
command:
@@ -13,7 +13,7 @@ services:
- "--entrypoints.web.address=:80"
- "--experimental.plugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
- "--experimental.plugins.bouncer.version=v1.7.1"
- "--experimental.plugins.bouncer.version=v1.7.0"
# - "--experimental.localplugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
+3 -5
View File
@@ -52,7 +52,7 @@ func (localCache) delete(key string) {
type redisCache struct {
log *slog.Logger
writer simpleredis.SimpleRedis
readers []*simpleredis.SimpleRedis
readers []simpleredis.SimpleRedis
counter atomic.Uint64
}
@@ -62,7 +62,7 @@ func (rc *redisCache) nextReader() *simpleredis.SimpleRedis {
return &rc.writer
}
idx := rc.counter.Add(1) % uint64(n)
return rc.readers[idx]
return &rc.readers[idx]
}
func (rc *redisCache) get(key string) (string, error) {
@@ -115,9 +115,7 @@ func (c *Client) New(log *slog.Logger, isRedis bool, writeHost string, readHosts
rc := &redisCache{log: log}
rc.writer.Init(writeHost, pass, database)
for _, h := range readHosts {
// 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{}
var r simpleredis.SimpleRedis
r.Init(h, pass, database)
rc.readers = append(rc.readers, r)
}
+2 -5
View File
@@ -130,7 +130,7 @@ func indexOfReader(rc *redisCache, r *simpleredis.SimpleRedis) int {
return -1
}
for i := range rc.readers {
if r == rc.readers[i] {
if r == &rc.readers[i] {
return i
}
}
@@ -151,10 +151,7 @@ func Test_nextReader(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
rc := &redisCache{log: logger.New("INFO", "")}
rc.readers = make([]*simpleredis.SimpleRedis, tt.readers)
for i := range rc.readers {
rc.readers[i] = &simpleredis.SimpleRedis{}
}
rc.readers = make([]simpleredis.SimpleRedis, tt.readers)
for call, want := range tt.want {
if got := indexOfReader(rc, rc.nextReader()); 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
# Pinned to match the Docker suite (tests/e2e/scenarios/*/docker-compose.yml).
TRAEFIK_VERSION="${TRAEFIK_VERSION:-v3.7.11}"
TRAEFIK_VERSION="${TRAEFIK_VERSION:-v3.7.9}"
WEB_PORT="${WEB_PORT:-8000}"
LAPI_PORT="${LAPI_PORT:-8090}"