Updated faceai container

This commit is contained in:
MaddoScientisto 2026-04-19 08:05:21 +02:00
commit 19f0d65896
3 changed files with 136 additions and 18 deletions

View file

@ -84,7 +84,7 @@ The `processor` service is built from `docker/processor.Dockerfile`, which uses
### Persistent Logs
The checked-in local Compose stack now redirects the relevant Node service logs into `faceai/logs` on the host.
The checked-in local Compose stack now mirrors the relevant Node service logs to both Docker stdout/stderr and `faceai/logs` on the host.
After `docker compose up --build`, inspect:
@ -95,6 +95,8 @@ After `docker compose up --build`, inspect:
This keeps the useful processor diagnostics outside the Docker-managed runtime volume so they survive container rebuilds and can be inspected directly from the workspace.
Because the service entrypoints now mirror output instead of redirecting it away, the same startup and runtime messages are also visible through `docker logs regalami-faceai`, `docker logs regalami-faceai-processor`, and Portainer's container log viewer.
The current bundled Linux `face_matcher` binary is a PyInstaller build that requires `GLIBC_2.38` or newer and the `libxcb.so.1` runtime library. The checked-in local processor image satisfies that requirement.
### Run The Browser Test
@ -211,14 +213,20 @@ services:
image: forgejo.maddoscientisto.net/maddo/faceai-client:latest
container_name: regalami-faceai
restart: unless-stopped
command: sh -c "mkdir -p /data/logs && npm run start >> /data/logs/backend.log 2>&1"
command:
- node
- docker/run-with-log-file.mjs
- /data/logs/backend.log
- npm
- run
- start
environment:
NODE_ENV: production
PORT: 3001
FACEAI_FRONTEND_URL: https://ai.regalamiunsorriso.it
FACEAI_PUBLIC_BASE_URL: https://ai.regalamiunsorriso.it
FACEAI_LEGACY_RETURN_URL: https://www.regalamiunsorriso.it/faceai_return.php
FACEAI_SHARED_SECRET: change-this-to-a-long-random-secret
FACEAI_SHARED_SECRET: disagio-spaghetti-science-lol-boh
FACEAI_SESSION_COOKIE: rus_faceai_session
FACEAI_REDIS_URL: redis://redis:6379
FACEAI_QUEUE_NAME: faceai-searches
@ -228,19 +236,32 @@ services:
FACEAI_PKL_ROOT: /data/pkl
FACEAI_ENABLE_LOCAL_LEGACY_STATIC: 0
volumes:
- /var/docker/faceai/runtime:/data/runtime
- /var/docker/faceai/logs:/data/logs
- /mnt/storage/data/faceai/runtime:/data/runtime
- /mnt/storage/data/faceai/logs:/data/logs
- /mnt/nas12/nas2/RUS:/data/pkl:ro
ports:
- "127.0.0.1:3001:3001"
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:3001/health | grep -q '\"ok\":true'"]
interval: 10s
timeout: 5s
retries: 6
start_period: 20s
depends_on:
- redis
redis:
condition: service_healthy
processor:
image: forgejo.maddoscientisto.net/maddo/faceai-client:latest
container_name: regalami-faceai-processor
restart: unless-stopped
command: sh -c "mkdir -p /data/logs && npm run start:processor >> /data/logs/processor.log 2>&1"
command:
- node
- docker/run-with-log-file.mjs
- /data/logs/processor.log
- npm
- run
- start:processor
environment:
NODE_ENV: production
FACEAI_REDIS_URL: redis://redis:6379
@ -252,18 +273,24 @@ services:
FACEAI_WORKER_CONCURRENCY: 2
FACEAI_WORKER_TIMEOUT_MS: 300000
volumes:
- /var/docker/faceai/runtime:/data/runtime
- /var/docker/faceai/logs:/data/logs
- /mnt/storage/data/faceai/runtime:/data/runtime
- /mnt/storage/data/faceai/logs:/data/logs
- /mnt/nas12/nas2/RUS:/data/pkl:ro
- /var/docker/faceai/bin/Face_Recognition_Unix:/opt/face-recognition:ro
- /mnt/storage/data/faceai/bin/Face_Recognition_Unix:/opt/face-recognition:ro
depends_on:
- redis
redis:
condition: service_healthy
redis:
image: redis:7-alpine
container_name: regalami-faceai-redis
restart: unless-stopped
command: redis-server --appendonly no
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 12
```
This pattern assumes a reverse proxy on the host publishes `https://ai.regalamiunsorriso.it` and forwards to `127.0.0.1:3001`. The processor is internal-only and does not expose any public port.
@ -392,7 +419,9 @@ In the provided Docker Compose stack, that wiring is already done with:
FACEAI_LEGACY_RETURN_URL=http://localhost:8080/faceai_return.php
```
The log wiring is also already done in the checked-in Compose file with a host bind mount for `./logs:/data/logs`, so both the backend and the processor write persistent diagnostics into the workspace.
The log wiring is also already done in the checked-in Compose file with a host bind mount for `./logs:/data/logs`, so both the backend and the processor write persistent diagnostics into the workspace while also remaining visible through Docker and Portainer container logs.
The Compose contract now also includes an HTTP healthcheck on the public FaceAI service and a Redis readiness check. That makes `docker compose ps` meaningful during rollout: `faceai` only becomes healthy after `GET /health` returns `{"ok":true}`, and both the public site and the processor wait for Redis readiness before their own startup sequence begins.
The local PHP simulator also needs the legacy bridge feature flag enabled:

View file

@ -2,8 +2,17 @@ services:
faceai:
image: node:20-alpine
container_name: regalami-faceai
restart: unless-stopped
working_dir: /app
command: sh -c "mkdir -p /data/logs && npm run start --workspace @regalami/faceai-backend >> /data/logs/backend.log 2>&1"
command:
- node
- docker/run-with-log-file.mjs
- /data/logs/backend.log
- npm
- run
- start
- --workspace
- "@regalami/faceai-backend"
environment:
PORT: 3001
FACEAI_FRONTEND_URL: http://localhost:3001
@ -12,7 +21,7 @@ services:
FACEAI_PKL_ROOT: /data/pkl
FACEAI_ENABLE_LOCAL_LEGACY_STATIC: 1
FACEAI_LOCAL_LEGACY_STATIC_ROOT: /legacy-www
FACEAI_SHARED_SECRET: change-me
FACEAI_SHARED_SECRET: disagio-spaghetti-science-lol-boh
FACEAI_SESSION_COOKIE: rus_faceai_session
FACEAI_REDIS_URL: redis://redis:6379
FACEAI_RUNTIME_ROOT: /data/runtime
@ -26,8 +35,15 @@ services:
- faceai-runtime:/data/runtime
ports:
- "3001:3001"
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:3001/health | grep -q '\"ok\":true'"]
interval: 10s
timeout: 5s
retries: 6
start_period: 20s
depends_on:
- redis
redis:
condition: service_healthy
processor:
build:
@ -35,8 +51,17 @@ services:
dockerfile: docker/processor.Dockerfile
image: regalami-faceai-processor-local
container_name: regalami-faceai-processor
restart: unless-stopped
working_dir: /app
command: sh -c "mkdir -p /data/logs && npm run start --workspace @regalami/faceai-processor >> /data/logs/processor.log 2>&1"
command:
- node
- docker/run-with-log-file.mjs
- /data/logs/processor.log
- npm
- run
- start
- --workspace
- "@regalami/faceai-processor"
environment:
FACEAI_REDIS_URL: redis://redis:6379
FACEAI_QUEUE_NAME: faceai-searches
@ -52,27 +77,38 @@ services:
- ../test_pkl:/data/pkl:ro
- faceai-runtime:/data/runtime
depends_on:
- redis
redis:
condition: service_healthy
redis:
image: redis:7-alpine
container_name: regalami-faceai-redis
restart: unless-stopped
command: redis-server --appendonly no
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 12
legacy-php:
image: php:8.3-apache
container_name: regalami-legacy-php
restart: unless-stopped
environment:
FACEAI_FEATURE_ENABLED: 1
FACEAI_BACKEND_INTERNAL_URL: http://faceai:3001
FACEAI_FRONTEND_URL: http://localhost:3001
FACEAI_SHARED_SECRET: change-me
FACEAI_SHARED_SECRET: disagio-spaghetti-science-lol-boh
FACEAI_ALLOW_DEV_HANDOFF: 1
FACEAI_IDENTITY_COOKIE: rus_faceai_identity
volumes:
- ../www:/var/www/html
ports:
- "8080:80"
depends_on:
faceai:
condition: service_healthy
volumes:
faceai-runtime:

View file

@ -0,0 +1,53 @@
import fs from 'node:fs';
import fsp from 'node:fs/promises';
import path from 'node:path';
import process from 'node:process';
import { spawn } from 'node:child_process';
const [, , logPath, ...commandArgs] = process.argv;
if (!logPath || commandArgs.length === 0) {
process.stderr.write('Usage: node docker/run-with-log-file.mjs <log-path> <command> [args...]\n');
process.exit(1);
}
await fsp.mkdir(path.dirname(logPath), { recursive: true });
const logStream = fs.createWriteStream(logPath, { flags: 'a' });
const child = spawn(commandArgs[0], commandArgs.slice(1), {
cwd: process.cwd(),
env: process.env,
stdio: ['inherit', 'pipe', 'pipe']
});
function writeChunk(target, chunk) {
target.write(chunk);
logStream.write(chunk);
}
child.stdout.on('data', (chunk) => {
writeChunk(process.stdout, chunk);
});
child.stderr.on('data', (chunk) => {
writeChunk(process.stderr, chunk);
});
child.on('error', (error) => {
const message = `${error.stack || error.message}\n`;
writeChunk(process.stderr, message);
logStream.end(() => {
process.exit(1);
});
});
child.on('close', (code, signal) => {
logStream.end(() => {
if (signal) {
process.kill(process.pid, signal);
return;
}
process.exit(code ?? 1);
});
});