@@ -92,7 +92,113 @@ SELECT
9292FROM trigger_dev .queue_metrics_raw_v1
9393GROUP BY organization_id, project_id, environment_id, queue_name, bucket_start;
9494
95+ -- (4) Env-level 1m rollup (no queue dimension) for header tiles/saturation charts.
96+ -- No counter deltas on purpose: cross-queue deltaSumTimestamp state merges mix unrelated
97+ -- odometers (env totals must GROUP BY queue then sum). TDigest because an env-level
98+ -- reservoir absorbs every sample in the environment.
99+ CREATE TABLE IF NOT EXISTS trigger_dev .env_metrics_1m_v1
100+ (
101+ organization_id LowCardinality(String),
102+ project_id LowCardinality(String),
103+ environment_id String CODEC(ZSTD(1 )),
104+ bucket_start DateTime CODEC(Delta(4 ), ZSTD(1 )),
105+
106+ max_env_queued SimpleAggregateFunction(max, UInt32),
107+ max_env_running SimpleAggregateFunction(max, UInt32),
108+ max_env_limit SimpleAggregateFunction(max, UInt32),
109+ throttled_count SimpleAggregateFunction(sum, UInt64),
110+
111+ wait_ms_sum SimpleAggregateFunction(sum, UInt64),
112+ wait_ms_count SimpleAggregateFunction(sum, UInt64),
113+ wait_quantiles AggregateFunction(quantilesTDigest(0 .5 , 0 .9 , 0 .95 , 0 .99 ), UInt32)
114+ )
115+ ENGINE = AggregatingMergeTree()
116+ PARTITION BY toDate(bucket_start)
117+ ORDER BY (organization_id, project_id, environment_id, bucket_start)
118+ TTL bucket_start + INTERVAL 30 DAY
119+ SETTINGS ttl_only_drop_parts = 1 ;
120+
121+ -- (5) MV: raw -> env rollup.
122+ CREATE MATERIALIZED VIEW IF NOT EXISTS trigger_dev .env_metrics_1m_mv_v1
123+ TO trigger_dev .env_metrics_1m_v1 AS
124+ SELECT
125+ organization_id, project_id, environment_id,
126+ toStartOfInterval(event_time, INTERVAL 1 MINUTE) AS bucket_start,
127+ max (env_queued) AS max_env_queued,
128+ max (env_running) AS max_env_running,
129+ max (env_limit) AS max_env_limit,
130+ sum (throttled) AS throttled_count,
131+ sumIf(wait_ms, op = ' started' ) AS wait_ms_sum,
132+ countIf(op = ' started' AND wait_ms > 0 ) AS wait_ms_count,
133+ quantilesTDigestStateIf(0 .5 , 0 .9 , 0 .95 , 0 .99 )(wait_ms, op = ' started' AND wait_ms > 0 ) AS wait_quantiles
134+ FROM trigger_dev .queue_metrics_raw_v1
135+ GROUP BY organization_id, project_id, environment_id, bucket_start;
136+
137+ -- (6) Per-queue 5m rollup, exact column mirror of queue_metrics_v1, for ranking and
138+ -- env-wide GROUP BY queue reads at long ranges.
139+ CREATE TABLE IF NOT EXISTS trigger_dev .queue_metrics_5m_v1
140+ (
141+ organization_id LowCardinality(String),
142+ project_id LowCardinality(String),
143+ environment_id String CODEC(ZSTD(1 )),
144+ queue_name String CODEC(ZSTD(1 )),
145+ bucket_start DateTime CODEC(Delta(4 ), ZSTD(1 )),
146+
147+ enqueue_delta AggregateFunction(deltaSumTimestamp, UInt64, UInt64),
148+ started_delta AggregateFunction(deltaSumTimestamp, UInt64, UInt64),
149+ ack_delta AggregateFunction(deltaSumTimestamp, UInt64, UInt64),
150+ nack_delta AggregateFunction(deltaSumTimestamp, UInt64, UInt64),
151+ dlq_delta AggregateFunction(deltaSumTimestamp, UInt64, UInt64),
152+ throttled_count SimpleAggregateFunction(sum, UInt64),
153+
154+ max_queued SimpleAggregateFunction(max, UInt32),
155+ max_running SimpleAggregateFunction(max, UInt32),
156+ max_limit SimpleAggregateFunction(max, UInt32),
157+ max_env_queued SimpleAggregateFunction(max, UInt32),
158+ max_env_running SimpleAggregateFunction(max, UInt32),
159+ max_env_limit SimpleAggregateFunction(max, UInt32),
160+
161+ wait_ms_sum SimpleAggregateFunction(sum, UInt64),
162+ wait_ms_count SimpleAggregateFunction(sum, UInt64),
163+ wait_quantiles AggregateFunction(quantiles(0 .5 , 0 .9 , 0 .95 , 0 .99 ), UInt32)
164+ )
165+ ENGINE = AggregatingMergeTree()
166+ PARTITION BY toDate(bucket_start)
167+ ORDER BY (organization_id, project_id, environment_id, queue_name, bucket_start)
168+ TTL bucket_start + INTERVAL 30 DAY
169+ SETTINGS ttl_only_drop_parts = 1 ;
170+
171+ -- (7) MV: raw -> 5m rollup. MUST read raw, never cascade off queue_metrics_v1 with
172+ -- -MergeState: MV GROUP BY merges states in hash order, and out-of-time-order
173+ -- deltaSumTimestamp merges double-count bridging spans (verified 3x inflation).
174+ CREATE MATERIALIZED VIEW IF NOT EXISTS trigger_dev .queue_metrics_5m_mv_v1
175+ TO trigger_dev .queue_metrics_5m_v1 AS
176+ SELECT
177+ organization_id, project_id, environment_id, queue_name,
178+ toStartOfInterval(event_time, INTERVAL 5 MINUTE) AS bucket_start,
179+ deltaSumTimestampStateIf(cumulative, order_key, op = ' enqueue' ) AS enqueue_delta,
180+ deltaSumTimestampStateIf(cumulative, order_key, op = ' started' ) AS started_delta,
181+ deltaSumTimestampStateIf(cumulative, order_key, op = ' ack' ) AS ack_delta,
182+ deltaSumTimestampStateIf(cumulative, order_key, op = ' nack' ) AS nack_delta,
183+ deltaSumTimestampStateIf(cumulative, order_key, op = ' dlq' ) AS dlq_delta,
184+ sum (throttled) AS throttled_count,
185+ max (queued) AS max_queued,
186+ max (running) AS max_running,
187+ max (queue_limit) AS max_limit,
188+ max (env_queued) AS max_env_queued,
189+ max (env_running) AS max_env_running,
190+ max (env_limit) AS max_env_limit,
191+ sumIf(wait_ms, op = ' started' ) AS wait_ms_sum,
192+ countIf(op = ' started' AND wait_ms > 0 ) AS wait_ms_count,
193+ quantilesStateIf(0 .5 , 0 .9 , 0 .95 , 0 .99 )(wait_ms, op = ' started' AND wait_ms > 0 ) AS wait_quantiles
194+ FROM trigger_dev .queue_metrics_raw_v1
195+ GROUP BY organization_id, project_id, environment_id, queue_name, bucket_start;
196+
95197-- +goose Down
198+ DROP VIEW IF EXISTS trigger_dev .queue_metrics_5m_mv_v1 ;
199+ DROP TABLE IF EXISTS trigger_dev .queue_metrics_5m_v1 ;
200+ DROP VIEW IF EXISTS trigger_dev .env_metrics_1m_mv_v1 ;
201+ DROP TABLE IF EXISTS trigger_dev .env_metrics_1m_v1 ;
96202DROP VIEW IF EXISTS trigger_dev .queue_metrics_mv_v1 ;
97203DROP TABLE IF EXISTS trigger_dev .queue_metrics_v1 ;
98204DROP TABLE IF EXISTS trigger_dev .queue_metrics_raw_v1 ;
0 commit comments