Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Production-Mode Bootstrap Guide (From Empty Data)

This guide explains how hh-lion works end-to-end and how to bring it up in real (non-mock) mode when both ClickHouse and MLflow are empty.

Use this when:

  • engineering/production cannot use mock mode
  • you do not yet have enough events in ClickHouse
  • MLFLOW_MODEL_NAME / MLFLOW_MODEL_ALIAS are not set because no promoted model alias exists yet

Related docs:

1. Mental Model: How This System Works

hh-lion has two loops that must both be healthy.

Offline/model loop:

  1. Events are ingested into ClickHouse (interaction_events).
  2. Feature jobs compute member/item/cohort features.
  3. Training reads ClickHouse booking events and logs model artifacts to MLflow.
  4. Serving loads one registered model alias via MLFLOW_MODEL_NAME + MLFLOW_MODEL_ALIAS.

Online/serving loop:

  1. API receives homepage requests.
  2. API uses model + FAISS + feature services to build recommendations.
  3. API writes impression events to Kafka.
  4. Kafka consumer inserts events into ClickHouse, feeding the next training cycle.

If either loop is empty, personalization quality or readiness will degrade.

2. Non-Negotiable Requirements for Non-Mock Mode

For ENVIRONMENT=engineering and ENVIRONMENT=production:

  • MLFLOW_MODEL_NAME and MLFLOW_MODEL_ALIAS must be set.
  • FORCE_MOCK_MODEL=false.
  • MLflow and artifact storage must be reachable from serving pods.
  • ClickHouse must contain enough booking_confirmed events for training.

Training minimum from code:

  • at least 1000 valid booking interactions in interaction_events.

Valid training rows must satisfy:

  • event_type='booking_confirmed'
  • item_type='restaurant'
  • package_id IS NOT NULL
  • user_id IS NOT NULL
  • item_id IS NOT NULL

3. Bootstrap Plan (Zero -> Production Mode)

Do these phases in order.

Phase A: Infrastructure and Schema

  1. Ensure services are reachable:
  • ClickHouse
  • Redis
  • Kafka
  • Schema Registry
  • MLflow
  • S3/MinIO artifact storage
  1. Apply ClickHouse migrations:
uv run python -m scripts.migrations.apply_migrations
  1. Apply Feast definitions:
uv run python -m scripts.apply_feast_repo

Phase B: Fill ClickHouse with Events

Run a consumer continuously:

uv run python -m scripts.run_kafka_consumer

Produce bootstrap events (if real traffic is not enough yet):

uv run python -m scripts.produce_test_events --event-type booking_confirmed --count 50000

Check event count in ClickHouse:

curl -sS -u "${CLICKHOUSE_USER}:${CLICKHOUSE_PASSWORD}" \
  "https://${CLICKHOUSE_HOST}:${CLICKHOUSE_HTTP_PORT}/?database=${CLICKHOUSE_DATABASE}&query=SELECT%20count()%20FROM%20interaction_events"

Check training-eligible row count:

curl -sS -u "${CLICKHOUSE_USER}:${CLICKHOUSE_PASSWORD}" \
  "https://${CLICKHOUSE_HOST}:${CLICKHOUSE_HTTP_PORT}/?database=${CLICKHOUSE_DATABASE}&query=SELECT%20count()%20FROM%20interaction_events%20WHERE%20event_type%3D%27booking_confirmed%27%20AND%20item_type%3D%27restaurant%27%20AND%20package_id%20IS%20NOT%20NULL%20AND%20user_id%20IS%20NOT%20NULL%20AND%20item_id%20IS%20NOT%20NULL"

Phase C: Build Feast V2 Features

Compute and publish features from ClickHouse:

uv run python -m scripts.compute_member_features --mode full --publish-online
uv run python -m scripts.compute_item_features --mode full --publish-online
uv run python -m scripts.compute_cohort_features --mode full --publish-online

Validate the cohort historical rows and Redis online candidate sets before serving selected-items traffic:

uv run python -m scripts.validate_feature_store_v2 \
  --feature-set cohort_popularity_features_v2 \
  --validate-candidate-online-store \
  --candidate-online-probe-key <known-cohort-key> \
  --output text

Run the serving benchmark with the selected-items replacement gate:

uv run python -m scripts.benchmark_serving_api_v2 \
  --base-url <hh-lion-base-url> \
  --require-selected-items-replace \
  --fail-on-regression \
  --output text

Optional metadata enrichment from OpenSearch:

uv run python -m scripts.compute_item_features --mode full --publish-online --with-opensearch-metadata

Phase D: Train First Real Model and Generate Run ID

Set MLflow/artifact env:

export MLFLOW_TRACKING_URI=<mlflow-url>
export MLFLOW_S3_ENDPOINT_URL=<s3-or-minio-endpoint>
export AWS_ACCESS_KEY_ID=<artifact-access-key>
export AWS_SECRET_ACCESS_KEY=<artifact-secret-key>

Train:

TRAINING_DATA_SOURCE=clickhouse uv run python -m scripts.train --config homepage_personalization

Capture printed line:

  • Run ID: <RUN_ID>

Export a temporal holdout, then evaluate, register, backfill ANN:

uv run python - <<'PY'
from recsys.shared.polars import ClickHousePolarsClient

client = ClickHousePolarsClient.from_env()
df = client.query(
    """
    SELECT
        toString(user_id) AS user_id,
        toString(item_id) AS item_id,
        event_timestamp AS timestamp
    FROM interaction_events
    WHERE event_type = 'booking_confirmed'
      AND item_type = 'restaurant'
      AND package_id IS NOT NULL
      AND user_id IS NOT NULL
      AND item_id IS NOT NULL
    ORDER BY event_timestamp
    """
)
df.write_csv("data/temporal_holdout.csv")
print("Wrote data/temporal_holdout.csv")
PY

uv run python -m scripts.evaluate --run_id <RUN_ID> --holdout_path data/temporal_holdout.csv
uv run python -m scripts.register_model --run_id <RUN_ID> --name homepage_two_tower --stage Engineering
uv run python -m scripts.backfill_ann --run_id <RUN_ID>

Phase E: Wire Model Alias Into Deployment

Set environment variable used by deploy workflow:

gh variable set MLFLOW_MODEL_NAME --env engineering --body "homepage_two_tower"
gh variable set MLFLOW_MODEL_ALIAS --env engineering --body "engineering"

For production rollout later:

gh variable set MLFLOW_MODEL_NAME --env production --body "homepage_two_tower"
gh variable set MLFLOW_MODEL_ALIAS --env production --body "production"

Deploy with your normal workflow (.github/workflows/deploy.yml).

4. Runtime Processes You Must Keep Running

For stable production-mode behavior, these must be active:

  • Serving API deployment (FastAPI)
  • Kafka consumer(s) for event ingestion (scripts.run_kafka_consumer equivalent)
  • Personalization RQ worker(s) (rq worker hh_lion_personalization)
  • Periodic feature recomputation jobs
  • Retrain + reindex operational cadence

If worker/consumer are missing, readiness, queue lag, and model freshness will degrade.

5. Verification Checklist After Deploy

  1. Startup probe:
  • GET /health/startup returns 200.
  1. Model source:
  • GET /v2/model/info shows:
    • "model_loaded": true
    • "model_source": "mlflow"
    • "mlflow_model_name": "homepage_two_tower"
    • "mlflow_model_alias": "engineering" or "production"
  1. Readiness:
  • GET /health/ready returns 200 in engineering/production.
  • No critical check in error.
  1. Personalization flow:
  • POST /v2/homepage for a member returns sections.
  • Refresh queue does not stay pending indefinitely.

6. Common Empty-State Failures

A) MLflow is empty

Symptom:

  • no registered model version is assigned to the configured alias

Fix:

  • run Phase D training once, register the model, and assign the target alias.

B) ClickHouse is empty

Symptom:

  • training fails with insufficient interactions

Fix:

  • run Phase B event generation and keep consumer running.

C) ClickHouse protocol mismatch

Symptom:

  • Unexpected packet ... expected Hello or Exception, got Unknown packet

Cause:

  • native ClickHouse client connected to HTTP endpoint (or wrong TLS mode).

Fix:

  • ensure CLICKHOUSE_PORT is native TCP port
  • ensure CLICKHOUSE_HTTP_PORT is HTTP port
  • set CLICKHOUSE_SECURE=true only when native TLS is required by server

D) Feast config missing in container

Symptom:

  • No such file or directory: '/app/feature_repo/feature_store.yaml'

Fix:

  • ensure Docker image includes /app/feature_repo/feature_store.yaml.
  1. Run full localhost non-mock flow once to validate commands.
  2. Bootstrap engineering data/events/features.
  3. Train first engineering model, register it, and set the engineering alias.
  4. Deploy engineering with FORCE_MOCK_MODEL=false.
  5. Verify /health/ready and /v2/model/info.
  6. Only then promote the validated model alias to production.