-- Global stats CREATE MATERIALIZED VIEW stats_1m_all WITH (timescaledb.continuous) AS SELECT time_bucket('1 minute', start_time) AS bucket, COUNT(*) AS total_count, COUNT(*) FILTER (WHERE status = 'FAILED') AS failed_count, COUNT(*) FILTER (WHERE status = 'RUNNING') AS running_count, SUM(duration_ms) AS duration_sum, MAX(duration_ms) AS duration_max, approx_percentile(0.99, percentile_agg(duration_ms::DOUBLE PRECISION)) AS p99_duration FROM executions WHERE status IS NOT NULL GROUP BY bucket; SELECT add_continuous_aggregate_policy('stats_1m_all', start_offset => INTERVAL '1 hour', end_offset => INTERVAL '1 minute', schedule_interval => INTERVAL '1 minute'); -- Per-application stats CREATE MATERIALIZED VIEW stats_1m_app WITH (timescaledb.continuous) AS SELECT time_bucket('1 minute', start_time) AS bucket, group_name, COUNT(*) AS total_count, COUNT(*) FILTER (WHERE status = 'FAILED') AS failed_count, COUNT(*) FILTER (WHERE status = 'RUNNING') AS running_count, SUM(duration_ms) AS duration_sum, MAX(duration_ms) AS duration_max, approx_percentile(0.99, percentile_agg(duration_ms::DOUBLE PRECISION)) AS p99_duration FROM executions WHERE status IS NOT NULL GROUP BY bucket, group_name; SELECT add_continuous_aggregate_policy('stats_1m_app', start_offset => INTERVAL '1 hour', end_offset => INTERVAL '1 minute', schedule_interval => INTERVAL '1 minute'); -- Per-route stats CREATE MATERIALIZED VIEW stats_1m_route WITH (timescaledb.continuous) AS SELECT time_bucket('1 minute', start_time) AS bucket, group_name, route_id, COUNT(*) AS total_count, COUNT(*) FILTER (WHERE status = 'FAILED') AS failed_count, COUNT(*) FILTER (WHERE status = 'RUNNING') AS running_count, SUM(duration_ms) AS duration_sum, MAX(duration_ms) AS duration_max, approx_percentile(0.99, percentile_agg(duration_ms::DOUBLE PRECISION)) AS p99_duration FROM executions WHERE status IS NOT NULL GROUP BY bucket, group_name, route_id; SELECT add_continuous_aggregate_policy('stats_1m_route', start_offset => INTERVAL '1 hour', end_offset => INTERVAL '1 minute', schedule_interval => INTERVAL '1 minute'); -- Per-processor stats (uses denormalized group_name/route_id on processor_executions) CREATE MATERIALIZED VIEW stats_1m_processor WITH (timescaledb.continuous) AS SELECT time_bucket('1 minute', start_time) AS bucket, group_name, route_id, processor_type, COUNT(*) AS total_count, COUNT(*) FILTER (WHERE status = 'FAILED') AS failed_count, SUM(duration_ms) AS duration_sum, MAX(duration_ms) AS duration_max, approx_percentile(0.99, percentile_agg(duration_ms::DOUBLE PRECISION)) AS p99_duration FROM processor_executions GROUP BY bucket, group_name, route_id, processor_type; SELECT add_continuous_aggregate_policy('stats_1m_processor', start_offset => INTERVAL '1 hour', end_offset => INTERVAL '1 minute', schedule_interval => INTERVAL '1 minute');