✅ Validation Results: - PPO training: 24.2s (1 epoch, 950 samples, dim=225) - Feature extraction: 105μs/bar (9.5x faster than target) - Model checkpoint: 293KB (147KB actor + 146KB critic) - GPU memory: 145MB used (96.4% headroom) - Zero dimension mismatches 📊 Success Criteria (5/5): ✅ Feature dimension = 225 (Wave C 201 + Wave D 24) ✅ Model state_dim = 225 ✅ Training completed without errors ✅ Checkpoint saved successfully ✅ No dimension mismatch errors 📁 Training Data Ready: - ES.FUT: 2.9MB, 180 days - NQ.FUT: 4.4MB, 180 days - 6E.FUT: 2.8MB, 180 days - ZN.FUT: 65KB, 90 days (clean) 🚀 Next: Full production model retraining (4 models, ~10min GPU time) 🤖 Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
336 lines
12 KiB
PL/PgSQL
336 lines
12 KiB
PL/PgSQL
-- ================================================================================================
|
|
-- Migration 046: Batch Job Tracking Schema
|
|
-- Support for batch job orchestration with parent-child job hierarchy and progress aggregation
|
|
-- ================================================================================================
|
|
|
|
-- ================================================================================================
|
|
-- BATCH JOBS TABLE
|
|
-- Parent jobs that orchestrate multiple child training jobs
|
|
-- ================================================================================================
|
|
CREATE TABLE IF NOT EXISTS batch_jobs (
|
|
-- Primary identifiers
|
|
id UUID PRIMARY KEY,
|
|
|
|
-- Batch job metadata
|
|
name VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
|
|
-- Status tracking
|
|
status VARCHAR(50) NOT NULL DEFAULT 'Pending',
|
|
|
|
-- Progress aggregation
|
|
total_jobs INTEGER NOT NULL DEFAULT 0,
|
|
pending_jobs INTEGER NOT NULL DEFAULT 0,
|
|
running_jobs INTEGER NOT NULL DEFAULT 0,
|
|
completed_jobs INTEGER NOT NULL DEFAULT 0,
|
|
failed_jobs INTEGER NOT NULL DEFAULT 0,
|
|
overall_progress DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
|
|
|
-- Configuration
|
|
config_json JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
|
|
-- Audit timestamps
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
started_at TIMESTAMPTZ,
|
|
completed_at TIMESTAMPTZ,
|
|
|
|
-- Constraints
|
|
CONSTRAINT chk_batch_job_status CHECK (
|
|
status IN ('Pending', 'Running', 'Completed', 'Failed', 'Stopped', 'Paused')
|
|
),
|
|
CONSTRAINT chk_batch_job_counts CHECK (
|
|
total_jobs >= 0 AND
|
|
pending_jobs >= 0 AND
|
|
running_jobs >= 0 AND
|
|
completed_jobs >= 0 AND
|
|
failed_jobs >= 0 AND
|
|
(pending_jobs + running_jobs + completed_jobs + failed_jobs) <= total_jobs
|
|
),
|
|
CONSTRAINT chk_batch_job_progress CHECK (
|
|
overall_progress >= 0.0 AND overall_progress <= 100.0
|
|
)
|
|
);
|
|
|
|
-- Add table comment
|
|
COMMENT ON TABLE batch_jobs IS 'Parent batch jobs that orchestrate multiple child training jobs with progress aggregation';
|
|
|
|
-- Add column comments
|
|
COMMENT ON COLUMN batch_jobs.id IS 'Unique batch job identifier';
|
|
COMMENT ON COLUMN batch_jobs.name IS 'Human-readable batch job name';
|
|
COMMENT ON COLUMN batch_jobs.status IS 'Current batch job status (Pending, Running, Completed, Failed, Stopped, Paused)';
|
|
COMMENT ON COLUMN batch_jobs.total_jobs IS 'Total number of child jobs in this batch';
|
|
COMMENT ON COLUMN batch_jobs.pending_jobs IS 'Number of pending child jobs';
|
|
COMMENT ON COLUMN batch_jobs.running_jobs IS 'Number of running child jobs';
|
|
COMMENT ON COLUMN batch_jobs.completed_jobs IS 'Number of completed child jobs';
|
|
COMMENT ON COLUMN batch_jobs.failed_jobs IS 'Number of failed child jobs';
|
|
COMMENT ON COLUMN batch_jobs.overall_progress IS 'Weighted overall progress (0.0-100.0)';
|
|
COMMENT ON COLUMN batch_jobs.config_json IS 'Batch job configuration and metadata';
|
|
|
|
-- ================================================================================================
|
|
-- CHILD JOBS TABLE
|
|
-- Individual training jobs that belong to a batch
|
|
-- ================================================================================================
|
|
CREATE TABLE IF NOT EXISTS child_jobs (
|
|
-- Primary identifiers
|
|
id UUID PRIMARY KEY,
|
|
batch_id UUID NOT NULL REFERENCES batch_jobs(id) ON DELETE CASCADE,
|
|
|
|
-- Job metadata
|
|
model_type VARCHAR(50) NOT NULL,
|
|
model_weight DOUBLE PRECISION NOT NULL DEFAULT 0.25,
|
|
|
|
-- Status tracking
|
|
status VARCHAR(50) NOT NULL DEFAULT 'Pending',
|
|
|
|
-- Progress tracking
|
|
current_epoch INTEGER NOT NULL DEFAULT 0,
|
|
total_epochs INTEGER NOT NULL DEFAULT 0,
|
|
progress_pct DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
|
|
|
-- Configuration
|
|
config_json JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
|
|
-- Error tracking
|
|
error_message TEXT,
|
|
|
|
-- Audit timestamps
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
started_at TIMESTAMPTZ,
|
|
completed_at TIMESTAMPTZ,
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
|
|
-- Constraints
|
|
CONSTRAINT chk_child_job_status CHECK (
|
|
status IN ('Pending', 'Running', 'Completed', 'Failed', 'Stopped', 'Paused')
|
|
),
|
|
CONSTRAINT chk_child_job_model_type CHECK (
|
|
model_type IN ('DQN', 'PPO', 'MAMBA-2', 'TFT', 'TLOB')
|
|
),
|
|
CONSTRAINT chk_child_job_weight CHECK (
|
|
model_weight >= 0.0 AND model_weight <= 1.0
|
|
),
|
|
CONSTRAINT chk_child_job_progress CHECK (
|
|
progress_pct >= 0.0 AND progress_pct <= 100.0
|
|
),
|
|
CONSTRAINT chk_child_job_epochs CHECK (
|
|
current_epoch >= 0 AND
|
|
total_epochs >= 0 AND
|
|
current_epoch <= total_epochs
|
|
)
|
|
);
|
|
|
|
-- Add table comment
|
|
COMMENT ON TABLE child_jobs IS 'Individual child training jobs that belong to a parent batch job';
|
|
|
|
-- Add column comments
|
|
COMMENT ON COLUMN child_jobs.id IS 'Unique child job identifier';
|
|
COMMENT ON COLUMN child_jobs.batch_id IS 'Parent batch job identifier';
|
|
COMMENT ON COLUMN child_jobs.model_type IS 'Type of ML model (DQN, PPO, MAMBA-2, TFT, TLOB)';
|
|
COMMENT ON COLUMN child_jobs.model_weight IS 'Weight for progress aggregation (0.0-1.0)';
|
|
COMMENT ON COLUMN child_jobs.status IS 'Current job status (Pending, Running, Completed, Failed, Stopped, Paused)';
|
|
COMMENT ON COLUMN child_jobs.current_epoch IS 'Current training epoch (0-based)';
|
|
COMMENT ON COLUMN child_jobs.total_epochs IS 'Total number of training epochs';
|
|
COMMENT ON COLUMN child_jobs.progress_pct IS 'Individual job progress (0.0-100.0)';
|
|
COMMENT ON COLUMN child_jobs.config_json IS 'Child job configuration and metadata';
|
|
|
|
-- ================================================================================================
|
|
-- HIGH-PERFORMANCE INDEXES
|
|
-- ================================================================================================
|
|
|
|
-- Index for batch job queries
|
|
CREATE INDEX IF NOT EXISTS idx_batch_jobs_status
|
|
ON batch_jobs(status);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_batch_jobs_created_at
|
|
ON batch_jobs(created_at DESC);
|
|
|
|
-- Index for child job queries
|
|
CREATE INDEX IF NOT EXISTS idx_child_jobs_batch_id
|
|
ON child_jobs(batch_id);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_child_jobs_status
|
|
ON child_jobs(status);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_child_jobs_model_type
|
|
ON child_jobs(model_type);
|
|
|
|
-- Composite index for batch summary queries
|
|
CREATE INDEX IF NOT EXISTS idx_child_jobs_batch_status
|
|
ON child_jobs(batch_id, status);
|
|
|
|
-- GIN indexes for JSONB queries
|
|
CREATE INDEX IF NOT EXISTS idx_batch_jobs_config_gin
|
|
ON batch_jobs USING GIN (config_json);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_child_jobs_config_gin
|
|
ON child_jobs USING GIN (config_json);
|
|
|
|
-- ================================================================================================
|
|
-- TRIGGER FUNCTIONS FOR DATA INTEGRITY
|
|
-- ================================================================================================
|
|
|
|
-- Function to update child job updated_at timestamp
|
|
CREATE OR REPLACE FUNCTION update_child_jobs_timestamp()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
NEW.updated_at := NOW();
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- Trigger to auto-update updated_at on modification
|
|
CREATE TRIGGER tg_child_jobs_update_timestamp
|
|
BEFORE UPDATE ON child_jobs
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION update_child_jobs_timestamp();
|
|
|
|
-- Function to update batch job counts and progress
|
|
CREATE OR REPLACE FUNCTION update_batch_job_aggregates()
|
|
RETURNS TRIGGER AS $$
|
|
DECLARE
|
|
v_batch_id UUID;
|
|
v_total_jobs INTEGER;
|
|
v_pending_jobs INTEGER;
|
|
v_running_jobs INTEGER;
|
|
v_completed_jobs INTEGER;
|
|
v_failed_jobs INTEGER;
|
|
v_weighted_progress DOUBLE PRECISION;
|
|
v_new_status VARCHAR(50);
|
|
BEGIN
|
|
-- Determine which batch to update
|
|
v_batch_id := COALESCE(NEW.batch_id, OLD.batch_id);
|
|
|
|
-- Count jobs by status
|
|
SELECT
|
|
COUNT(*),
|
|
COUNT(*) FILTER (WHERE status = 'Pending'),
|
|
COUNT(*) FILTER (WHERE status = 'Running'),
|
|
COUNT(*) FILTER (WHERE status = 'Completed'),
|
|
COUNT(*) FILTER (WHERE status = 'Failed')
|
|
INTO
|
|
v_total_jobs,
|
|
v_pending_jobs,
|
|
v_running_jobs,
|
|
v_completed_jobs,
|
|
v_failed_jobs
|
|
FROM child_jobs
|
|
WHERE batch_id = v_batch_id;
|
|
|
|
-- Calculate weighted progress
|
|
SELECT COALESCE(SUM(progress_pct * model_weight), 0.0)
|
|
INTO v_weighted_progress
|
|
FROM child_jobs
|
|
WHERE batch_id = v_batch_id;
|
|
|
|
-- Determine batch status
|
|
IF v_failed_jobs > 0 AND v_running_jobs = 0 AND v_pending_jobs = 0 THEN
|
|
v_new_status := 'Failed';
|
|
ELSIF v_completed_jobs = v_total_jobs AND v_total_jobs > 0 THEN
|
|
v_new_status := 'Completed';
|
|
ELSIF v_running_jobs > 0 THEN
|
|
v_new_status := 'Running';
|
|
ELSE
|
|
v_new_status := 'Pending';
|
|
END IF;
|
|
|
|
-- Update batch job
|
|
UPDATE batch_jobs
|
|
SET
|
|
total_jobs = v_total_jobs,
|
|
pending_jobs = v_pending_jobs,
|
|
running_jobs = v_running_jobs,
|
|
completed_jobs = v_completed_jobs,
|
|
failed_jobs = v_failed_jobs,
|
|
overall_progress = v_weighted_progress,
|
|
status = v_new_status,
|
|
started_at = CASE
|
|
WHEN started_at IS NULL AND v_running_jobs > 0 THEN NOW()
|
|
ELSE started_at
|
|
END,
|
|
completed_at = CASE
|
|
WHEN v_new_status IN ('Completed', 'Failed') THEN NOW()
|
|
ELSE NULL
|
|
END
|
|
WHERE id = v_batch_id;
|
|
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- Trigger to update batch aggregates on child job changes
|
|
CREATE TRIGGER tg_child_jobs_update_batch_aggregates
|
|
AFTER INSERT OR UPDATE OR DELETE ON child_jobs
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION update_batch_job_aggregates();
|
|
|
|
-- ================================================================================================
|
|
-- ANALYTICAL VIEWS FOR REPORTING
|
|
-- ================================================================================================
|
|
|
|
-- View for active batch jobs
|
|
CREATE OR REPLACE VIEW v_active_batch_jobs AS
|
|
SELECT
|
|
b.id,
|
|
b.name,
|
|
b.description,
|
|
b.status,
|
|
b.total_jobs,
|
|
b.pending_jobs,
|
|
b.running_jobs,
|
|
b.completed_jobs,
|
|
b.failed_jobs,
|
|
b.overall_progress,
|
|
b.created_at,
|
|
b.started_at,
|
|
b.completed_at,
|
|
EXTRACT(EPOCH FROM (COALESCE(b.completed_at, NOW()) - b.created_at)) as duration_seconds
|
|
FROM batch_jobs b
|
|
WHERE b.status IN ('Pending', 'Running')
|
|
ORDER BY b.created_at DESC;
|
|
|
|
COMMENT ON VIEW v_active_batch_jobs IS 'Active batch jobs (Pending or Running) with progress metrics';
|
|
|
|
-- View for batch job details with child job breakdown
|
|
CREATE OR REPLACE VIEW v_batch_job_details AS
|
|
SELECT
|
|
b.id as batch_id,
|
|
b.name as batch_name,
|
|
b.status as batch_status,
|
|
b.overall_progress,
|
|
c.id as child_job_id,
|
|
c.model_type,
|
|
c.model_weight,
|
|
c.status as child_status,
|
|
c.progress_pct,
|
|
c.current_epoch,
|
|
c.total_epochs,
|
|
c.error_message
|
|
FROM batch_jobs b
|
|
LEFT JOIN child_jobs c ON b.id = c.batch_id
|
|
ORDER BY b.created_at DESC, c.model_type;
|
|
|
|
COMMENT ON VIEW v_batch_job_details IS 'Detailed view of batch jobs with all child jobs';
|
|
|
|
-- ================================================================================================
|
|
-- FINAL VALIDATION
|
|
-- ================================================================================================
|
|
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM information_schema.tables
|
|
WHERE table_name = 'batch_jobs'
|
|
) THEN
|
|
RAISE EXCEPTION 'Migration 046 failed: batch_jobs table not created';
|
|
END IF;
|
|
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM information_schema.tables
|
|
WHERE table_name = 'child_jobs'
|
|
) THEN
|
|
RAISE EXCEPTION 'Migration 046 failed: child_jobs table not created';
|
|
END IF;
|
|
|
|
RAISE NOTICE 'Migration 046 completed successfully: Batch job tracking schema created';
|
|
END $$;
|