Skip to content

Recipe: Production Pipelines & Orchestration

For data engineers and analytics teams maintaining a production data warehouse (PostgreSQL, Snowflake, BigQuery, or MotherDuck), Retrosheet ingestion should run as an automated, idempotent ELT pipeline.

This guide outlines an end-to-end production pipeline pattern using retrosheetpy, SQL DDL, and dlt.


Pattern: Schema Setup -> Staging -> Load

sequenceDiagram
    autonumber
    participant Pipeline as Orchestrator (Airflow / Cron)
    participant RS as retrosheetpy
    participant DB as Production Database

    Pipeline->>RS: rs.get_ddl("gamelogs", dialect="postgres")
    RS-->>Pipeline: CREATE TABLE IF NOT EXISTS ...
    Pipeline->>DB: Execute DDL (Idempotent table creation)
    Pipeline->>RS: rs.to_dlt(destination, years=[2024], ...)
    RS->>DB: Stream typed Arrow RecordBatches (0.1s load)
    DB-->>Pipeline: Complete with 0 failed jobs

Production Python Script (sync_retrosheet.py)

import os
import dlt
import retrosheetpy as rs
from sqlalchemy import create_engine, text

# 1. Connection string from environment variable
DB_URI = os.getenv("DATABASE_URL", "postgresql://postgres:postgres@localhost:5432/retrosheet")

# 2. Pre-create strongly-typed tables using DDL generator
engine = create_engine(DB_URI)
with engine.begin() as conn:
    for dataset in ["gamelogs", "rosters", "parks"]:
        ddl = rs.get_ddl(dataset, dialect="postgres")
        conn.execute(text(ddl))

# 3. Stream data via dlt
pipeline = dlt.pipeline(
    pipeline_name="retrosheet_production_sync",
    destination=dlt.destinations.postgres(DB_URI),
    dataset_name="public",
)

# Ingest current season with replace disposition
source = rs.to_dlt(
    destination=dlt.destinations.postgres(DB_URI),
    years=[2024],
    datasets=["gamelogs", "rosters", "parks"],
    dataset_name="public",
)

print("Pipeline synchronization complete!")

Running Headless via Cron or Docker

You can run this pipeline inside a lightweight container or scheduled GitHub Action:

# .github/workflows/nightly-sync.yml
name: Nightly Retrosheet Sync
on:
  schedule:
    - cron: '0 4 * * *'  # 4:00 AM UTC
jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/setup-uv@v5
      - run: uv run python sync_retrosheet.py
        env:
          DATABASE_URL: ${{ secrets.PROD_DB_URL }}