From 65878cf5dbf8733cf030492c1cdfc34c6e0b5c19 Mon Sep 17 00:00:00 2001 From: Theodore Li Date: Mon, 6 Jul 2026 18:07:10 -0700 Subject: [PATCH 1/2] feat(pii): env-driven uvicorn worker count (PII_WORKERS) Launch the Presidio service with --workers from the PII_WORKERS env var so one image scales per task size (set PII_WORKERS = the task's vCPU count) without a rebuild. `sh -c exec` expands the var while keeping uvicorn as PID 1 for clean SIGTERM. Defaults to 1, so local/self-hosted is unchanged. Each worker loads the spaCy models independently (~3.3GB measured), so task memory must be sized to PII_WORKERS x ~3.3GB + overhead (set in infra alongside PII_WORKERS). --- docker/pii.Dockerfile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docker/pii.Dockerfile b/docker/pii.Dockerfile index 73f56647909..538f182cbbe 100644 --- a/docker/pii.Dockerfile +++ b/docker/pii.Dockerfile @@ -47,4 +47,8 @@ EXPOSE 5001 HEALTHCHECK --interval=30s --timeout=5s --start-period=180s --retries=3 \ CMD curl -fsS http://localhost:5001/health || exit 1 -CMD ["uvicorn", "server:app", "--host", "0.0.0.0", "--port", "5001"] +# Worker count is env-driven so ONE image scales per task size: set PII_WORKERS to +# the task's vCPU count (each worker loads the models independently, ~3 GB each, so +# size task memory ≈ PII_WORKERS × 3 GB + overhead). Defaults to 1 for local/small. +# `sh -c exec` expands the env var while keeping uvicorn as PID 1 for clean SIGTERM. +CMD ["sh", "-c", "exec uvicorn server:app --host 0.0.0.0 --port 5001 --workers ${PII_WORKERS:-1}"] From 044eb3d1c955b1d3dd2b688b9cd9b706e5e4006f Mon Sep 17 00:00:00 2001 From: Theodore Li Date: Mon, 6 Jul 2026 18:14:16 -0700 Subject: [PATCH 2/2] harden(pii): quote PII_WORKERS expansion + raise healthcheck start-period for multi-worker - Quote ${PII_WORKERS} so a malformed value fails uvicorn arg-parsing instead of being shell-interpreted (verified: '1; echo X' rejected as non-integer, X not run) - Bump HEALTHCHECK start-period 180s -> 300s: N workers load the spaCy models in parallel, stretching cold start beyond the single-worker case --- docker/pii.Dockerfile | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docker/pii.Dockerfile b/docker/pii.Dockerfile index 538f182cbbe..29cb5185ea4 100644 --- a/docker/pii.Dockerfile +++ b/docker/pii.Dockerfile @@ -42,13 +42,16 @@ USER pii # 5001 avoids colliding with the app's 3000 in local/compose runs on one host. EXPOSE 5001 -# start-period is generous: five large spaCy models load at import before -# /health responds. Tune against measured cold-start once built. -HEALTHCHECK --interval=30s --timeout=5s --start-period=180s --retries=3 \ +# start-period covers the model cold start. With PII_WORKERS>1 each worker loads +# the five spaCy models independently and in parallel, so allow generous headroom +# (memory-bandwidth contention stretches the wall-time beyond the single-worker case). +HEALTHCHECK --interval=30s --timeout=5s --start-period=300s --retries=3 \ CMD curl -fsS http://localhost:5001/health || exit 1 # Worker count is env-driven so ONE image scales per task size: set PII_WORKERS to # the task's vCPU count (each worker loads the models independently, ~3 GB each, so # size task memory ≈ PII_WORKERS × 3 GB + overhead). Defaults to 1 for local/small. # `sh -c exec` expands the env var while keeping uvicorn as PID 1 for clean SIGTERM. -CMD ["sh", "-c", "exec uvicorn server:app --host 0.0.0.0 --port 5001 --workers ${PII_WORKERS:-1}"] +# Quote the expansion so a malformed PII_WORKERS fails uvicorn arg-parsing rather +# than being interpreted by the shell. +CMD ["sh", "-c", "exec uvicorn server:app --host 0.0.0.0 --port 5001 --workers \"${PII_WORKERS:-1}\""]