feat(filters): enforce safe Node.js heap sizing via reusable filter

- Add node_autosize filter (node_max_old_space_size) using get_app_conf
- Raise error when mem_limit < min_mb to prevent OOM-kill misconfigurations
- Wire Whiteboard NODE_OPTIONS and increase mem_limit to 1g; set cpus=1
- Refactor PeerTube to use the same filter; simplify vars
- Add unit tests; keep integration filters usage green

Context: https://chatgpt.com/share/690e0499-6a94-800f-b8ed-2c5124690103
This commit is contained in:
2025-11-07 15:39:54 +01:00
parent 493d5bbbda
commit 36f9573fdf
6 changed files with 231 additions and 31 deletions

View File

@@ -93,9 +93,9 @@ docker:
version: "latest"
backup:
no_stop_required: true
cpus: "0.25"
cpus: "1"
mem_reservation: "128m"
mem_limit: "512m"
mem_limit: "1g"
pids_limit: 1024
enabled: "{{ applications | get_app_conf('web-app-nextcloud', 'features.oidc', False, True, True) }}" # Activate OIDC for Nextcloud
# floavor decides which OICD plugin should be used.

View File

@@ -77,7 +77,8 @@
volumes:
- whiteboard_tmp:/tmp
- whiteboard_fontcache:/var/cache/fontconfig
environment:
- NODE_OPTIONS=--max-old-space-size={{ NEXTCLOUD_WHITEBOARD_MAX_OLD_SPACE_SIZE }}
expose:
- "{{ container_port }}"
shm_size: 1g

View File

@@ -130,6 +130,7 @@ NEXTCLOUD_WHITEBOARD_TMP_VOLUME: "{{ applications | get_app_conf(applic
NEXTCLOUD_WHITEBOARD_FRONTCACHE_VOLUME: "{{ applications | get_app_conf(application_id, 'docker.volumes.whiteboard_fontcache') }}"
NEXTCLOUD_WHITEBOARD_SERVICE_DIRECTORY: "{{ [ docker_compose.directories.services, 'whiteboard' ] | path_join }}"
NEXTCLOUD_WHITEBOARD_SERVICE_DOCKERFILE: "{{ [ NEXTCLOUD_WHITEBOARD_SERVICE_DIRECTORY, 'Dockerfile' ] | path_join }}"
NEXTCLOUD_WHITEBOARD_MAX_OLD_SPACE_SIZE: "{{ applications | node_max_old_space_size(application_id, NEXTCLOUD_WHITEBOARD_SERVICE) }}"
### Collabora
NEXTCLOUD_COLLABORA_URL: "{{ domains | get_url('web-svc-collabora', WEB_PROTOCOL) }}"

View File

@@ -1,6 +1,7 @@
# General
application_id: "web-app-peertube"
database_type: "postgres"
entity_name: "{{ application_id | get_entity_name }}"
# Docker
docker_compose_flush_handlers: true
@@ -16,32 +17,8 @@ PEERTUBE_CONFIG_VOLUME: "{{ applications | get_app_conf(application_id
PEERTUBE_OIDC_PLUGIN: "peertube-plugin-auth-openid-connect"
PEERTUBE_OIDC_ENABLED: "{{ applications | get_app_conf(application_id, 'features.oidc') }}"
# === Dynamic performance defaults ==========================================
# Raw Docker configuration values (with sane fallbacks)
peertube_cpus: "{{ applications | get_app_conf(application_id, 'docker.services.peertube.cpus') | float }}"
peertube_mem_limit_raw: "{{ applications | get_app_conf(application_id, 'docker.services.peertube.mem_limit') }}"
peertube_mem_bytes: "{{ peertube_mem_limit_raw | human_to_bytes }}"
peertube_mem_mb: "{{ ((peertube_mem_bytes | int) // (1024 * 1024)) | int }}"
# ---------------------------------------------------------------------------
# Node heap size:
# ~35% of total RAM, but at least 768 MB, at most 3072 MB,
# and never more than 60% of total memory (safety cap for small containers)
# ---------------------------------------------------------------------------
_peertube_heap_candidate_mb: "{{ ((peertube_mem_mb | float) * 0.35) | round(0, 'floor') | int }}"
_peertube_heap_cap_mb: "{{ ((peertube_mem_mb | float) * 0.60) | round(0, 'floor') | int }}"
# Step 1: enforce minimum (≥768 MB)
_peertube_heap_min_applied: "{{ [ (_peertube_heap_candidate_mb | int), 768 ] | max }}"
# Step 2: determine hard cap (min of 3072 MB and 60% of total memory)
_peertube_heap_hardcap: "{{ [ 3072, (_peertube_heap_cap_mb | int) ] | min }}"
# Step 3: final heap = min(min-applied, hardcap)
PEERTUBE_MAX_OLD_SPACE_SIZE: "{{ [ (_peertube_heap_min_applied | int), (_peertube_heap_hardcap | int) ] | min }}"
# Transcoding concurrency: half the vCPUs; min 1, max 8
_peertube_concurrency_candidate: "{{ ((peertube_cpus | float) * 0.5) | round(0, 'floor') | int }}"
# Performance
PEERTUBE_CPUS: "{{ applications | get_app_conf(application_id, 'docker.services.peertube.cpus') | float }}"
PEERTUBE_MAX_OLD_SPACE_SIZE: "{{ applications | node_max_old_space_size(application_id, entity_name) }}"
_peertube_concurrency_candidate: "{{ ((PEERTUBE_CPUS | float) * 0.5) | round(0, 'floor') | int }}"
PEERTUBE_TRANSCODING_CONCURRENCY: "{{ [ ( [ (_peertube_concurrency_candidate | int), 1 ] | max ), 8 ] | min }}"