queen-mq 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/API.md +1226 -0
- package/AUTH.md +2044 -0
- package/LICENSE.md +202 -0
- package/README.md +276 -53
- package/WEBAPP.md +1889 -0
- package/assets/dashboard-01.png +0 -0
- package/assets/queen-logo-blue.svg +210 -0
- package/assets/queen-logo-cyan.svg +210 -0
- package/assets/queen-logo-indigo.svg +210 -0
- package/assets/queen-logo-orange.svg +210 -0
- package/assets/queen-logo-pink.svg +210 -0
- package/assets/queen-logo-purple.svg +210 -0
- package/assets/queen-logo-rose.svg +239 -0
- package/assets/queen-logo.svg +263 -0
- package/examples/batch-processing.js +58 -0
- package/examples/test-dashboard-api.js +200 -0
- package/package.json +4 -2
- package/server.log +1 -0
- package/src/benchmark/consumer.js +207 -0
- package/src/benchmark/consumer_multi.js +216 -0
- package/src/benchmark/producer.js +75 -0
- package/src/benchmark/producer_multi.js +115 -0
- package/src/client/client.js +192 -16
- package/src/client/queenClient.js +5 -0
- package/src/cluster-server.js +242 -0
- package/src/config.js +19 -5
- package/src/database/connection.js +42 -16
- package/src/database/poolManager.js +7 -0
- package/src/database/schema-v2.sql +194 -130
- package/src/managers/queueManagerOptimized.js +823 -933
- package/src/managers/systemEventManager.js +8 -3
- package/src/routes/messages.js +127 -57
- package/src/routes/pop.js +27 -43
- package/src/routes/resources.js +61 -27
- package/src/routes/status.js +1037 -0
- package/src/server.js +308 -272
- package/src/services/evictionService.js +57 -28
- package/src/services/retentionService.js +44 -11
- package/src/test/advanced-pattern-tests.js +5 -5
- package/src/test/bus-mode-tests.js +24 -11
- package/src/test/edge-case-tests.js +12 -5
- package/src/test/enterprise-tests.js +48 -15
- package/src/test/utils.js +1 -1
- package/src/utils/streaming.js +231 -0
- package/src/utils/uuid.js +2 -2
- package/src/websocket/wsServer.js +10 -3
- package/test-keepalive-v2.sh +22 -0
- package/webapp/COLOR_GUIDE.md +118 -0
- package/webapp/README.md +143 -0
- package/webapp/index.html +14 -0
- package/webapp/package-lock.json +3184 -0
- package/webapp/package.json +25 -0
- package/webapp/postcss.config.js +7 -0
- package/webapp/public/assets/queen-logo-blue.svg +210 -0
- package/webapp/public/assets/queen-logo-cyan.svg +210 -0
- package/webapp/public/assets/queen-logo-indigo.svg +210 -0
- package/webapp/public/assets/queen-logo-orange.svg +210 -0
- package/webapp/public/assets/queen-logo-pink.svg +210 -0
- package/webapp/public/assets/queen-logo-purple.svg +210 -0
- package/webapp/public/assets/queen-logo-rose.svg +239 -0
- package/webapp/public/assets/queen-logo.svg +263 -0
- package/webapp/src/App.vue +19 -0
- package/webapp/src/api/analytics.js +10 -0
- package/webapp/src/api/client.js +29 -0
- package/webapp/src/api/consumers.js +52 -0
- package/webapp/src/api/health.js +7 -0
- package/webapp/src/api/messages.js +26 -0
- package/webapp/src/api/queues.js +14 -0
- package/webapp/src/api/resources.js +8 -0
- package/webapp/src/assets/styles/main.css +357 -0
- package/webapp/src/components/analytics/AnalyticsFilters.vue +87 -0
- package/webapp/src/components/analytics/AnalyticsMetrics.vue +57 -0
- package/webapp/src/components/analytics/MessageDistributionChart.vue +111 -0
- package/webapp/src/components/analytics/MessageFlowChart.vue +173 -0
- package/webapp/src/components/analytics/TimeRangeSelector.vue +27 -0
- package/webapp/src/components/analytics/TopQueuesChart.vue +132 -0
- package/webapp/src/components/common/ConfirmDialog.vue +56 -0
- package/webapp/src/components/common/LoadingSpinner.vue +6 -0
- package/webapp/src/components/common/MetricCard.vue +43 -0
- package/webapp/src/components/common/StatusBadge.vue +45 -0
- package/webapp/src/components/dashboard/MessageStatusCard.vue +50 -0
- package/webapp/src/components/dashboard/PerformanceCard.vue +38 -0
- package/webapp/src/components/dashboard/ThroughputChart.vue +182 -0
- package/webapp/src/components/dashboard/TopQueuesTable.vue +53 -0
- package/webapp/src/components/layout/AppLayout.vue +110 -0
- package/webapp/src/components/layout/AppSidebar.vue +304 -0
- package/webapp/src/components/messages/MessageDetailPanel.vue +242 -0
- package/webapp/src/components/messages/MessageFilters.vue +114 -0
- package/webapp/src/components/queue-detail/PartitionList.vue +79 -0
- package/webapp/src/components/queue-detail/PushMessageModal.vue +175 -0
- package/webapp/src/components/queue-detail/QueueConfig.vue +63 -0
- package/webapp/src/components/queue-detail/QueueDetailHeader.vue +53 -0
- package/webapp/src/components/queue-detail/RecentMessages.vue +76 -0
- package/webapp/src/components/queues/CreateQueueModal.vue +193 -0
- package/webapp/src/components/queues/QueueFilters.vue +90 -0
- package/webapp/src/composables/useApi.js +34 -0
- package/webapp/src/composables/useTheme.js +36 -0
- package/webapp/src/main.js +11 -0
- package/webapp/src/router/index.js +42 -0
- package/webapp/src/utils/colors.js +96 -0
- package/webapp/src/utils/formatters.js +49 -0
- package/webapp/src/views/Analytics.vue +377 -0
- package/webapp/src/views/ConsumerGroups.vue +433 -0
- package/webapp/src/views/Dashboard.vue +418 -0
- package/webapp/src/views/Messages.vue +361 -0
- package/webapp/src/views/QueueDetail.vue +582 -0
- package/webapp/src/views/Queues.vue +496 -0
- package/webapp/tailwind.config.js +25 -0
- package/webapp/vite.config.js +10 -0
- package/dashboard/.vscode/extensions.json +0 -3
- package/dashboard/README.md +0 -5
- package/dashboard/index.html +0 -14
- package/dashboard/package-lock.json +0 -1458
- package/dashboard/package.json +0 -25
- package/dashboard/public/vite.svg +0 -1
- package/dashboard/src/App.vue +0 -29
- package/dashboard/src/assets/styles/main.css +0 -908
- package/dashboard/src/assets/vue.svg +0 -1
- package/dashboard/src/components/cards/MetricCard.vue +0 -298
- package/dashboard/src/components/charts/QueueDepthChart.vue +0 -276
- package/dashboard/src/components/charts/QueueLagChart.vue +0 -436
- package/dashboard/src/components/charts/ThroughputChart.vue +0 -302
- package/dashboard/src/components/common/ActivityFeed.vue +0 -251
- package/dashboard/src/components/layout/AppHeader.vue +0 -208
- package/dashboard/src/components/layout/AppLayout.vue +0 -88
- package/dashboard/src/components/layout/AppSidebar.vue +0 -261
- package/dashboard/src/main.js +0 -44
- package/dashboard/src/router.js +0 -54
- package/dashboard/src/services/api.js +0 -187
- package/dashboard/src/services/websocket.js +0 -167
- package/dashboard/src/utils/constants.js +0 -56
- package/dashboard/src/utils/helpers.js +0 -118
- package/dashboard/src/views/Analytics.vue +0 -912
- package/dashboard/src/views/Dashboard.vue +0 -906
- package/dashboard/src/views/Messages.vue +0 -437
- package/dashboard/src/views/QueueDetail.vue +0 -501
- package/dashboard/src/views/Queues.vue +0 -333
- package/dashboard/vite.config.js +0 -30
- package/src/routes/analytics.js +0 -812
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
--
|
|
2
|
-
--
|
|
1
|
+
-- ════════════════════════════════════════════════════════════════
|
|
2
|
+
-- Queen Message Queue Schema V3
|
|
3
|
+
-- Simplified: Merged cursor+lease, removed messages_status
|
|
4
|
+
-- ════════════════════════════════════════════════════════════════
|
|
3
5
|
|
|
4
|
-
-- Create schema only if it doesn't exist (preserves existing data)
|
|
5
6
|
CREATE SCHEMA IF NOT EXISTS queen;
|
|
6
7
|
|
|
7
|
-
--
|
|
8
|
+
-- ────────────────────────────────────────────────────────────────
|
|
9
|
+
-- 1. QUEUES - Top-level configuration
|
|
10
|
+
-- ────────────────────────────────────────────────────────────────
|
|
8
11
|
CREATE TABLE IF NOT EXISTS queen.queues (
|
|
9
12
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
10
13
|
name VARCHAR(255) UNIQUE NOT NULL,
|
|
11
|
-
namespace VARCHAR(255),
|
|
12
|
-
task VARCHAR(255),
|
|
13
|
-
priority INTEGER DEFAULT 0,
|
|
14
|
-
|
|
14
|
+
namespace VARCHAR(255),
|
|
15
|
+
task VARCHAR(255),
|
|
16
|
+
priority INTEGER DEFAULT 0,
|
|
17
|
+
|
|
18
|
+
-- Processing configuration
|
|
15
19
|
lease_time INTEGER DEFAULT 300,
|
|
16
20
|
retry_limit INTEGER DEFAULT 3,
|
|
17
21
|
retry_delay INTEGER DEFAULT 1000,
|
|
@@ -21,16 +25,30 @@ CREATE TABLE IF NOT EXISTS queen.queues (
|
|
|
21
25
|
dlq_after_max_retries BOOLEAN DEFAULT FALSE,
|
|
22
26
|
delayed_processing INTEGER DEFAULT 0,
|
|
23
27
|
window_buffer INTEGER DEFAULT 0,
|
|
28
|
+
|
|
29
|
+
-- Enterprise features
|
|
24
30
|
retention_seconds INTEGER DEFAULT 0,
|
|
25
31
|
completed_retention_seconds INTEGER DEFAULT 0,
|
|
26
32
|
retention_enabled BOOLEAN DEFAULT FALSE,
|
|
27
33
|
encryption_enabled BOOLEAN DEFAULT FALSE,
|
|
28
34
|
max_wait_time_seconds INTEGER DEFAULT 0,
|
|
29
|
-
max_queue_size INTEGER DEFAULT 0,
|
|
35
|
+
max_queue_size INTEGER DEFAULT 0,
|
|
36
|
+
|
|
30
37
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
31
38
|
);
|
|
32
39
|
|
|
33
|
-
--
|
|
40
|
+
-- Indexes for queues
|
|
41
|
+
CREATE INDEX IF NOT EXISTS idx_queues_name ON queen.queues(name);
|
|
42
|
+
CREATE INDEX IF NOT EXISTS idx_queues_priority ON queen.queues(priority DESC);
|
|
43
|
+
CREATE INDEX IF NOT EXISTS idx_queues_namespace ON queen.queues(namespace) WHERE namespace IS NOT NULL;
|
|
44
|
+
CREATE INDEX IF NOT EXISTS idx_queues_task ON queen.queues(task) WHERE task IS NOT NULL;
|
|
45
|
+
CREATE INDEX IF NOT EXISTS idx_queues_namespace_task ON queen.queues(namespace, task)
|
|
46
|
+
WHERE namespace IS NOT NULL AND task IS NOT NULL;
|
|
47
|
+
CREATE INDEX IF NOT EXISTS idx_queues_retention_enabled ON queen.queues(retention_enabled) WHERE retention_enabled = true;
|
|
48
|
+
|
|
49
|
+
-- ────────────────────────────────────────────────────────────────
|
|
50
|
+
-- 2. PARTITIONS - FIFO subdivisions within queues
|
|
51
|
+
-- ────────────────────────────────────────────────────────────────
|
|
34
52
|
CREATE TABLE IF NOT EXISTS queen.partitions (
|
|
35
53
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
36
54
|
queue_id UUID REFERENCES queen.queues(id) ON DELETE CASCADE,
|
|
@@ -40,131 +58,169 @@ CREATE TABLE IF NOT EXISTS queen.partitions (
|
|
|
40
58
|
UNIQUE(queue_id, name)
|
|
41
59
|
);
|
|
42
60
|
|
|
43
|
-
|
|
61
|
+
CREATE INDEX IF NOT EXISTS idx_partitions_queue_name
|
|
62
|
+
ON queen.partitions(queue_id, name);
|
|
63
|
+
|
|
64
|
+
CREATE INDEX IF NOT EXISTS idx_partitions_last_activity
|
|
65
|
+
ON queen.partitions(last_activity);
|
|
66
|
+
|
|
67
|
+
-- ────────────────────────────────────────────────────────────────
|
|
68
|
+
-- 3. MESSAGES - Immutable message data
|
|
69
|
+
-- ────────────────────────────────────────────────────────────────
|
|
44
70
|
CREATE TABLE IF NOT EXISTS queen.messages (
|
|
45
71
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
46
|
-
transaction_id VARCHAR(255) UNIQUE NOT NULL,
|
|
47
|
-
trace_id UUID DEFAULT gen_random_uuid(),
|
|
72
|
+
transaction_id VARCHAR(255) UNIQUE NOT NULL,
|
|
73
|
+
trace_id UUID DEFAULT gen_random_uuid(),
|
|
48
74
|
partition_id UUID REFERENCES queen.partitions(id) ON DELETE CASCADE,
|
|
49
75
|
payload JSONB NOT NULL,
|
|
50
76
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
51
77
|
is_encrypted BOOLEAN DEFAULT FALSE
|
|
52
|
-
-- Removed all status fields - moved to messages_status table
|
|
53
78
|
);
|
|
54
79
|
|
|
55
|
-
--
|
|
56
|
-
CREATE
|
|
80
|
+
-- Indexes for messages (critical for cursor-based queries!)
|
|
81
|
+
CREATE INDEX IF NOT EXISTS idx_messages_partition_created_id
|
|
82
|
+
ON queen.messages(partition_id, created_at, id);
|
|
83
|
+
|
|
84
|
+
CREATE INDEX IF NOT EXISTS idx_messages_transaction_id
|
|
85
|
+
ON queen.messages(transaction_id);
|
|
86
|
+
|
|
87
|
+
CREATE INDEX IF NOT EXISTS idx_messages_trace_id
|
|
88
|
+
ON queen.messages(trace_id);
|
|
89
|
+
|
|
90
|
+
CREATE INDEX IF NOT EXISTS idx_messages_created_at
|
|
91
|
+
ON queen.messages(created_at);
|
|
92
|
+
|
|
93
|
+
-- ────────────────────────────────────────────────────────────────
|
|
94
|
+
-- 4. PARTITION_CONSUMERS - Unified cursor + lease tracking
|
|
95
|
+
-- ────────────────────────────────────────────────────────────────
|
|
96
|
+
CREATE TABLE IF NOT EXISTS queen.partition_consumers (
|
|
57
97
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
58
|
-
|
|
59
|
-
consumer_group VARCHAR(255)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
98
|
+
partition_id UUID REFERENCES queen.partitions(id) ON DELETE CASCADE,
|
|
99
|
+
consumer_group VARCHAR(255) DEFAULT '__QUEUE_MODE__',
|
|
100
|
+
|
|
101
|
+
-- ═══════════════════════════════════════════════════════════
|
|
102
|
+
-- CURSOR STATE (Persistent - consumption progress)
|
|
103
|
+
-- ═══════════════════════════════════════════════════════════
|
|
104
|
+
last_consumed_id UUID DEFAULT '00000000-0000-0000-0000-000000000000',
|
|
105
|
+
last_consumed_created_at TIMESTAMPTZ,
|
|
106
|
+
total_messages_consumed BIGINT DEFAULT 0,
|
|
107
|
+
total_batches_consumed BIGINT DEFAULT 0,
|
|
108
|
+
last_consumed_at TIMESTAMPTZ,
|
|
109
|
+
|
|
110
|
+
-- ═══════════════════════════════════════════════════════════
|
|
111
|
+
-- LEASE STATE (Ephemeral - active processing lock)
|
|
112
|
+
-- ═══════════════════════════════════════════════════════════
|
|
67
113
|
lease_expires_at TIMESTAMPTZ,
|
|
68
|
-
|
|
114
|
+
lease_acquired_at TIMESTAMPTZ,
|
|
115
|
+
message_batch JSONB,
|
|
116
|
+
batch_size INTEGER DEFAULT 0,
|
|
117
|
+
acked_count INTEGER DEFAULT 0,
|
|
118
|
+
worker_id VARCHAR(255),
|
|
119
|
+
|
|
120
|
+
-- ═══════════════════════════════════════════════════════════
|
|
121
|
+
-- STATISTICS (for dashboard - avoids expensive COUNT queries)
|
|
122
|
+
-- ═══════════════════════════════════════════════════════════
|
|
123
|
+
pending_estimate BIGINT DEFAULT 0,
|
|
124
|
+
last_stats_update TIMESTAMPTZ,
|
|
125
|
+
|
|
126
|
+
-- ═══════════════════════════════════════════════════════════
|
|
127
|
+
-- METADATA
|
|
128
|
+
-- ═══════════════════════════════════════════════════════════
|
|
69
129
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
70
|
-
|
|
130
|
+
|
|
131
|
+
UNIQUE(partition_id, consumer_group),
|
|
132
|
+
|
|
133
|
+
-- Constraint: cursor consistency
|
|
134
|
+
CHECK (
|
|
135
|
+
(last_consumed_id = '00000000-0000-0000-0000-000000000000'
|
|
136
|
+
AND last_consumed_created_at IS NULL)
|
|
137
|
+
OR
|
|
138
|
+
(last_consumed_id != '00000000-0000-0000-0000-000000000000'
|
|
139
|
+
AND last_consumed_created_at IS NOT NULL)
|
|
140
|
+
)
|
|
71
141
|
);
|
|
72
142
|
|
|
73
|
-
--
|
|
74
|
-
CREATE
|
|
143
|
+
-- Indexes for partition_consumers (critical for performance!)
|
|
144
|
+
CREATE INDEX IF NOT EXISTS idx_partition_consumers_lookup
|
|
145
|
+
ON queen.partition_consumers(partition_id, consumer_group);
|
|
146
|
+
|
|
147
|
+
CREATE INDEX IF NOT EXISTS idx_partition_consumers_active_leases
|
|
148
|
+
ON queen.partition_consumers(partition_id, consumer_group, lease_expires_at)
|
|
149
|
+
WHERE lease_expires_at IS NOT NULL;
|
|
150
|
+
|
|
151
|
+
CREATE INDEX IF NOT EXISTS idx_partition_consumers_expired_leases
|
|
152
|
+
ON queen.partition_consumers(lease_expires_at)
|
|
153
|
+
WHERE lease_expires_at IS NOT NULL;
|
|
154
|
+
|
|
155
|
+
CREATE INDEX IF NOT EXISTS idx_partition_consumers_progress
|
|
156
|
+
ON queen.partition_consumers(last_consumed_at DESC);
|
|
157
|
+
|
|
158
|
+
CREATE INDEX IF NOT EXISTS idx_partition_consumers_idle
|
|
159
|
+
ON queen.partition_consumers(partition_id, consumer_group)
|
|
160
|
+
WHERE lease_expires_at IS NULL;
|
|
161
|
+
|
|
162
|
+
CREATE INDEX IF NOT EXISTS idx_partition_consumers_consumer_group
|
|
163
|
+
ON queen.partition_consumers(consumer_group);
|
|
164
|
+
|
|
165
|
+
-- ────────────────────────────────────────────────────────────────
|
|
166
|
+
-- 5. MESSAGES_CONSUMED - ACK tracking for metrics (time-series)
|
|
167
|
+
-- ────────────────────────────────────────────────────────────────
|
|
168
|
+
CREATE TABLE IF NOT EXISTS queen.messages_consumed (
|
|
75
169
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
170
|
+
partition_id UUID REFERENCES queen.partitions(id) ON DELETE CASCADE,
|
|
171
|
+
consumer_group VARCHAR(255) NOT NULL,
|
|
172
|
+
|
|
173
|
+
-- Metrics for this ACK batch
|
|
174
|
+
messages_completed INTEGER DEFAULT 0,
|
|
175
|
+
messages_failed INTEGER DEFAULT 0,
|
|
176
|
+
|
|
177
|
+
-- Timestamp for time-series aggregation
|
|
178
|
+
acked_at TIMESTAMPTZ DEFAULT NOW()
|
|
83
179
|
);
|
|
84
180
|
|
|
85
|
-
--
|
|
86
|
-
CREATE
|
|
181
|
+
-- Indexes for time-series queries
|
|
182
|
+
CREATE INDEX IF NOT EXISTS idx_messages_consumed_acked_at
|
|
183
|
+
ON queen.messages_consumed(acked_at DESC);
|
|
184
|
+
|
|
185
|
+
CREATE INDEX IF NOT EXISTS idx_messages_consumed_partition_acked
|
|
186
|
+
ON queen.messages_consumed(partition_id, acked_at DESC);
|
|
187
|
+
|
|
188
|
+
CREATE INDEX IF NOT EXISTS idx_messages_consumed_consumer_acked
|
|
189
|
+
ON queen.messages_consumed(consumer_group, acked_at DESC);
|
|
190
|
+
|
|
191
|
+
-- Composite index for filtering by queue (via partition join)
|
|
192
|
+
CREATE INDEX IF NOT EXISTS idx_messages_consumed_partition_id
|
|
193
|
+
ON queen.messages_consumed(partition_id);
|
|
194
|
+
|
|
195
|
+
-- ────────────────────────────────────────────────────────────────
|
|
196
|
+
-- 6. DEAD_LETTER_QUEUE - Failed messages
|
|
197
|
+
-- ────────────────────────────────────────────────────────────────
|
|
198
|
+
CREATE TABLE IF NOT EXISTS queen.dead_letter_queue (
|
|
87
199
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
200
|
+
message_id UUID REFERENCES queen.messages(id) ON DELETE CASCADE,
|
|
88
201
|
partition_id UUID REFERENCES queen.partitions(id) ON DELETE CASCADE,
|
|
89
|
-
consumer_group VARCHAR(255)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
UNIQUE(partition_id, consumer_group) -- One active lease per partition per consumer group
|
|
202
|
+
consumer_group VARCHAR(255),
|
|
203
|
+
error_message TEXT,
|
|
204
|
+
retry_count INTEGER DEFAULT 0,
|
|
205
|
+
original_created_at TIMESTAMPTZ,
|
|
206
|
+
failed_at TIMESTAMPTZ DEFAULT NOW()
|
|
95
207
|
);
|
|
96
208
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
CREATE INDEX IF NOT EXISTS
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
CREATE INDEX IF NOT EXISTS
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
CREATE INDEX IF NOT EXISTS
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
--
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
-- Indexes for messages (simplified - no status fields)
|
|
113
|
-
CREATE INDEX IF NOT EXISTS idx_messages_partition_created ON queen.messages(partition_id, created_at);
|
|
114
|
-
CREATE INDEX IF NOT EXISTS idx_messages_transaction_id ON queen.messages(transaction_id);
|
|
115
|
-
CREATE INDEX IF NOT EXISTS idx_messages_trace_id ON queen.messages(trace_id);
|
|
116
|
-
CREATE INDEX IF NOT EXISTS idx_messages_created_at ON queen.messages(created_at);
|
|
117
|
-
|
|
118
|
-
-- Indexes for messages_status (critical for performance)
|
|
119
|
-
-- Note: Removed the partial unique index idx_status_queue_mode as it conflicts with
|
|
120
|
-
-- the table-level UNIQUE(message_id, consumer_group) constraint
|
|
121
|
-
|
|
122
|
-
-- Bus mode index (consumer_group IS NOT NULL)
|
|
123
|
-
CREATE INDEX IF NOT EXISTS idx_status_bus_mode
|
|
124
|
-
ON queen.messages_status(message_id, consumer_group, status)
|
|
125
|
-
WHERE consumer_group IS NOT NULL;
|
|
126
|
-
|
|
127
|
-
-- Index for finding pending messages by consumer group
|
|
128
|
-
CREATE INDEX IF NOT EXISTS idx_status_pending
|
|
129
|
-
ON queen.messages_status(consumer_group, status, message_id)
|
|
130
|
-
WHERE status = 'pending';
|
|
131
|
-
|
|
132
|
-
-- Index for lease expiration checks
|
|
133
|
-
CREATE INDEX IF NOT EXISTS idx_status_lease_expires
|
|
134
|
-
ON queen.messages_status(lease_expires_at, status, consumer_group)
|
|
135
|
-
WHERE status = 'processing';
|
|
136
|
-
|
|
137
|
-
-- Index for fast queue depth checks
|
|
138
|
-
CREATE INDEX IF NOT EXISTS idx_messages_status_pending_processing
|
|
139
|
-
ON queen.messages_status(message_id, status)
|
|
140
|
-
WHERE status IN ('pending', 'processing') OR status IS NULL;
|
|
141
|
-
|
|
142
|
-
-- Index for efficient pop operations (find messages without status for a consumer group)
|
|
143
|
-
CREATE INDEX IF NOT EXISTS idx_status_message_consumer
|
|
144
|
-
ON queen.messages_status(message_id, consumer_group);
|
|
145
|
-
|
|
146
|
-
-- Indexes for consumer groups
|
|
147
|
-
CREATE INDEX IF NOT EXISTS idx_consumer_groups_queue_name
|
|
148
|
-
ON queen.consumer_groups(queue_id, name);
|
|
149
|
-
|
|
150
|
-
CREATE INDEX IF NOT EXISTS idx_consumer_groups_active
|
|
151
|
-
ON queen.consumer_groups(queue_id, active)
|
|
152
|
-
WHERE active = true;
|
|
153
|
-
|
|
154
|
-
-- Indexes for partition leases
|
|
155
|
-
CREATE INDEX IF NOT EXISTS idx_partition_leases_expires
|
|
156
|
-
ON queen.partition_leases(lease_expires_at)
|
|
157
|
-
WHERE released_at IS NULL;
|
|
158
|
-
|
|
159
|
-
CREATE INDEX IF NOT EXISTS idx_partition_leases_active
|
|
160
|
-
ON queen.partition_leases(partition_id, consumer_group)
|
|
161
|
-
WHERE released_at IS NULL;
|
|
162
|
-
|
|
163
|
-
CREATE INDEX IF NOT EXISTS idx_partition_leases_active_lookup
|
|
164
|
-
ON queen.partition_leases(partition_id, consumer_group, lease_expires_at)
|
|
165
|
-
WHERE released_at IS NULL;
|
|
166
|
-
|
|
167
|
-
-- Retention history table for tracking deletions
|
|
209
|
+
CREATE INDEX IF NOT EXISTS idx_dlq_partition
|
|
210
|
+
ON queen.dead_letter_queue(partition_id);
|
|
211
|
+
|
|
212
|
+
CREATE INDEX IF NOT EXISTS idx_dlq_consumer_group
|
|
213
|
+
ON queen.dead_letter_queue(consumer_group);
|
|
214
|
+
|
|
215
|
+
CREATE INDEX IF NOT EXISTS idx_dlq_failed_at
|
|
216
|
+
ON queen.dead_letter_queue(failed_at DESC);
|
|
217
|
+
|
|
218
|
+
CREATE INDEX IF NOT EXISTS idx_dlq_message_consumer
|
|
219
|
+
ON queen.dead_letter_queue(message_id, consumer_group);
|
|
220
|
+
|
|
221
|
+
-- ────────────────────────────────────────────────────────────────
|
|
222
|
+
-- 7. RETENTION_HISTORY - Optional audit of cleanup operations
|
|
223
|
+
-- ────────────────────────────────────────────────────────────────
|
|
168
224
|
CREATE TABLE IF NOT EXISTS queen.retention_history (
|
|
169
225
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
170
226
|
partition_id UUID REFERENCES queen.partitions(id) ON DELETE CASCADE,
|
|
@@ -179,7 +235,11 @@ ON queen.retention_history(partition_id);
|
|
|
179
235
|
CREATE INDEX IF NOT EXISTS idx_retention_history_executed
|
|
180
236
|
ON queen.retention_history(executed_at);
|
|
181
237
|
|
|
182
|
-
--
|
|
238
|
+
-- ────────────────────────────────────────────────────────────────
|
|
239
|
+
-- TRIGGERS
|
|
240
|
+
-- ────────────────────────────────────────────────────────────────
|
|
241
|
+
|
|
242
|
+
-- Update partition last_activity on message insert
|
|
183
243
|
CREATE OR REPLACE FUNCTION update_partition_last_activity()
|
|
184
244
|
RETURNS TRIGGER AS $$
|
|
185
245
|
BEGIN
|
|
@@ -196,19 +256,23 @@ AFTER INSERT ON queen.messages
|
|
|
196
256
|
FOR EACH ROW
|
|
197
257
|
EXECUTE FUNCTION update_partition_last_activity();
|
|
198
258
|
|
|
199
|
-
--
|
|
200
|
-
CREATE OR REPLACE FUNCTION
|
|
201
|
-
RETURNS
|
|
259
|
+
-- Update pending_estimate on message insert
|
|
260
|
+
CREATE OR REPLACE FUNCTION update_pending_on_push()
|
|
261
|
+
RETURNS TRIGGER AS $$
|
|
202
262
|
BEGIN
|
|
203
|
-
--
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
AND q.completed_retention_seconds > 0
|
|
212
|
-
AND ms.completed_at < NOW() - INTERVAL '1 second' * q.completed_retention_seconds;
|
|
263
|
+
-- Increment pending estimate for all consumers on this partition
|
|
264
|
+
UPDATE queen.partition_consumers
|
|
265
|
+
SET pending_estimate = pending_estimate + 1,
|
|
266
|
+
last_stats_update = NOW()
|
|
267
|
+
WHERE partition_id = NEW.partition_id;
|
|
268
|
+
|
|
269
|
+
-- If no consumers exist yet, that's OK - they'll be created on first POP
|
|
270
|
+
RETURN NEW;
|
|
213
271
|
END;
|
|
214
|
-
$$ LANGUAGE plpgsql;
|
|
272
|
+
$$ LANGUAGE plpgsql;
|
|
273
|
+
|
|
274
|
+
DROP TRIGGER IF EXISTS trigger_update_pending_on_push ON queen.messages;
|
|
275
|
+
CREATE TRIGGER trigger_update_pending_on_push
|
|
276
|
+
AFTER INSERT ON queen.messages
|
|
277
|
+
FOR EACH ROW
|
|
278
|
+
EXECUTE FUNCTION update_pending_on_push();
|