Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Loan Approval MLOps Demo

An end-to-end MLOps pipeline for loan approval, built to mirror a standard "manual exploratory workflow -> automated pipeline" architecture:

Manual/Exploratory: Ingest -> Prepare/Transform -> Process -> Feature Store -> Bias Detection -> Train & Tune -> Register Model -> Deploy -> Online Feature Store -> Run Inference

Automated: Airflow DAG -> Monitor (drift) -> Retrain (scheduled DAG) -> Scale Inference

Everything runs locally with pip + venv. No Docker required. One exception: Airflow needs WSL2 (see section 3) since it doesn't run natively on Windows — everything else is pure Windows Python.

A Jenkins version (jenkins/Jenkinsfile) is also included as a fallback if WSL2 setup goes sideways before Monday — same pipeline, no WSL needed.


0. Airflow crash course (read this before the run-through)

You don't need deep Airflow expertise — you need to fluently use these five concepts, which map directly onto what's already built in this repo:

  • DAG (Directed Acyclic Graph) — a pipeline definition: a set of tasks and the order they must run in. This repo has two: loan_approval_full_pipeline and loan_approval_retrain, both defined in airflow_home/dags/loan_approval_pipeline.py.
  • Task / Operator — one step in the DAG. BashOperator runs a shell command (used here to call your .py scripts); PythonOperator runs a Python function directly in-process (used here for the model hot-swap call). Every diagram box became one task.
  • Dependencies (>>)ingest >> prepare >> feature_store >> train means "prepare only starts after ingest succeeds." This is the actual arrows in your architecture diagram, expressed in code.
  • Scheduler — the process that watches all DAGs and decides when to run them, based on each DAG's schedule (None = manual trigger only; timedelta(hours=6) = run automatically every 6 hours). This is the literal mechanism behind the "Automated Workflow" box.
  • Webserver / UI — the dashboard at localhost:8080 showing DAG runs, a live Graph view of tasks turning green/red as they execute, and logs per task. This is what you'll have open during the demo.

If asked anything deeper (XComs, sensors, executors, backfills) it's fine to say "I focused on getting DAGs, task dependencies, and scheduling solid for this project — happy to go deeper on [topic] if useful," which is honest and still shows you know the landscape.


1. One-time setup (do this today, not Sunday night)

1a. Python project (Windows, no WSL needed for this part)

cd C:\
REM copy this folder to C:\ml-mlops-demo

cd ml-mlops-demo
py -3.12 -m venv venv
venv\Scripts\activate
pip install -r requirements.txt

1b. WSL2 + Airflow (needed for the orchestration piece)

Open PowerShell as Administrator:

wsl --install

Reboot when prompted. This installs Ubuntu by default. After reboot, it'll open a terminal asking you to create a Linux username/password — do that, then you're in a real Linux shell running inside Windows.

Your Windows C:\ drive is auto-mounted inside WSL2 at /mnt/c/, so C:\ml-mlops-demo becomes /mnt/c/ml-mlops-demo — this is why the DAG file uses that path format.

Inside the WSL2 terminal:

sudo apt update && sudo apt install -y python3-venv python3-pip

cd /mnt/c/ml-mlops-demo
python3 -m venv airflow_venv
source airflow_venv/bin/activate

AIRFLOW_VERSION=2.10.4
PYTHON_VERSION=3.12
CONSTRAINT_URL="https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt"
pip install "apache-airflow==${AIRFLOW_VERSION}" --constraint "${CONSTRAINT_URL}"

Set Airflow's home and disable the clutter of built-in example DAGs:

export AIRFLOW_HOME=/mnt/c/ml-mlops-demo/airflow_home
airflow db migrate
sed -i 's/^load_examples = True/load_examples = False/' $AIRFLOW_HOME/airflow.cfg

Also point the DAG at your actual venv paths (only needed if you didn't put the project at C:\ml-mlops-demo — the defaults already match that path):

export LOAN_DEMO_PYTHON=/mnt/c/ml-mlops-demo/venv/Scripts/python.exe
export LOAN_DEMO_SRC=/mnt/c/ml-mlops-demo/src

Note: if calling the Windows venv's python.exe from inside WSL2 gives you grief, the simpler path is to also pip install -r requirements.txt inside a second, WSL2-native venv and point LOAN_DEMO_PYTHON at that instead — then everything (Airflow + your scripts) runs natively in Linux and you sidestep any Windows/WSL interop issues entirely. This is what I'd actually recommend if you have the extra 15 minutes.

Add these export lines to ~/.bashrc inside WSL2 so you don't retype them every session:

echo 'export AIRFLOW_HOME=/mnt/c/ml-mlops-demo/airflow_home' >> ~/.bashrc
echo 'export LOAN_DEMO_PYTHON=/mnt/c/ml-mlops-demo/venv/Scripts/python.exe' >> ~/.bashrc
echo 'export LOAN_DEMO_SRC=/mnt/c/ml-mlops-demo/src' >> ~/.bashrc

2. Run order (do this once now to make sure it all works on YOUR machine)

Open 1 WSL2 terminal and 4 PowerShell windows. In each PowerShell window: cd C:\ml-mlops-demo and venv\Scripts\activate.

PowerShell 1 — MLflow tracking server (leave running)

mlflow server --host 127.0.0.1 --port 5000

Open http://localhost:5000 — you should see the MLflow UI.

WSL2 terminal — start Airflow (leave running)

cd /mnt/c/ml-mlops-demo
source airflow_venv/bin/activate
airflow standalone

This starts both the webserver and scheduler, and prints an admin password in the terminal output — copy it. Open http://localhost:8080, log in as admin with that password.

You should see two DAGs: loan_approval_full_pipeline and loan_approval_retrain. Un-pause loan_approval_full_pipeline (toggle on the left), click it, then Trigger DAG (play button, top right). Watch the Graph view — tasks turn green left to right as they complete: ingest_data -> prepare_process_data -> store_in_feature_store -> train_and_tune_models -> detect_and_mitigate_bias -> deploy_hotswap_model -> monitor_for_drift.

Check MLflow UI: Experiments tab shows loan_approval with new runs. Models tab shows loan_approval_model with a champion alias.

PowerShell 2 — start the inference API (leave running)

python -m uvicorn src.deploy_api:app --host 127.0.0.1 --port 8001

Open http://localhost:8001/docs — try POST /predict with {"applicant_id": 5}.

Back in Airflow UI — trigger the retrain DAG live Un-pause and trigger loan_approval_retrain. Watch it run, then check /health on port 8001 again — model_version should have incremented, proving the DAG hot-swapped the live API with zero downtime, orchestrated entirely by Airflow's scheduler rather than a manual script call.

Open reports\monitoring\drift_report.html (generated by the monitor_for_drift task) in a browser — this is your Evidently drift dashboard.

PowerShell 3 & 4 — scale inference demo

REM PowerShell 3
python -m uvicorn src.deploy_api:app --host 127.0.0.1 --port 8002
REM PowerShell 4
python src\scale_inference_demo.py

Shows requests round-robining across two replicas.

For the scheduled retrain story: point out that loan_approval_retrain has schedule=timedelta(hours=6) set in the DAG — in the Airflow UI's DAG list you can see its next scheduled run time, which is the concrete "automated retraining" proof point interviewers usually want to see.


3. What to say in the interview (mapping back to the diagram)

Diagram box What you show Where
Ingest / Prepare / Process ingest.py, prepare_features.py as Airflow tasks Airflow Graph view
Store Data in Feature Store Feast local repo, feast apply output Terminal + src/feature_store/
Detect and Mitigate Bias Fairlearn demographic parity/equalized odds, before/after mitigation bias_check.py output + MLflow run
Train & Tune Models Two candidate models, best picked by AUC MLflow experiment UI
Associate Lineage / Deposit in Registry mlflow.register_model, version tags, champion alias MLflow Models UI
Deploy Models / Run Inference FastAPI /predict, live Feast online lookup http://localhost:8001/docs
Online Feature Store Feast SQLite online store, materialized data materialize.py
Build Pipeline that integrates Steps Airflow DAG, explicit task dependency graph http://localhost:8080
Monitor Models Evidently drift report reports/monitoring/drift_report.html
Retrain Models Second Airflow DAG on a timedelta(hours=6) schedule, hot-swap Airflow UI + /health
Scale Inference Two replicas + round-robin script scale_inference_demo.py

Is this production-grade?": this is a local, single-node reference implementation of the pattern — in production you'd swap SQLite/file stores for Redis/S3/a real data warehouse, standalone Airflow for a managed instance (MWAA, Composer, Astronomer) with a proper executor (Celery/Kubernetes instead of the local SequentialExecutor), and add authentication, autoscaling, and canary deployments. The point was to demonstrate you understand every stage of the lifecycle and how they connect, not to reinvent a managed platform.

Why Airflow over Jenkins/other schedulers": DAGs give you explicit dependency graphs (not just a linear script), per-task retries and backfills, a scheduler that's aware of run history, and it's the de-facto standard for data/ML pipeline orchestration — which is why it shows up in almost every MLOps job posting.


4. Known rough edges (so you're not surprised live)

  • feast, mlflow, and the API all show harmless DeprecationWarning lines on some versions — cosmetic, doesn't affect functionality
  • The bias-mitigation step (ThresholdOptimizer) needs the sensitive attribute (gender) passed at prediction time too — that's realistic: fairness-aware post-processing generally requires it, and it's a good talking point about the practical trade-offs of different mitigation techniques (pre-processing vs. in-processing vs. post-processing)
  • If port 5000/8001/8002/8080 are already in use on your machine, change the port in the relevant command AND in deploy_api.py / loan_approval_pipeline.py (MLFLOW_TRACKING_URI, the reload_model URL)
  • Airflow's local SequentialExecutor (the default in airflow standalone) runs one task at a time — totally fine for this demo, just don't expect true parallelism without swapping executors
  • src/retrain_trigger.py still exists as a manual, Airflow-free way to trigger a full retrain cycle from the command line (python src\retrain_trigger.py) — useful for quick local testing without spinning up Airflow, or as a second fallback if both WSL2 and Jenkins give you trouble

5. Fallback: Jenkins version (no WSL2 needed)

If WSL2/Airflow setup isn't working in time, jenkins/Jenkinsfile runs the identical pipeline stages using Jenkins instead, which installs natively on Windows with no WSL required. Install from https://www.jenkins.io/download/, create a Pipeline job, paste the Jenkinsfile contents, edit PROJECT_DIR at the top, and click Build Now. Same demo story, same scripts, different orchestrator.

About

Airflow

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages