perf(cmpp): add durable inbound fast path
This commit is contained in:
@@ -11,6 +11,13 @@ API_METRICS_HOST="${API_METRICS_HOST:-127.0.0.1}"
|
||||
API_METRICS_PORT="${API_METRICS_PORT:-9464}"
|
||||
API_ENABLE_SEND_WORKER="${API_ENABLE_SEND_WORKER:-true}"
|
||||
API_SEND_WORKER_CONCURRENCY="${API_SEND_WORKER_CONCURRENCY:-50}"
|
||||
API_WORKER_METRICS_HOST="${API_WORKER_METRICS_HOST:-127.0.0.1}"
|
||||
API_WORKER_METRICS_PORT="${API_WORKER_METRICS_PORT:-9465}"
|
||||
CMPP_INBOUND_FAST_PATH_ENABLED="${CMPP_INBOUND_FAST_PATH_ENABLED:-true}"
|
||||
CMPP_INBOUND_WORKFLOW_WORKER_ENABLED="${CMPP_INBOUND_WORKFLOW_WORKER_ENABLED:-true}"
|
||||
API_INBOUND_WORKFLOW_CONCURRENCY="${API_INBOUND_WORKFLOW_CONCURRENCY:-32}"
|
||||
API_INBOUND_WORKFLOW_POLL_INTERVAL_MS="${API_INBOUND_WORKFLOW_POLL_INTERVAL_MS:-100}"
|
||||
API_INBOUND_WORKFLOW_STALE_SECONDS="${API_INBOUND_WORKFLOW_STALE_SECONDS:-300}"
|
||||
GATEWAY_CONTROL_ADDR="${GATEWAY_CONTROL_ADDR:-127.0.0.1:8090}"
|
||||
GATEWAY_CMPP_ADDR="${GATEWAY_CMPP_ADDR:-0.0.0.0:17890}"
|
||||
CMPP_PUBLIC_HOST="${CMPP_PUBLIC_HOST:-8.160.169.106}"
|
||||
@@ -182,7 +189,7 @@ SQL
|
||||
|
||||
write_env() {
|
||||
log "Writing production environment"
|
||||
mkdir -p /etc/cmpp-platform "$APP_DIR" "$APP_DIR/logs/api" "$APP_DIR/logs/gateway" "$APP_DIR/backups" "$OBJECT_STORAGE_LOCAL_ROOT"
|
||||
mkdir -p /etc/cmpp-platform "$APP_DIR" "$APP_DIR/logs/api" "$APP_DIR/logs/send-worker" "$APP_DIR/logs/gateway" "$APP_DIR/backups" "$OBJECT_STORAGE_LOCAL_ROOT"
|
||||
cat >/etc/cmpp-platform/cmpp-platform.env <<EOF
|
||||
NODE_ENV=production
|
||||
API_PORT=${API_PORT}
|
||||
@@ -191,6 +198,13 @@ API_METRICS_HOST=${API_METRICS_HOST}
|
||||
API_METRICS_PORT=${API_METRICS_PORT}
|
||||
API_ENABLE_SEND_WORKER=${API_ENABLE_SEND_WORKER}
|
||||
API_SEND_WORKER_CONCURRENCY=${API_SEND_WORKER_CONCURRENCY}
|
||||
API_WORKER_METRICS_HOST=${API_WORKER_METRICS_HOST}
|
||||
API_WORKER_METRICS_PORT=${API_WORKER_METRICS_PORT}
|
||||
CMPP_INBOUND_FAST_PATH_ENABLED=${CMPP_INBOUND_FAST_PATH_ENABLED}
|
||||
CMPP_INBOUND_WORKFLOW_WORKER_ENABLED=${CMPP_INBOUND_WORKFLOW_WORKER_ENABLED}
|
||||
API_INBOUND_WORKFLOW_CONCURRENCY=${API_INBOUND_WORKFLOW_CONCURRENCY}
|
||||
API_INBOUND_WORKFLOW_POLL_INTERVAL_MS=${API_INBOUND_WORKFLOW_POLL_INTERVAL_MS}
|
||||
API_INBOUND_WORKFLOW_STALE_SECONDS=${API_INBOUND_WORKFLOW_STALE_SECONDS}
|
||||
DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@127.0.0.1:5432/${DB_NAME}?schema=public
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PORT=6379
|
||||
@@ -265,12 +279,34 @@ User=cmpp-api
|
||||
Group=cmpp-security
|
||||
WorkingDirectory=${APP_DIR}/api
|
||||
EnvironmentFile=/etc/cmpp-platform/cmpp-platform.env
|
||||
Environment=CMPP_PROCESS_ROLE=api
|
||||
ExecStart=${node_bin} dist/main.js
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
StandardOutput=append:${APP_DIR}/logs/api/stdout.log
|
||||
StandardError=append:${APP_DIR}/logs/api/stderr.log
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
cat >/etc/systemd/system/cmpp-send-worker.service <<EOF
|
||||
[Unit]
|
||||
Description=CMPP durable send workflow worker
|
||||
After=network.target postgresql.service redis.service cmpp-minio.service
|
||||
|
||||
[Service]
|
||||
User=cmpp-api
|
||||
Group=cmpp-security
|
||||
WorkingDirectory=${APP_DIR}/api
|
||||
EnvironmentFile=/etc/cmpp-platform/cmpp-platform.env
|
||||
Environment=CMPP_PROCESS_ROLE=worker
|
||||
ExecStart=${node_bin} dist/send-worker.js
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
StandardOutput=append:${APP_DIR}/logs/send-worker/stdout.log
|
||||
StandardError=append:${APP_DIR}/logs/send-worker/stderr.log
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
@@ -29,6 +29,16 @@ if [[ ! "${API_SEND_WORKER_CONCURRENCY:-}" =~ ^[1-9][0-9]*$ ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${CMPP_INBOUND_FAST_PATH_ENABLED:-}" != "true" || "${CMPP_INBOUND_WORKFLOW_WORKER_ENABLED:-}" != "true" ]]; then
|
||||
echo "CMPP_INBOUND_FAST_PATH_ENABLED=true and CMPP_INBOUND_WORKFLOW_WORKER_ENABLED=true are required in $ENV_FILE." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! "${API_INBOUND_WORKFLOW_CONCURRENCY:-}" =~ ^[1-9][0-9]*$ ]]; then
|
||||
echo "API_INBOUND_WORKFLOW_CONCURRENCY must be a positive integer in $ENV_FILE." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "${CMPP_PUBLIC_HOST:-}" || ! "${CMPP_PUBLIC_PORT:-}" =~ ^[1-9][0-9]*$ ]]; then
|
||||
echo "CMPP_PUBLIC_HOST and a positive CMPP_PUBLIC_PORT are required in $ENV_FILE; these are the customer-facing CMPP endpoint." >&2
|
||||
exit 1
|
||||
@@ -64,7 +74,35 @@ PROD_ADMIN_CREDENTIAL_FILE="$ADMIN_CREDENTIAL_FILE" node tools/deploy/ensure-pro
|
||||
chmod 600 "$ADMIN_CREDENTIAL_FILE" || true
|
||||
|
||||
echo "[deploy] Ensuring runtime log directories"
|
||||
install -d -m 0755 "$APP_DIR/logs/api" "$APP_DIR/logs/gateway"
|
||||
install -d -m 0755 "$APP_DIR/logs/api" "$APP_DIR/logs/send-worker" "$APP_DIR/logs/gateway"
|
||||
|
||||
echo "[deploy] Installing split API and send-worker services"
|
||||
node_bin="$(command -v node)"
|
||||
install -d -m 0755 /etc/systemd/system/cmpp-api.service.d
|
||||
cat >/etc/systemd/system/cmpp-api.service.d/process-role.conf <<'EOF'
|
||||
[Service]
|
||||
Environment=CMPP_PROCESS_ROLE=api
|
||||
EOF
|
||||
cat >/etc/systemd/system/cmpp-send-worker.service <<EOF
|
||||
[Unit]
|
||||
Description=CMPP durable send workflow worker
|
||||
After=network.target postgresql.service redis.service cmpp-minio.service
|
||||
|
||||
[Service]
|
||||
User=cmpp-api
|
||||
Group=cmpp-security
|
||||
WorkingDirectory=$APP_DIR/api
|
||||
EnvironmentFile=$ENV_FILE
|
||||
Environment=CMPP_PROCESS_ROLE=worker
|
||||
ExecStart=$node_bin dist/send-worker.js
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
StandardOutput=append:$APP_DIR/logs/send-worker/stdout.log
|
||||
StandardError=append:$APP_DIR/logs/send-worker/stderr.log
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
echo "[deploy] Installing restricted security boundary"
|
||||
bash "$APP_DIR/tools/security/install-security-agent.sh"
|
||||
@@ -90,15 +128,16 @@ echo "[deploy] Restarting services"
|
||||
systemctl daemon-reload
|
||||
if [[ "${OBJECT_STORAGE_DRIVER:-minio}" == "local" ]]; then
|
||||
systemctl disable --now cmpp-minio 2>/dev/null || true
|
||||
systemctl enable --now cmpp-api cmpp-gateway nginx
|
||||
systemctl enable --now cmpp-api cmpp-send-worker cmpp-gateway nginx
|
||||
else
|
||||
systemctl enable --now cmpp-minio
|
||||
systemctl restart cmpp-minio
|
||||
systemctl enable --now cmpp-api cmpp-gateway nginx
|
||||
systemctl enable --now cmpp-api cmpp-send-worker cmpp-gateway nginx
|
||||
fi
|
||||
systemctl restart cmpp-gateway
|
||||
systemctl restart cmpp-security-agent
|
||||
systemctl restart cmpp-api
|
||||
systemctl restart cmpp-send-worker
|
||||
systemctl restart nginx
|
||||
|
||||
echo "[deploy] Health checks"
|
||||
@@ -117,6 +156,7 @@ wait_for_http() {
|
||||
return 1
|
||||
}
|
||||
wait_for_http "API" "http://127.0.0.1:${API_PORT:-3000}/api/health"
|
||||
wait_for_http "Send worker metrics" "http://127.0.0.1:${API_WORKER_METRICS_PORT:-9465}/metrics"
|
||||
wait_for_http "Gateway" "http://127.0.0.1:8090/health"
|
||||
redis-cli -h "${REDIS_HOST:-127.0.0.1}" -p "${REDIS_PORT:-6379}" ping >/dev/null
|
||||
pg_isready -d "${DATABASE_URL%%\?*}" >/dev/null
|
||||
|
||||
@@ -4,6 +4,7 @@ import { resolve } from 'node:path';
|
||||
const deploy = readFileSync(resolve(import.meta.dirname, 'production-deploy.sh'), 'utf8');
|
||||
const bootstrap = readFileSync(resolve(import.meta.dirname, 'production-bootstrap.sh'), 'utf8');
|
||||
const apiMain = readFileSync(resolve(import.meta.dirname, '../../api/src/main.ts'), 'utf8');
|
||||
const workerMain = readFileSync(resolve(import.meta.dirname, '../../api/src/send-worker.ts'), 'utf8');
|
||||
const required = [
|
||||
'compression_config=/etc/nginx/conf.d/cmpp-compression.conf',
|
||||
': >"$compression_config"',
|
||||
@@ -26,4 +27,22 @@ if (!apiMain.includes("process.env.API_HOST?.trim() || '127.0.0.1'") || !apiMain
|
||||
throw new Error('NestJS API must bind to API_HOST and default to loopback');
|
||||
}
|
||||
|
||||
console.log('Production deployment verified: Nginx compression is idempotent and NestJS defaults to loopback.');
|
||||
for (const marker of [
|
||||
'CMPP_INBOUND_FAST_PATH_ENABLED=true',
|
||||
'CMPP_INBOUND_WORKFLOW_WORKER_ENABLED=true',
|
||||
'API_INBOUND_WORKFLOW_CONCURRENCY',
|
||||
'cmpp-send-worker.service',
|
||||
'Environment=CMPP_PROCESS_ROLE=api',
|
||||
'Environment=CMPP_PROCESS_ROLE=worker',
|
||||
'dist/send-worker.js',
|
||||
'API_WORKER_METRICS_PORT',
|
||||
]) {
|
||||
if (!`${deploy}\n${bootstrap}`.includes(marker)) {
|
||||
throw new Error(`production deployment is missing the durable inbound worker contract: ${marker}`);
|
||||
}
|
||||
}
|
||||
if (!workerMain.includes("process.env.API_WORKER_METRICS_HOST?.trim() || '127.0.0.1'")) {
|
||||
throw new Error('send worker metrics must default to loopback');
|
||||
}
|
||||
|
||||
console.log('Production deployment verified: Nginx/API guards and the split durable send worker contract are present.');
|
||||
|
||||
Reference in New Issue
Block a user