Browse Source

Update ratelimit.py docstring; add Redis service to docker-compose

ratelimit.py: fix module docstring to reflect current _NAMESPACE resolution
  (settings.POD_NAMESPACE, not K8s SA files read inside the middleware).

docker-compose.yaml:
  - Add saplredis service (redis:7-alpine, no persistence, 512 MB maxmemory,
    allkeys-lru, 4 databases, same policy as k8s ConfigMap).
  - Add REDIS_URL=redis://saplredis:6379 and CACHE_BACKEND=redis to the
    sapl service so local docker-compose runs use Redis out of the box.
  - sapl depends_on now includes saplredis.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
rate-limiter-2026
Edward Ribeiro 3 weeks ago
parent
commit
85e971ae9b
  1. 34
      docker/docker-compose.yaml
  2. 11
      sapl/middleware/ratelimit.py

34
docker/docker-compose.yaml

@ -18,6 +18,7 @@ services:
- "5433:5432" - "5433:5432"
networks: networks:
- sapl-net - sapl-net
saplsolr: saplsolr:
image: solr:8.11 image: solr:8.11
restart: always restart: always
@ -32,6 +33,34 @@ services:
- "8983:8983" - "8983:8983"
networks: networks:
- sapl-net - sapl-net
saplredis:
image: redis:7-alpine
restart: always
container_name: redis
labels:
NAME: "redis"
command: >
redis-server
--save ""
--appendonly no
--maxmemory 512mb
--maxmemory-policy allkeys-lru
--maxmemory-samples 10
--maxclients 1000
--timeout 300
--tcp-keepalive 60
--hz 20
--lazyfree-lazy-eviction yes
--lazyfree-lazy-expire yes
--lazyfree-lazy-server-del yes
--databases 4
--protected-mode no
ports:
- "6379:6379"
networks:
- sapl-net
sapl: sapl:
image: sapl:local image: sapl:local
# build: # build:
@ -57,20 +86,25 @@ services:
IS_ZK_EMBEDDED: 'True' IS_ZK_EMBEDDED: 'True'
ENABLE_SAPN: 'False' ENABLE_SAPN: 'False'
TZ: America/Sao_Paulo TZ: America/Sao_Paulo
REDIS_URL: redis://saplredis:6379
CACHE_BACKEND: redis
volumes: volumes:
- sapl_data:/var/interlegis/sapl/data - sapl_data:/var/interlegis/sapl/data
- sapl_media:/var/interlegis/sapl/media - sapl_media:/var/interlegis/sapl/media
depends_on: depends_on:
- sapldb - sapldb
- saplsolr - saplsolr
- saplredis
ports: ports:
- "80:80" - "80:80"
networks: networks:
- sapl-net - sapl-net
networks: networks:
sapl-net: sapl-net:
name: sapl-net name: sapl-net
driver: bridge driver: bridge
volumes: volumes:
sapldb_data: sapldb_data:
sapl_data: sapl_data:

11
sapl/middleware/ratelimit.py

@ -16,11 +16,12 @@ Decision flow (per request):
All decisions are no-ops when RATELIMIT_DRY_RUN=True (logged only). All decisions are no-ops when RATELIMIT_DRY_RUN=True (logged only).
Degrades gracefully to non-atomic counting when Redis is unavailable. Degrades gracefully to non-atomic counting when Redis is unavailable.
Tenant namespace (_NAMESPACE) is resolved once at module load from: _NAMESPACE is settings.POD_NAMESPACE, resolved once at startup:
1. POD_NAMESPACE env var (K8s Downward API preferred) - K8s: start.sh reads the k8s namespace from the Downward API env var
2. K8s service-account namespace file (always present in-cluster) or the service-account namespace file, writes it to .env as POD_NAMESPACE.
3. 'global' (local development fallback) - Bare-metal / VM / docker-compose: defaults to the machine hostname
Since each pod serves exactly one tenant, this is a startup constant (socket.gethostbyname_ex result computed in settings.py).
Since a deployment serves exactly one tenant, this is a startup constant
no per-request lookup is needed or correct. no per-request lookup is needed or correct.
""" """

Loading…
Cancel
Save