#!/usr/bin/env bash set -euo pipefail DATA_DIR="${LABEL_STUDIO_BASE_DATA_DIR:-/label-studio/data}" LOG_DIR="${LABEL_STUDIO_LOG_DIR:-/label-studio/logs}" mkdir -p "$DATA_DIR" "$LOG_DIR" export PYTHONPATH="/app/scripts:${PYTHONPATH:-}" _log() { printf '[%s] %s\n' "$(date -u +'%Y-%m-%dT%H:%M:%SZ')" "$*" } _print_startup_environment() { python3 - <<'PY' import os from datetime import datetime, timezone safe_r2_variables = { "R2_BUCKET_NAME", "R2_SYNC_INTERVAL_SEC", "R2_SYNC_ON_START", "R2_SYNC_ON_STOP", } sensitive_name_parts = ( "ACCESS_KEY", "API_KEY", "AUTH", "CREDENTIAL", "DATABASE_URL", "PASSWORD", "PASSWD", "PRIVATE_KEY", "REDIS_URL", "SECRET", "SESSION", "TOKEN", ) def log(message: str) -> None: timestamp = datetime.now(timezone.utc).isoformat(timespec="seconds").replace( "+00:00", "Z" ) print(f"[{timestamp}] {message}", flush=True) log("[entrypoint] Startup environment (sensitive values are redacted):") for name in sorted(os.environ): upper_name = name.upper() is_r2_credential = ( upper_name.startswith("R2_") and upper_name not in safe_r2_variables ) is_sensitive = is_r2_credential or any( part in upper_name for part in sensitive_name_parts ) if is_sensitive: value = "" else: value = os.environ[name].encode( "unicode_escape", errors="backslashreplace" ).decode("ascii") log(f"[entrypoint] {name}={value}") PY } _print_startup_environment if [[ "${R2_SYNC_ON_START:-1}" == "1" ]] && [[ -n "${R2_ACCESS_KEY_ID:-}" ]]; then _log "[r2-sync] Pulling Label Studio state on startup." python3 /app/scripts/sync_label_studio_r2.py pull --data-dir "$DATA_DIR" || true fi if [[ -n "${SECRET_KEY:-}" ]]; then printf 'SECRET_KEY=%s\n' "$SECRET_KEY" > "$DATA_DIR/.env" fi _sync_push() { if [[ -z "${R2_ACCESS_KEY_ID:-}" ]]; then _log "[r2-sync] Push skipped: R2_ACCESS_KEY_ID is not configured." return 0 fi python3 /app/scripts/sync_label_studio_r2.py push --data-dir "$DATA_DIR" } _sync_on_stop() { if [[ "${R2_SYNC_ON_STOP:-1}" == "1" ]]; then _log "[r2-sync] Pushing Label Studio state on shutdown." _sync_push || true else _log "[r2-sync] Shutdown push is disabled." fi } SYNC_PID="" APP_PID="" SYNC_INTERVAL="${R2_SYNC_INTERVAL_SEC:-300}" if [[ "$SYNC_INTERVAL" =~ ^[0-9]+$ ]] && [[ "$SYNC_INTERVAL" -gt 0 ]]; then _log "[r2-sync] Periodic push enabled every ${SYNC_INTERVAL} seconds." ( while true; do sleep "$SYNC_INTERVAL" _log "[r2-sync] Starting periodic push." _sync_push || true done ) & SYNC_PID=$! else _log "[r2-sync] Periodic push disabled (R2_SYNC_INTERVAL_SEC=${SYNC_INTERVAL})." fi _stop_periodic_sync() { if [[ -n "$SYNC_PID" ]] && kill -0 "$SYNC_PID" 2>/dev/null; then kill "$SYNC_PID" 2>/dev/null || true wait "$SYNC_PID" 2>/dev/null || true fi } _shutdown() { local signal="$1" local app_status=0 trap - INT TERM _log "[entrypoint] Received ${signal}; stopping Label Studio." _stop_periodic_sync if [[ -n "$APP_PID" ]] && kill -0 "$APP_PID" 2>/dev/null; then kill -s "$signal" "$APP_PID" 2>/dev/null || true fi wait "$APP_PID" 2>/dev/null || app_status=$? _sync_on_stop exit "$app_status" } if [[ -n "${SPACE_HOST:-}" ]]; then label-studio --host="$SPACE_HOST" & else label-studio --host="${LABEL_STUDIO_HOST:-0.0.0.0}" --port="${LABEL_STUDIO_PORT:-8080}" & fi APP_PID=$! trap '_shutdown INT' INT trap '_shutdown TERM' TERM APP_STATUS=0 wait "$APP_PID" || APP_STATUS=$? trap - INT TERM _stop_periodic_sync _sync_on_stop exit "$APP_STATUS"