Merge pull request #5 from ualsweb/claude/analyze-orchestration-models-011CUpqMMaHG5AP1Sm3Bnj1K
Create consolidated initial schema migration for orchestration service
This commit is contained in:
232
services/orchestrator/migrations/MIGRATION_GUIDE.md
Normal file
232
services/orchestrator/migrations/MIGRATION_GUIDE.md
Normal file
@@ -0,0 +1,232 @@
|
||||
# Migration Guide - Consolidated Schema
|
||||
|
||||
## Overview
|
||||
|
||||
This guide explains how to use the new consolidated initial schema migration for the Orchestration Service.
|
||||
|
||||
## Background
|
||||
|
||||
The orchestration service schema was previously split across two migration files:
|
||||
1. `20251029_1700_add_orchestration_runs.py` - Initial table creation
|
||||
2. `20251105_add_ai_insights_tracking.py` - AI insights fields addition
|
||||
|
||||
These have been consolidated into a single, well-structured initial schema file: `001_initial_schema.py`
|
||||
|
||||
## For New Deployments
|
||||
|
||||
If you're deploying the orchestration service for the first time:
|
||||
|
||||
1. **Use the consolidated migration:**
|
||||
```bash
|
||||
cd services/orchestrator
|
||||
alembic upgrade head
|
||||
```
|
||||
|
||||
2. **The migration will create:**
|
||||
- `orchestration_runs` table with all columns
|
||||
- `orchestrationstatus` enum type
|
||||
- All 15 indexes for optimal query performance
|
||||
|
||||
3. **Verify the migration:**
|
||||
```bash
|
||||
alembic current
|
||||
# Should show: 001_initial_schema (head)
|
||||
```
|
||||
|
||||
## For Existing Deployments
|
||||
|
||||
If your database already has the orchestration schema from the old migrations:
|
||||
|
||||
### Option 1: Keep Existing Migration History (Recommended)
|
||||
|
||||
**Do nothing.** Your existing migrations are functionally equivalent to the consolidated version. The schema structure is identical.
|
||||
|
||||
- Your alembic_version table will show: `20251105_add_ai_insights`
|
||||
- The new consolidated migration is for future deployments
|
||||
- No action needed - your database is up to date
|
||||
|
||||
### Option 2: Reset Migration History (For Clean State)
|
||||
|
||||
Only do this if you want a clean migration history and can afford downtime:
|
||||
|
||||
1. **Backup your database:**
|
||||
```bash
|
||||
pg_dump -h localhost -U user orchestrator_db > backup.sql
|
||||
```
|
||||
|
||||
2. **Drop and recreate schema:**
|
||||
```bash
|
||||
# In PostgreSQL
|
||||
DROP SCHEMA public CASCADE;
|
||||
CREATE SCHEMA public;
|
||||
```
|
||||
|
||||
3. **Apply consolidated migration:**
|
||||
```bash
|
||||
cd services/orchestrator
|
||||
alembic upgrade head
|
||||
```
|
||||
|
||||
4. **Restore data (if needed):**
|
||||
```bash
|
||||
psql -h localhost -U user orchestrator_db < backup_data_only.sql
|
||||
```
|
||||
|
||||
⚠️ **Warning:** This approach requires downtime and careful data backup/restore.
|
||||
|
||||
## Checking Your Current Migration Status
|
||||
|
||||
### Check Alembic version:
|
||||
```bash
|
||||
cd services/orchestrator
|
||||
alembic current
|
||||
```
|
||||
|
||||
### Check applied migrations:
|
||||
```bash
|
||||
alembic history
|
||||
```
|
||||
|
||||
### Verify table structure:
|
||||
```sql
|
||||
-- Check if table exists
|
||||
SELECT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'orchestration_runs'
|
||||
);
|
||||
|
||||
-- Check column count
|
||||
SELECT COUNT(*) FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'orchestration_runs';
|
||||
-- Should return 47 columns
|
||||
|
||||
-- Check indexes
|
||||
SELECT indexname FROM pg_indexes
|
||||
WHERE tablename = 'orchestration_runs';
|
||||
-- Should return 15 indexes
|
||||
```
|
||||
|
||||
## Migration File Comparison
|
||||
|
||||
### Old Migration Chain
|
||||
```
|
||||
None → 20251029_1700 → 20251105_add_ai_insights
|
||||
```
|
||||
|
||||
### New Consolidated Migration
|
||||
```
|
||||
None → 001_initial_schema
|
||||
```
|
||||
|
||||
Both result in the exact same database schema, but the new version is:
|
||||
- ✅ Better organized and documented
|
||||
- ✅ Easier to understand and maintain
|
||||
- ✅ Fixes revision ID inconsistencies
|
||||
- ✅ Properly categorizes fields
|
||||
- ✅ Eliminates duplicate index definitions
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Issue: "relation already exists"
|
||||
**Cause:** Database already has the schema from old migrations.
|
||||
|
||||
**Solution:**
|
||||
- For existing deployments, no action needed
|
||||
- For fresh start, see "Option 2: Reset Migration History" above
|
||||
|
||||
### Issue: "enum type already exists"
|
||||
**Cause:** The orchestrationstatus enum was created by old migration.
|
||||
|
||||
**Solution:**
|
||||
- The migration uses `create_type=False` and `checkfirst=True` to handle this
|
||||
- Should not be an issue in practice
|
||||
|
||||
### Issue: "duplicate key value violates unique constraint on alembic_version"
|
||||
**Cause:** Trying to apply new migration on database with old migrations.
|
||||
|
||||
**Solution:**
|
||||
- Don't apply the new migration on existing databases
|
||||
- The old migrations already provide the same schema
|
||||
|
||||
## Deprecation Notice
|
||||
|
||||
### Files Superseded (Do Not Delete Yet)
|
||||
|
||||
The following migration files are superseded but kept for reference:
|
||||
- `20251029_1700_add_orchestration_runs.py`
|
||||
- `20251105_add_ai_insights_tracking.py`
|
||||
|
||||
**Why keep them?**
|
||||
- Existing deployments reference these migrations
|
||||
- Provides migration history for troubleshooting
|
||||
- Can be removed in future major version
|
||||
|
||||
### Future Cleanup
|
||||
|
||||
In a future major version (e.g., v2.0.0), after all deployments have migrated:
|
||||
1. Archive old migration files to `migrations/archive/`
|
||||
2. Update documentation to reference only consolidated schema
|
||||
3. Clean up alembic version history
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always backup before migrations:**
|
||||
```bash
|
||||
pg_dump -Fc -h localhost -U user orchestrator_db > backup_$(date +%Y%m%d).dump
|
||||
```
|
||||
|
||||
2. **Test migrations in staging first:**
|
||||
- Never run migrations directly in production
|
||||
- Verify schema changes in staging environment
|
||||
- Check application compatibility
|
||||
|
||||
3. **Monitor migration performance:**
|
||||
- Initial migration should complete in < 1 second for empty database
|
||||
- Index creation time scales with data volume
|
||||
|
||||
4. **Use version control:**
|
||||
- All migration files are in git
|
||||
- Never modify existing migration files
|
||||
- Create new migrations for schema changes
|
||||
|
||||
## Getting Help
|
||||
|
||||
If you encounter issues with migrations:
|
||||
|
||||
1. Check migration status: `alembic current`
|
||||
2. Review migration history: `alembic history`
|
||||
3. Check database schema: See SQL queries in "Checking Your Current Migration Status" section
|
||||
4. Review logs: Check alembic output for error details
|
||||
5. Consult SCHEMA_DOCUMENTATION.md for expected schema structure
|
||||
|
||||
## Next Steps
|
||||
|
||||
After successfully applying migrations:
|
||||
|
||||
1. **Verify application startup:**
|
||||
```bash
|
||||
docker-compose up orchestrator
|
||||
```
|
||||
|
||||
2. **Run health checks:**
|
||||
```bash
|
||||
curl http://localhost:8000/health
|
||||
```
|
||||
|
||||
3. **Test basic operations:**
|
||||
- Create a test orchestration run
|
||||
- Query run status
|
||||
- Verify data persistence
|
||||
|
||||
4. **Monitor logs:**
|
||||
```bash
|
||||
docker-compose logs -f orchestrator
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- `SCHEMA_DOCUMENTATION.md` - Complete schema reference
|
||||
- `001_initial_schema.py` - Consolidated migration file
|
||||
- `../../README.md` - Orchestration service overview
|
||||
295
services/orchestrator/migrations/SCHEMA_DOCUMENTATION.md
Normal file
295
services/orchestrator/migrations/SCHEMA_DOCUMENTATION.md
Normal file
@@ -0,0 +1,295 @@
|
||||
# Orchestration Service Database Schema
|
||||
|
||||
## Overview
|
||||
|
||||
This document describes the database schema for the Orchestration Service, which tracks and manages the execution of orchestration workflows across the bakery system.
|
||||
|
||||
## Schema Version History
|
||||
|
||||
### Initial Schema (001_initial_schema)
|
||||
|
||||
This is the consolidated initial schema that includes all tables, columns, indexes, and constraints from the original fragmented migrations.
|
||||
|
||||
**Consolidated from:**
|
||||
- `20251029_1700_add_orchestration_runs.py` - Base orchestration_runs table
|
||||
- `20251105_add_ai_insights_tracking.py` - AI insights tracking additions
|
||||
|
||||
## Tables
|
||||
|
||||
### orchestration_runs
|
||||
|
||||
The main audit trail table for orchestration executions. This table tracks the entire lifecycle of an orchestration run, including all workflow steps, results, and performance metrics.
|
||||
|
||||
#### Columns
|
||||
|
||||
##### Primary Identification
|
||||
| Column | Type | Nullable | Description |
|
||||
|--------|------|----------|-------------|
|
||||
| `id` | UUID | No | Primary key, auto-generated UUID |
|
||||
| `run_number` | VARCHAR(50) | No | Unique human-readable run identifier (indexed, unique) |
|
||||
|
||||
##### Run Details
|
||||
| Column | Type | Nullable | Default | Description |
|
||||
|--------|------|----------|---------|-------------|
|
||||
| `tenant_id` | UUID | No | - | Tenant/organization identifier (indexed) |
|
||||
| `status` | ENUM | No | 'pending' | Current run status (indexed) |
|
||||
| `run_type` | VARCHAR(50) | No | 'scheduled' | Type of run: scheduled, manual, test (indexed) |
|
||||
| `priority` | VARCHAR(20) | No | 'normal' | Run priority: normal, high, critical |
|
||||
|
||||
##### Timing
|
||||
| Column | Type | Nullable | Default | Description |
|
||||
|--------|------|----------|---------|-------------|
|
||||
| `started_at` | TIMESTAMP | No | now() | When the run started (indexed) |
|
||||
| `completed_at` | TIMESTAMP | Yes | NULL | When the run completed (indexed) |
|
||||
| `duration_seconds` | INTEGER | Yes | NULL | Total duration in seconds |
|
||||
|
||||
##### Step Tracking - Forecasting
|
||||
| Column | Type | Nullable | Description |
|
||||
|--------|------|----------|-------------|
|
||||
| `forecasting_started_at` | TIMESTAMP | Yes | When forecasting step started |
|
||||
| `forecasting_completed_at` | TIMESTAMP | Yes | When forecasting step completed |
|
||||
| `forecasting_status` | VARCHAR(20) | Yes | Status: success, failed, skipped |
|
||||
| `forecasting_error` | TEXT | Yes | Error message if failed |
|
||||
|
||||
##### Step Tracking - Production
|
||||
| Column | Type | Nullable | Description |
|
||||
|--------|------|----------|-------------|
|
||||
| `production_started_at` | TIMESTAMP | Yes | When production step started |
|
||||
| `production_completed_at` | TIMESTAMP | Yes | When production step completed |
|
||||
| `production_status` | VARCHAR(20) | Yes | Status: success, failed, skipped |
|
||||
| `production_error` | TEXT | Yes | Error message if failed |
|
||||
|
||||
##### Step Tracking - Procurement
|
||||
| Column | Type | Nullable | Description |
|
||||
|--------|------|----------|-------------|
|
||||
| `procurement_started_at` | TIMESTAMP | Yes | When procurement step started |
|
||||
| `procurement_completed_at` | TIMESTAMP | Yes | When procurement step completed |
|
||||
| `procurement_status` | VARCHAR(20) | Yes | Status: success, failed, skipped |
|
||||
| `procurement_error` | TEXT | Yes | Error message if failed |
|
||||
|
||||
##### Step Tracking - Notifications
|
||||
| Column | Type | Nullable | Description |
|
||||
|--------|------|----------|-------------|
|
||||
| `notification_started_at` | TIMESTAMP | Yes | When notification step started |
|
||||
| `notification_completed_at` | TIMESTAMP | Yes | When notification step completed |
|
||||
| `notification_status` | VARCHAR(20) | Yes | Status: success, failed, skipped |
|
||||
| `notification_error` | TEXT | Yes | Error message if failed |
|
||||
|
||||
##### Step Tracking - AI Insights
|
||||
| Column | Type | Nullable | Default | Description |
|
||||
|--------|------|----------|---------|-------------|
|
||||
| `ai_insights_started_at` | TIMESTAMP | Yes | NULL | When AI insights step started |
|
||||
| `ai_insights_completed_at` | TIMESTAMP | Yes | NULL | When AI insights step completed |
|
||||
| `ai_insights_status` | VARCHAR(20) | Yes | NULL | Status: success, failed, skipped |
|
||||
| `ai_insights_error` | TEXT | Yes | NULL | Error message if failed |
|
||||
| `ai_insights_generated` | INTEGER | No | 0 | Number of AI insights generated |
|
||||
| `ai_insights_posted` | INTEGER | No | 0 | Number of AI insights posted |
|
||||
|
||||
##### Results Summary
|
||||
| Column | Type | Nullable | Default | Description |
|
||||
|--------|------|----------|---------|-------------|
|
||||
| `forecasts_generated` | INTEGER | No | 0 | Total forecasts generated |
|
||||
| `production_batches_created` | INTEGER | No | 0 | Total production batches created |
|
||||
| `procurement_plans_created` | INTEGER | No | 0 | Total procurement plans created |
|
||||
| `purchase_orders_created` | INTEGER | No | 0 | Total purchase orders created |
|
||||
| `notifications_sent` | INTEGER | No | 0 | Total notifications sent |
|
||||
|
||||
##### Data Storage
|
||||
| Column | Type | Nullable | Description |
|
||||
|--------|------|----------|-------------|
|
||||
| `forecast_data` | JSONB | Yes | Forecast results for downstream services |
|
||||
| `run_metadata` | JSONB | Yes | Additional run metadata |
|
||||
|
||||
##### Error Handling
|
||||
| Column | Type | Nullable | Default | Description |
|
||||
|--------|------|----------|---------|-------------|
|
||||
| `retry_count` | INTEGER | No | 0 | Number of retry attempts |
|
||||
| `max_retries_reached` | BOOLEAN | No | false | Whether max retries was reached |
|
||||
| `error_message` | TEXT | Yes | NULL | General error message |
|
||||
| `error_details` | JSONB | Yes | NULL | Detailed error information |
|
||||
|
||||
##### External References
|
||||
| Column | Type | Nullable | Description |
|
||||
|--------|------|----------|-------------|
|
||||
| `forecast_id` | UUID | Yes | Reference to forecast record |
|
||||
| `production_schedule_id` | UUID | Yes | Reference to production schedule |
|
||||
| `procurement_plan_id` | UUID | Yes | Reference to procurement plan |
|
||||
|
||||
##### Saga Tracking
|
||||
| Column | Type | Nullable | Default | Description |
|
||||
|--------|------|----------|---------|-------------|
|
||||
| `saga_steps_total` | INTEGER | No | 0 | Total saga steps planned |
|
||||
| `saga_steps_completed` | INTEGER | No | 0 | Saga steps completed |
|
||||
|
||||
##### Audit Fields
|
||||
| Column | Type | Nullable | Default | Description |
|
||||
|--------|------|----------|---------|-------------|
|
||||
| `created_at` | TIMESTAMP | No | now() | Record creation timestamp |
|
||||
| `updated_at` | TIMESTAMP | No | now() | Record last update timestamp (auto-updated) |
|
||||
| `triggered_by` | VARCHAR(100) | Yes | NULL | Who/what triggered the run (indexed) |
|
||||
|
||||
##### Performance Metrics
|
||||
| Column | Type | Nullable | Description |
|
||||
|--------|------|----------|-------------|
|
||||
| `fulfillment_rate` | INTEGER | Yes | Fulfillment rate percentage (0-100, indexed) |
|
||||
| `on_time_delivery_rate` | INTEGER | Yes | On-time delivery rate percentage (0-100, indexed) |
|
||||
| `cost_accuracy` | INTEGER | Yes | Cost accuracy percentage (0-100, indexed) |
|
||||
| `quality_score` | INTEGER | Yes | Quality score (0-100, indexed) |
|
||||
|
||||
#### Indexes
|
||||
|
||||
##### Single Column Indexes
|
||||
- `ix_orchestration_runs_run_number` - UNIQUE index on run_number for fast lookups
|
||||
- `ix_orchestration_runs_tenant_id` - Tenant filtering
|
||||
- `ix_orchestration_runs_status` - Status filtering
|
||||
- `ix_orchestration_runs_started_at` - Temporal queries
|
||||
- `ix_orchestration_runs_completed_at` - Temporal queries
|
||||
- `ix_orchestration_runs_run_type` - Type filtering
|
||||
- `ix_orchestration_runs_trigger` - Trigger source filtering
|
||||
|
||||
##### Composite Indexes (for common query patterns)
|
||||
- `ix_orchestration_runs_tenant_status` - (tenant_id, status) - Tenant's runs by status
|
||||
- `ix_orchestration_runs_tenant_type` - (tenant_id, run_type) - Tenant's runs by type
|
||||
- `ix_orchestration_runs_tenant_started` - (tenant_id, started_at) - Tenant's runs by date
|
||||
- `ix_orchestration_runs_status_started` - (status, started_at) - Global runs by status and date
|
||||
|
||||
##### Performance Metric Indexes
|
||||
- `ix_orchestration_runs_fulfillment_rate` - Fulfillment rate queries
|
||||
- `ix_orchestration_runs_on_time_delivery_rate` - Delivery performance queries
|
||||
- `ix_orchestration_runs_cost_accuracy` - Cost tracking queries
|
||||
- `ix_orchestration_runs_quality_score` - Quality filtering
|
||||
|
||||
## Enums
|
||||
|
||||
### orchestrationstatus
|
||||
|
||||
Represents the current status of an orchestration run.
|
||||
|
||||
**Values:**
|
||||
- `pending` - Run is queued but not yet started
|
||||
- `running` - Run is currently executing
|
||||
- `completed` - Run completed successfully
|
||||
- `partial_success` - Run completed but some steps failed
|
||||
- `failed` - Run failed to complete
|
||||
- `cancelled` - Run was cancelled
|
||||
|
||||
## Workflow Steps
|
||||
|
||||
The orchestration service coordinates multiple workflow steps in sequence:
|
||||
|
||||
1. **Forecasting** - Generate demand forecasts
|
||||
2. **Production** - Create production schedules
|
||||
3. **Procurement** - Generate procurement plans and purchase orders
|
||||
4. **Notifications** - Send notifications to stakeholders
|
||||
5. **AI Insights** - Generate and post AI-driven insights
|
||||
|
||||
Each step tracks:
|
||||
- Start/completion timestamps
|
||||
- Status (success/failed/skipped)
|
||||
- Error messages (if applicable)
|
||||
- Step-specific metrics
|
||||
|
||||
## Data Flow
|
||||
|
||||
```
|
||||
Orchestration Run
|
||||
↓
|
||||
1. Forecasting → forecast_data (JSONB)
|
||||
↓
|
||||
2. Production → production_schedule_id (UUID)
|
||||
↓
|
||||
3. Procurement → procurement_plan_id (UUID)
|
||||
↓
|
||||
4. Notifications → notifications_sent (count)
|
||||
↓
|
||||
5. AI Insights → ai_insights_posted (count)
|
||||
```
|
||||
|
||||
## Query Patterns
|
||||
|
||||
### Common Queries
|
||||
|
||||
1. **Get active runs for a tenant:**
|
||||
```sql
|
||||
SELECT * FROM orchestration_runs
|
||||
WHERE tenant_id = ? AND status IN ('pending', 'running')
|
||||
ORDER BY started_at DESC;
|
||||
```
|
||||
*Uses: ix_orchestration_runs_tenant_status*
|
||||
|
||||
2. **Get run history for a date range:**
|
||||
```sql
|
||||
SELECT * FROM orchestration_runs
|
||||
WHERE tenant_id = ? AND started_at BETWEEN ? AND ?
|
||||
ORDER BY started_at DESC;
|
||||
```
|
||||
*Uses: ix_orchestration_runs_tenant_started*
|
||||
|
||||
3. **Get performance metrics summary:**
|
||||
```sql
|
||||
SELECT AVG(fulfillment_rate), AVG(on_time_delivery_rate),
|
||||
AVG(cost_accuracy), AVG(quality_score)
|
||||
FROM orchestration_runs
|
||||
WHERE tenant_id = ? AND status = 'completed'
|
||||
AND started_at > ?;
|
||||
```
|
||||
*Uses: ix_orchestration_runs_tenant_started + metric indexes*
|
||||
|
||||
4. **Find failed runs needing attention:**
|
||||
```sql
|
||||
SELECT * FROM orchestration_runs
|
||||
WHERE status = 'failed' AND retry_count < 3
|
||||
AND max_retries_reached = false
|
||||
ORDER BY started_at DESC;
|
||||
```
|
||||
*Uses: ix_orchestration_runs_status*
|
||||
|
||||
## Migration Notes
|
||||
|
||||
### Consolidation Changes
|
||||
|
||||
The original schema was split across two migrations:
|
||||
1. Base table with most fields
|
||||
2. AI insights tracking added later
|
||||
|
||||
This consolidation:
|
||||
- ✅ Combines all fields into one initial migration
|
||||
- ✅ Fixes revision ID inconsistencies
|
||||
- ✅ Removes duplicate index definitions
|
||||
- ✅ Organizes fields logically by category
|
||||
- ✅ Adds comprehensive documentation
|
||||
- ✅ Improves maintainability
|
||||
|
||||
### Old Migration Files
|
||||
|
||||
The following files are superseded by `001_initial_schema.py`:
|
||||
- `20251029_1700_add_orchestration_runs.py`
|
||||
- `20251105_add_ai_insights_tracking.py`
|
||||
|
||||
**Important:** If your database was already migrated using the old files, you should not apply the new consolidated migration. The new migration is for fresh deployments or can be used after resetting the migration history.
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always set tenant_id** - Required for multi-tenant isolation
|
||||
2. **Use run_number for user-facing displays** - More readable than UUID
|
||||
3. **Track all step timing** - Helps identify bottlenecks
|
||||
4. **Store detailed errors** - Use error_details JSONB for structured error data
|
||||
5. **Update metrics in real-time** - Keep counts and statuses current
|
||||
6. **Use saga tracking** - Helps monitor overall progress
|
||||
7. **Leverage indexes** - Use composite indexes for multi-column queries
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
- All timestamp columns have indexes for temporal queries
|
||||
- Composite indexes optimize common multi-column filters
|
||||
- JSONB columns (forecast_data, error_details, run_metadata) allow flexible data storage
|
||||
- Performance metric indexes enable fast analytics queries
|
||||
- Unique constraint on run_number prevents duplicates
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Potential schema improvements for future versions:
|
||||
- Add foreign key constraints to external references (if services support it)
|
||||
- Add partition by started_at for very high-volume deployments
|
||||
- Add GIN indexes on JSONB columns for complex queries
|
||||
- Add materialized views for common analytics queries
|
||||
201
services/orchestrator/migrations/versions/001_initial_schema.py
Normal file
201
services/orchestrator/migrations/versions/001_initial_schema.py
Normal file
@@ -0,0 +1,201 @@
|
||||
"""Initial orchestration schema
|
||||
|
||||
Revision ID: 001_initial_schema
|
||||
Revises:
|
||||
Create Date: 2025-11-05 00:00:00.000000
|
||||
|
||||
This is the consolidated initial schema for the orchestration service.
|
||||
It includes all tables, enums, indexes, and constraints needed for the
|
||||
orchestration_runs table and related functionality.
|
||||
|
||||
Tables:
|
||||
- orchestration_runs: Main audit trail for orchestration executions
|
||||
|
||||
Enums:
|
||||
- orchestrationstatus: Status values for orchestration runs
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '001_initial_schema'
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
"""Create initial orchestration schema"""
|
||||
|
||||
# ================================================================
|
||||
# Create Enums
|
||||
# ================================================================
|
||||
|
||||
# Create PostgreSQL enum type for orchestration status
|
||||
orchestrationstatus_enum = postgresql.ENUM(
|
||||
'pending',
|
||||
'running',
|
||||
'completed',
|
||||
'partial_success',
|
||||
'failed',
|
||||
'cancelled',
|
||||
name='orchestrationstatus',
|
||||
create_type=False
|
||||
)
|
||||
orchestrationstatus_enum.create(op.get_bind(), checkfirst=True)
|
||||
|
||||
# ================================================================
|
||||
# Create Tables
|
||||
# ================================================================
|
||||
|
||||
# Create orchestration_runs table
|
||||
op.create_table(
|
||||
'orchestration_runs',
|
||||
|
||||
# Primary identification
|
||||
sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column('run_number', sa.String(length=50), nullable=False),
|
||||
|
||||
# Run details
|
||||
sa.Column('tenant_id', postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column('status', orchestrationstatus_enum, nullable=False, server_default='pending'),
|
||||
sa.Column('run_type', sa.String(length=50), nullable=False, server_default=sa.text("'scheduled'::character varying")),
|
||||
sa.Column('priority', sa.String(length=20), nullable=False, server_default=sa.text("'normal'::character varying")),
|
||||
|
||||
# Timing
|
||||
sa.Column('started_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
|
||||
sa.Column('completed_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('duration_seconds', sa.Integer(), nullable=True),
|
||||
|
||||
# Forecasting step tracking
|
||||
sa.Column('forecasting_started_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('forecasting_completed_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('forecasting_status', sa.String(length=20), nullable=True),
|
||||
sa.Column('forecasting_error', sa.Text(), nullable=True),
|
||||
|
||||
# Production step tracking
|
||||
sa.Column('production_started_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('production_completed_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('production_status', sa.String(length=20), nullable=True),
|
||||
sa.Column('production_error', sa.Text(), nullable=True),
|
||||
|
||||
# Procurement step tracking
|
||||
sa.Column('procurement_started_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('procurement_completed_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('procurement_status', sa.String(length=20), nullable=True),
|
||||
sa.Column('procurement_error', sa.Text(), nullable=True),
|
||||
|
||||
# Notification step tracking
|
||||
sa.Column('notification_started_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('notification_completed_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('notification_status', sa.String(length=20), nullable=True),
|
||||
sa.Column('notification_error', sa.Text(), nullable=True),
|
||||
|
||||
# AI Insights step tracking
|
||||
sa.Column('ai_insights_started_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('ai_insights_completed_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('ai_insights_status', sa.String(length=20), nullable=True),
|
||||
sa.Column('ai_insights_error', sa.Text(), nullable=True),
|
||||
sa.Column('ai_insights_generated', sa.Integer(), nullable=False, server_default=sa.text('0')),
|
||||
sa.Column('ai_insights_posted', sa.Integer(), nullable=False, server_default=sa.text('0')),
|
||||
|
||||
# Results summary
|
||||
sa.Column('forecasts_generated', sa.Integer(), nullable=False, server_default=sa.text('0')),
|
||||
sa.Column('production_batches_created', sa.Integer(), nullable=False, server_default=sa.text('0')),
|
||||
sa.Column('procurement_plans_created', sa.Integer(), nullable=False, server_default=sa.text('0')),
|
||||
sa.Column('purchase_orders_created', sa.Integer(), nullable=False, server_default=sa.text('0')),
|
||||
sa.Column('notifications_sent', sa.Integer(), nullable=False, server_default=sa.text('0')),
|
||||
|
||||
# Forecast data passed between services
|
||||
sa.Column('forecast_data', postgresql.JSONB(astext_type=sa.Text()), nullable=True),
|
||||
|
||||
# Error handling
|
||||
sa.Column('retry_count', sa.Integer(), nullable=False, server_default=sa.text('0')),
|
||||
sa.Column('max_retries_reached', sa.Boolean(), nullable=False, server_default=sa.text('false')),
|
||||
sa.Column('error_message', sa.Text(), nullable=True),
|
||||
sa.Column('error_details', postgresql.JSONB(astext_type=sa.Text()), nullable=True),
|
||||
|
||||
# External references
|
||||
sa.Column('forecast_id', postgresql.UUID(as_uuid=True), nullable=True),
|
||||
sa.Column('production_schedule_id', postgresql.UUID(as_uuid=True), nullable=True),
|
||||
sa.Column('procurement_plan_id', postgresql.UUID(as_uuid=True), nullable=True),
|
||||
|
||||
# Saga tracking
|
||||
sa.Column('saga_steps_total', sa.Integer(), nullable=False, server_default=sa.text('0')),
|
||||
sa.Column('saga_steps_completed', sa.Integer(), nullable=False, server_default=sa.text('0')),
|
||||
|
||||
# Audit fields
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), onupdate=sa.text('now()'), nullable=False),
|
||||
sa.Column('triggered_by', sa.String(length=100), nullable=True),
|
||||
|
||||
# Performance metrics
|
||||
sa.Column('fulfillment_rate', sa.Integer(), nullable=True),
|
||||
sa.Column('on_time_delivery_rate', sa.Integer(), nullable=True),
|
||||
sa.Column('cost_accuracy', sa.Integer(), nullable=True),
|
||||
sa.Column('quality_score', sa.Integer(), nullable=True),
|
||||
|
||||
# Metadata
|
||||
sa.Column('run_metadata', postgresql.JSONB(astext_type=sa.Text()), nullable=True),
|
||||
|
||||
# Constraints
|
||||
sa.PrimaryKeyConstraint('id', name=op.f('pk_orchestration_runs'))
|
||||
)
|
||||
|
||||
# ================================================================
|
||||
# Create Indexes
|
||||
# ================================================================
|
||||
|
||||
# Primary lookup indexes
|
||||
op.create_index('ix_orchestration_runs_run_number', 'orchestration_runs', ['run_number'], unique=True)
|
||||
op.create_index('ix_orchestration_runs_tenant_id', 'orchestration_runs', ['tenant_id'], unique=False)
|
||||
op.create_index('ix_orchestration_runs_status', 'orchestration_runs', ['status'], unique=False)
|
||||
|
||||
# Temporal indexes
|
||||
op.create_index('ix_orchestration_runs_started_at', 'orchestration_runs', ['started_at'], unique=False)
|
||||
op.create_index('ix_orchestration_runs_completed_at', 'orchestration_runs', ['completed_at'], unique=False)
|
||||
|
||||
# Classification indexes
|
||||
op.create_index('ix_orchestration_runs_run_type', 'orchestration_runs', ['run_type'], unique=False)
|
||||
op.create_index('ix_orchestration_runs_trigger', 'orchestration_runs', ['triggered_by'], unique=False)
|
||||
|
||||
# Composite indexes for common queries
|
||||
op.create_index('ix_orchestration_runs_tenant_status', 'orchestration_runs', ['tenant_id', 'status'], unique=False)
|
||||
op.create_index('ix_orchestration_runs_tenant_type', 'orchestration_runs', ['tenant_id', 'run_type'], unique=False)
|
||||
op.create_index('ix_orchestration_runs_tenant_started', 'orchestration_runs', ['tenant_id', 'started_at'], unique=False)
|
||||
op.create_index('ix_orchestration_runs_status_started', 'orchestration_runs', ['status', 'started_at'], unique=False)
|
||||
|
||||
# Performance metric indexes
|
||||
op.create_index('ix_orchestration_runs_fulfillment_rate', 'orchestration_runs', ['fulfillment_rate'], unique=False)
|
||||
op.create_index('ix_orchestration_runs_on_time_delivery_rate', 'orchestration_runs', ['on_time_delivery_rate'], unique=False)
|
||||
op.create_index('ix_orchestration_runs_cost_accuracy', 'orchestration_runs', ['cost_accuracy'], unique=False)
|
||||
op.create_index('ix_orchestration_runs_quality_score', 'orchestration_runs', ['quality_score'], unique=False)
|
||||
|
||||
|
||||
def downgrade():
|
||||
"""Drop orchestration schema"""
|
||||
|
||||
# Drop indexes
|
||||
op.drop_index('ix_orchestration_runs_quality_score', table_name='orchestration_runs')
|
||||
op.drop_index('ix_orchestration_runs_cost_accuracy', table_name='orchestration_runs')
|
||||
op.drop_index('ix_orchestration_runs_on_time_delivery_rate', table_name='orchestration_runs')
|
||||
op.drop_index('ix_orchestration_runs_fulfillment_rate', table_name='orchestration_runs')
|
||||
op.drop_index('ix_orchestration_runs_status_started', table_name='orchestration_runs')
|
||||
op.drop_index('ix_orchestration_runs_tenant_started', table_name='orchestration_runs')
|
||||
op.drop_index('ix_orchestration_runs_tenant_type', table_name='orchestration_runs')
|
||||
op.drop_index('ix_orchestration_runs_tenant_status', table_name='orchestration_runs')
|
||||
op.drop_index('ix_orchestration_runs_trigger', table_name='orchestration_runs')
|
||||
op.drop_index('ix_orchestration_runs_run_type', table_name='orchestration_runs')
|
||||
op.drop_index('ix_orchestration_runs_completed_at', table_name='orchestration_runs')
|
||||
op.drop_index('ix_orchestration_runs_started_at', table_name='orchestration_runs')
|
||||
op.drop_index('ix_orchestration_runs_status', table_name='orchestration_runs')
|
||||
op.drop_index('ix_orchestration_runs_tenant_id', table_name='orchestration_runs')
|
||||
op.drop_index('ix_orchestration_runs_run_number', table_name='orchestration_runs')
|
||||
|
||||
# Drop table
|
||||
op.drop_table('orchestration_runs')
|
||||
|
||||
# Drop enum type
|
||||
op.execute("DROP TYPE IF EXISTS orchestrationstatus")
|
||||
Reference in New Issue
Block a user