smart_message 0.0.10 → 0.0.12

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.
Files changed (169) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/deploy-github-pages.yml +38 -0
  3. data/.gitignore +5 -0
  4. data/CHANGELOG.md +30 -0
  5. data/Gemfile.lock +35 -4
  6. data/README.md +169 -71
  7. data/Rakefile +29 -4
  8. data/docs/assets/images/ddq_architecture.svg +130 -0
  9. data/docs/assets/images/dlq_architecture.svg +115 -0
  10. data/docs/assets/images/enhanced-dual-publishing.svg +136 -0
  11. data/docs/assets/images/enhanced-fluent-api.svg +149 -0
  12. data/docs/assets/images/enhanced-microservices-routing.svg +115 -0
  13. data/docs/assets/images/enhanced-pattern-matching.svg +107 -0
  14. data/docs/assets/images/fluent-api-demo.svg +59 -0
  15. data/docs/assets/images/performance-comparison.svg +161 -0
  16. data/docs/assets/images/redis-basic-architecture.svg +53 -0
  17. data/docs/assets/images/redis-enhanced-architecture.svg +88 -0
  18. data/docs/assets/images/redis-queue-architecture.svg +101 -0
  19. data/docs/assets/images/smart_message.jpg +0 -0
  20. data/docs/assets/images/smart_message_walking.jpg +0 -0
  21. data/docs/assets/images/smartmessage_architecture_overview.svg +173 -0
  22. data/docs/assets/images/transport-comparison-matrix.svg +171 -0
  23. data/docs/assets/javascripts/mathjax.js +17 -0
  24. data/docs/assets/stylesheets/extra.css +51 -0
  25. data/docs/{addressing.md → core-concepts/addressing.md} +5 -7
  26. data/docs/{architecture.md → core-concepts/architecture.md} +78 -138
  27. data/docs/{dispatcher.md → core-concepts/dispatcher.md} +21 -21
  28. data/docs/{message_filtering.md → core-concepts/message-filtering.md} +2 -3
  29. data/docs/{message_processing.md → core-concepts/message-processing.md} +17 -17
  30. data/docs/{troubleshooting.md → development/troubleshooting.md} +7 -7
  31. data/docs/{examples.md → getting-started/examples.md} +115 -89
  32. data/docs/{getting-started.md → getting-started/quick-start.md} +47 -18
  33. data/docs/guides/redis-queue-getting-started.md +697 -0
  34. data/docs/guides/redis-queue-patterns.md +889 -0
  35. data/docs/guides/redis-queue-production.md +1091 -0
  36. data/docs/index.md +64 -0
  37. data/docs/{dead_letter_queue.md → reference/dead-letter-queue.md} +2 -3
  38. data/docs/{logging.md → reference/logging.md} +1 -1
  39. data/docs/{message_deduplication.md → reference/message-deduplication.md} +1 -0
  40. data/docs/{proc_handlers_summary.md → reference/proc-handlers.md} +7 -6
  41. data/docs/{serializers.md → reference/serializers.md} +3 -5
  42. data/docs/{transports.md → reference/transports.md} +133 -11
  43. data/docs/transports/memory-transport.md +374 -0
  44. data/docs/transports/redis-enhanced-transport.md +524 -0
  45. data/docs/transports/redis-queue-transport.md +1304 -0
  46. data/docs/transports/redis-transport-comparison.md +496 -0
  47. data/docs/transports/redis-transport.md +509 -0
  48. data/examples/README.md +98 -5
  49. data/examples/city_scenario/911_emergency_call_flow.svg +99 -0
  50. data/examples/city_scenario/README.md +515 -0
  51. data/examples/city_scenario/ai_visitor_intelligence_flow.svg +108 -0
  52. data/examples/city_scenario/citizen.rb +195 -0
  53. data/examples/city_scenario/city_diagram.svg +125 -0
  54. data/examples/city_scenario/common/health_monitor.rb +80 -0
  55. data/examples/city_scenario/common/logger.rb +30 -0
  56. data/examples/city_scenario/emergency_dispatch_center.rb +270 -0
  57. data/examples/city_scenario/fire_department.rb +446 -0
  58. data/examples/city_scenario/fire_emergency_flow.svg +95 -0
  59. data/examples/city_scenario/health_department.rb +100 -0
  60. data/examples/city_scenario/health_monitoring_system.svg +130 -0
  61. data/examples/city_scenario/house.rb +244 -0
  62. data/examples/city_scenario/local_bank.rb +217 -0
  63. data/examples/city_scenario/messages/emergency_911_message.rb +81 -0
  64. data/examples/city_scenario/messages/emergency_resolved_message.rb +43 -0
  65. data/examples/city_scenario/messages/fire_dispatch_message.rb +43 -0
  66. data/examples/city_scenario/messages/fire_emergency_message.rb +45 -0
  67. data/examples/city_scenario/messages/health_check_message.rb +22 -0
  68. data/examples/city_scenario/messages/health_status_message.rb +35 -0
  69. data/examples/city_scenario/messages/police_dispatch_message.rb +46 -0
  70. data/examples/city_scenario/messages/silent_alarm_message.rb +38 -0
  71. data/examples/city_scenario/police_department.rb +316 -0
  72. data/examples/city_scenario/redis_monitor.rb +129 -0
  73. data/examples/city_scenario/redis_stats.rb +743 -0
  74. data/examples/city_scenario/room_for_improvement.md +240 -0
  75. data/examples/city_scenario/security_emergency_flow.svg +95 -0
  76. data/examples/city_scenario/service_internal_architecture.svg +154 -0
  77. data/examples/city_scenario/smart_message_ai_agent.rb +364 -0
  78. data/examples/city_scenario/start_demo.sh +236 -0
  79. data/examples/city_scenario/stop_demo.sh +106 -0
  80. data/examples/city_scenario/visitor.rb +631 -0
  81. data/examples/{10_message_deduplication.rb → memory/01_message_deduplication_demo.rb} +1 -1
  82. data/examples/{09_dead_letter_queue_demo.rb → memory/02_dead_letter_queue_demo.rb} +13 -40
  83. data/examples/{01_point_to_point_orders.rb → memory/03_point_to_point_orders.rb} +1 -1
  84. data/examples/{02_publish_subscribe_events.rb → memory/04_publish_subscribe_events.rb} +2 -2
  85. data/examples/{03_many_to_many_chat.rb → memory/05_many_to_many_chat.rb} +4 -4
  86. data/examples/{show_me.rb → memory/06_pretty_print_demo.rb} +1 -1
  87. data/examples/{05_proc_handlers.rb → memory/07_proc_handlers_demo.rb} +2 -2
  88. data/examples/{06_custom_logger_example.rb → memory/08_custom_logger_demo.rb} +17 -14
  89. data/examples/{07_error_handling_scenarios.rb → memory/09_error_handling_demo.rb} +4 -4
  90. data/examples/{08_entity_addressing_basic.rb → memory/10_entity_addressing_basic.rb} +8 -8
  91. data/examples/{08_entity_addressing_with_filtering.rb → memory/11_entity_addressing_with_filtering.rb} +6 -6
  92. data/examples/{09_regex_filtering_microservices.rb → memory/12_regex_filtering_microservices.rb} +2 -2
  93. data/examples/{10_header_block_configuration.rb → memory/13_header_block_configuration.rb} +6 -6
  94. data/examples/{11_global_configuration_example.rb → memory/14_global_configuration_demo.rb} +19 -8
  95. data/examples/{show_logger.rb → memory/15_logger_demo.rb} +1 -1
  96. data/examples/memory/README.md +163 -0
  97. data/examples/memory/memory_transport_architecture.svg +90 -0
  98. data/examples/memory/point_to_point_pattern.svg +94 -0
  99. data/examples/memory/publish_subscribe_pattern.svg +125 -0
  100. data/examples/{04_redis_smart_home_iot.rb → redis/01_smart_home_iot_demo.rb} +5 -5
  101. data/examples/redis/README.md +230 -0
  102. data/examples/redis/alert_system_flow.svg +127 -0
  103. data/examples/redis/dashboard_status_flow.svg +107 -0
  104. data/examples/redis/device_command_flow.svg +113 -0
  105. data/examples/redis/redis_transport_architecture.svg +115 -0
  106. data/examples/{smart_home_iot_dataflow.md → redis/smart_home_iot_dataflow.md} +4 -116
  107. data/examples/redis/smart_home_system_architecture.svg +133 -0
  108. data/examples/redis_enhanced/README.md +319 -0
  109. data/examples/redis_enhanced/enhanced_01_basic_patterns.rb +233 -0
  110. data/examples/redis_enhanced/enhanced_02_fluent_api.rb +331 -0
  111. data/examples/redis_enhanced/enhanced_03_dual_publishing.rb +281 -0
  112. data/examples/redis_enhanced/enhanced_04_advanced_routing.rb +419 -0
  113. data/examples/redis_queue/01_basic_messaging.rb +221 -0
  114. data/examples/redis_queue/01_comprehensive_examples.rb +508 -0
  115. data/examples/redis_queue/02_pattern_routing.rb +405 -0
  116. data/examples/redis_queue/03_fluent_api.rb +422 -0
  117. data/examples/redis_queue/04_load_balancing.rb +486 -0
  118. data/examples/redis_queue/05_microservices.rb +735 -0
  119. data/examples/redis_queue/06_emergency_alerts.rb +777 -0
  120. data/examples/redis_queue/07_queue_management.rb +587 -0
  121. data/examples/redis_queue/README.md +366 -0
  122. data/examples/redis_queue/enhanced_01_basic_patterns.rb +233 -0
  123. data/examples/redis_queue/enhanced_02_fluent_api.rb +331 -0
  124. data/examples/redis_queue/enhanced_03_dual_publishing.rb +281 -0
  125. data/examples/redis_queue/enhanced_04_advanced_routing.rb +419 -0
  126. data/examples/redis_queue/redis_queue_architecture.svg +148 -0
  127. data/ideas/README.md +41 -0
  128. data/ideas/agents.md +1001 -0
  129. data/ideas/database_transport.md +980 -0
  130. data/ideas/improvement.md +359 -0
  131. data/ideas/meshage.md +1788 -0
  132. data/ideas/message_discovery.md +178 -0
  133. data/ideas/message_schema.md +1381 -0
  134. data/lib/smart_message/.idea/.gitignore +8 -0
  135. data/lib/smart_message/.idea/markdown.xml +6 -0
  136. data/lib/smart_message/.idea/misc.xml +4 -0
  137. data/lib/smart_message/.idea/modules.xml +8 -0
  138. data/lib/smart_message/.idea/smart_message.iml +16 -0
  139. data/lib/smart_message/.idea/vcs.xml +6 -0
  140. data/lib/smart_message/addressing.rb +15 -0
  141. data/lib/smart_message/base.rb +0 -2
  142. data/lib/smart_message/configuration.rb +1 -1
  143. data/lib/smart_message/logger.rb +15 -4
  144. data/lib/smart_message/plugins.rb +5 -2
  145. data/lib/smart_message/serializer.rb +14 -0
  146. data/lib/smart_message/transport/redis_enhanced_transport.rb +399 -0
  147. data/lib/smart_message/transport/redis_queue_transport.rb +555 -0
  148. data/lib/smart_message/transport/registry.rb +1 -0
  149. data/lib/smart_message/transport.rb +34 -1
  150. data/lib/smart_message/version.rb +1 -1
  151. data/lib/smart_message.rb +5 -52
  152. data/mkdocs.yml +184 -0
  153. data/p2p_plan.md +326 -0
  154. data/p2p_roadmap.md +287 -0
  155. data/smart_message.gemspec +2 -0
  156. data/smart_message.svg +51 -0
  157. metadata +170 -44
  158. data/docs/README.md +0 -57
  159. data/examples/dead_letters.jsonl +0 -12
  160. data/examples/temp.txt +0 -94
  161. data/examples/tmux_chat/README.md +0 -283
  162. data/examples/tmux_chat/bot_agent.rb +0 -278
  163. data/examples/tmux_chat/human_agent.rb +0 -199
  164. data/examples/tmux_chat/room_monitor.rb +0 -160
  165. data/examples/tmux_chat/shared_chat_system.rb +0 -328
  166. data/examples/tmux_chat/start_chat_demo.sh +0 -190
  167. data/examples/tmux_chat/stop_chat_demo.sh +0 -22
  168. /data/docs/{properties.md → core-concepts/properties.md} +0 -0
  169. /data/docs/{ideas_to_think_about.md → development/ideas.md} +0 -0
@@ -0,0 +1,980 @@
1
+ # Database Transport Implementation Ideas
2
+
3
+ This document explores implementing database-backed transports for SmartMessage, focusing on persistent messaging, advanced routing capabilities, and high-performance batching operations.
4
+
5
+ ## Overview
6
+
7
+ Database transports provide a **persistent, transactional messaging layer** that complements existing in-memory (Redis, Memory) transports. The recommended architecture uses a **hybrid approach**:
8
+
9
+ - **Database Transport**: Publish-only persistent archive (no subscriptions)
10
+ - **Redis Transport**: Real-time pub/sub processing (existing functionality)
11
+ - **Multi-Transport Publishing**: Messages published to both simultaneously
12
+
13
+ This hybrid model delivers enterprise-grade persistence with Redis-speed real-time processing, while dramatically simplifying the database transport implementation by eliminating all subscription complexity.
14
+
15
+ ## Core Benefits
16
+
17
+ ### 1. Reliability & Persistence
18
+ - **ACID Guarantees**: Transactional message processing with rollback capabilities
19
+ - **Message Survival**: Messages persist across application restarts and failures
20
+ - **Built-in Dead Letter Queue**: Failed messages automatically retained in database
21
+ - **Complete Audit Trail**: Every message stored with timestamps, processing status
22
+ - **Guaranteed Delivery**: Messages remain until successfully processed
23
+ - **Disaster Recovery**: Database backups include full message history
24
+
25
+ ### 2. Advanced Routing Capabilities
26
+ - **SQL-based Filtering**: Complex routing rules using WHERE clauses
27
+ - **Priority Queues**: ORDER BY priority, created_at for message ordering
28
+ - **Delayed Processing**: Schedule messages for future processing with WHERE process_after < NOW()
29
+ - **Content-based Routing**: Route messages based on payload content using JSONB queries
30
+ - **Entity Targeting**: Perfect integration with FROM/TO/REPLY_TO addressing system
31
+
32
+ ### 3. Performance Through Batching
33
+ - **Bulk Operations**: INSERT/UPDATE operations 100x faster than individual operations
34
+ - **Transaction Efficiency**: Process multiple messages atomically
35
+ - **Connection Pool Utilization**: Leverage database connection pooling
36
+ - **Reduced I/O Overhead**: Batch database round-trips for high-throughput scenarios
37
+
38
+ ## Database Schema Design
39
+
40
+ ### Core Messages Table
41
+ ```sql
42
+ CREATE TABLE smart_messages (
43
+ id BIGSERIAL PRIMARY KEY,
44
+
45
+ -- Header fields (matches SmartMessage::Header exactly)
46
+ uuid UUID NOT NULL UNIQUE,
47
+ message_class VARCHAR NOT NULL,
48
+ published_at TIMESTAMP WITH TIME ZONE NOT NULL,
49
+ publisher_pid INTEGER NOT NULL,
50
+ version INTEGER NOT NULL DEFAULT 1,
51
+ serializer VARCHAR, -- Tracks serializer used for DLQ/gateway patterns
52
+
53
+ -- Entity addressing fields (SmartMessage::Header addressing)
54
+ from_entity VARCHAR NOT NULL, -- Required: sender entity ID
55
+ to_entity VARCHAR, -- NULL = broadcast to all subscribers
56
+ reply_to VARCHAR, -- Optional: response routing entity
57
+
58
+ -- Message content and processing
59
+ payload JSONB NOT NULL, -- Serialized message payload
60
+ payload_format VARCHAR DEFAULT 'json', -- Format tracking for multi-serializer support
61
+
62
+ -- Processing state tracking
63
+ status VARCHAR DEFAULT 'pending' CHECK (status IN ('pending', 'processing', 'completed', 'failed')),
64
+ processed_at TIMESTAMP WITH TIME ZONE,
65
+ processing_attempts INTEGER DEFAULT 0,
66
+ last_error TEXT,
67
+ last_processed_by VARCHAR, -- Handler/processor identification
68
+
69
+ -- Advanced features for enterprise usage
70
+ priority INTEGER DEFAULT 0, -- Higher numbers = higher priority
71
+ process_after TIMESTAMP WITH TIME ZONE DEFAULT NOW(), -- Delayed processing
72
+ expires_at TIMESTAMP WITH TIME ZONE, -- Message expiration
73
+ correlation_id VARCHAR, -- Request-reply correlation
74
+
75
+ -- Audit and compliance
76
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
77
+ updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
78
+
79
+ -- Constraints
80
+ CONSTRAINT smart_messages_uuid_key UNIQUE (uuid),
81
+ CONSTRAINT smart_messages_version_positive CHECK (version > 0),
82
+ CONSTRAINT smart_messages_priority_range CHECK (priority >= 0),
83
+ CONSTRAINT smart_messages_processing_attempts_positive CHECK (processing_attempts >= 0)
84
+ );
85
+
86
+ -- Optimized performance indexes based on SmartMessage usage patterns
87
+ CREATE INDEX idx_smart_messages_processing_queue
88
+ ON smart_messages (status, process_after, priority DESC, created_at ASC)
89
+ WHERE status IN ('pending', 'processing');
90
+
91
+ CREATE INDEX idx_smart_messages_entity_routing
92
+ ON smart_messages (message_class, to_entity, status);
93
+
94
+ CREATE INDEX idx_smart_messages_from_entity_audit
95
+ ON smart_messages (from_entity, created_at DESC);
96
+
97
+ CREATE INDEX idx_smart_messages_correlation
98
+ ON smart_messages (correlation_id)
99
+ WHERE correlation_id IS NOT NULL;
100
+
101
+ CREATE INDEX idx_smart_messages_expiration
102
+ ON smart_messages (expires_at)
103
+ WHERE expires_at IS NOT NULL AND status = 'pending';
104
+
105
+ -- Partial index for active messages only (significant performance gain)
106
+ CREATE INDEX idx_smart_messages_active_by_class
107
+ ON smart_messages (message_class, priority DESC, created_at ASC)
108
+ WHERE status IN ('pending', 'processing');
109
+ ```
110
+
111
+ ### Subscription Registry Table
112
+ ```sql
113
+ CREATE TABLE smart_subscriptions (
114
+ id BIGSERIAL PRIMARY KEY,
115
+ message_class VARCHAR NOT NULL,
116
+ processor_method VARCHAR NOT NULL,
117
+
118
+ -- Entity-aware filtering support (matches SmartMessage v0.0.6+ filtering)
119
+ subscriber_entity_id VARCHAR, -- The entity subscribing (for targeting)
120
+ from_filter VARCHAR[], -- Array of from entity patterns
121
+ to_filter VARCHAR[], -- Array of to entity patterns
122
+ broadcast_filter BOOLEAN, -- Filter for broadcast messages
123
+
124
+ -- Filter type tracking for regex vs exact matching
125
+ from_filter_types VARCHAR[], -- 'exact' or 'regex' for each from_filter
126
+ to_filter_types VARCHAR[], -- 'exact' or 'regex' for each to_filter
127
+
128
+ -- Subscription metadata
129
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
130
+ last_matched_at TIMESTAMP WITH TIME ZONE,
131
+ match_count BIGINT DEFAULT 0,
132
+
133
+ -- Deduplication settings per subscription
134
+ ddq_enabled BOOLEAN DEFAULT true,
135
+ ddq_size INTEGER DEFAULT 100,
136
+
137
+ UNIQUE(message_class, processor_method, subscriber_entity_id)
138
+ );
139
+
140
+ -- Optimized indexes for subscription matching
141
+ CREATE INDEX idx_smart_subscriptions_message_routing
142
+ ON smart_subscriptions (message_class);
143
+
144
+ CREATE INDEX idx_smart_subscriptions_entity_targeting
145
+ ON smart_subscriptions (subscriber_entity_id, message_class);
146
+
147
+ CREATE INDEX idx_smart_subscriptions_broadcast
148
+ ON smart_subscriptions (message_class, broadcast_filter)
149
+ WHERE broadcast_filter = true;
150
+ ```
151
+
152
+ ### Deduplication Queue Table (Database-backed DDQ)
153
+ ```sql
154
+ CREATE TABLE smart_ddq_entries (
155
+ id BIGSERIAL PRIMARY KEY,
156
+ handler_key VARCHAR NOT NULL, -- "MessageClass:HandlerMethod" format
157
+ message_uuid UUID NOT NULL,
158
+ processed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
159
+
160
+ -- Circular buffer metadata
161
+ position INTEGER NOT NULL, -- Position in circular buffer (0 to ddq_size-1)
162
+
163
+ UNIQUE(handler_key, position), -- Ensures circular buffer constraint
164
+ INDEX idx_ddq_handler_lookup (handler_key, message_uuid),
165
+ INDEX idx_ddq_cleanup (processed_at) -- For TTL cleanup
166
+ );
167
+
168
+ -- Partitioning by handler_key for high-throughput scenarios
169
+ -- CREATE TABLE smart_ddq_entries_handler1 PARTITION OF smart_ddq_entries FOR VALUES IN ('OrderMessage:process');
170
+ ```
171
+
172
+ ### Dead Letter Queue Table
173
+ ```sql
174
+ CREATE TABLE smart_dead_letters (
175
+ id BIGSERIAL PRIMARY KEY,
176
+
177
+ -- Reference to original message
178
+ original_message_id BIGINT REFERENCES smart_messages(id),
179
+ original_uuid UUID NOT NULL,
180
+
181
+ -- Failure tracking
182
+ failed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
183
+ failure_reason VARCHAR NOT NULL, -- 'processing_error', 'timeout', 'circuit_breaker', 'max_retries'
184
+ error_message TEXT,
185
+ error_details JSONB, -- Structured error information
186
+ stack_trace TEXT,
187
+ retry_count INTEGER DEFAULT 0,
188
+
189
+ -- Handler context
190
+ failed_handler VARCHAR, -- Which handler failed
191
+ failed_processor VARCHAR, -- Which processor/method failed
192
+
193
+ -- Complete message preservation for replay
194
+ message_class VARCHAR NOT NULL,
195
+ from_entity VARCHAR NOT NULL,
196
+ to_entity VARCHAR,
197
+ reply_to VARCHAR,
198
+ payload JSONB NOT NULL,
199
+ payload_format VARCHAR DEFAULT 'json',
200
+
201
+ -- Original header preservation
202
+ original_published_at TIMESTAMP WITH TIME ZONE,
203
+ original_publisher_pid INTEGER,
204
+ original_version INTEGER,
205
+ original_serializer VARCHAR,
206
+
207
+ -- DLQ management
208
+ replay_count INTEGER DEFAULT 0,
209
+ last_replay_at TIMESTAMP WITH TIME ZONE,
210
+ replay_successful BOOLEAN,
211
+
212
+ -- Audit
213
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
214
+ updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
215
+ );
216
+
217
+ -- Indexes for DLQ management and analysis
218
+ CREATE INDEX idx_dead_letters_failure_analysis
219
+ ON smart_dead_letters (message_class, failure_reason, failed_at DESC);
220
+
221
+ CREATE INDEX idx_dead_letters_replay_queue
222
+ ON smart_dead_letters (failed_at ASC)
223
+ WHERE replay_successful IS NULL;
224
+
225
+ CREATE INDEX idx_dead_letters_handler_errors
226
+ ON smart_dead_letters (failed_handler, failed_at DESC);
227
+ ```
228
+
229
+ ## Hybrid Architecture: Publish-Only Database + Redis Processing
230
+
231
+ ### Recommended Architecture
232
+
233
+ The optimal database transport implementation uses a **publish-only pattern** combined with Redis for real-time processing:
234
+
235
+ ```
236
+ ┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
237
+ │ Application │ │ SmartMessage │ │ Multi-Trans │
238
+ │ Publishes ├───►│ Message ├───►│ Publishing │
239
+ │ OrderMessage │ │ Instance │ │ │
240
+ └─────────────────┘ └──────────────────┘ └─────────┬───────┘
241
+
242
+ ┌───────────────┼───────────────┐
243
+ │ │ │
244
+ ▼ ▼ ▼
245
+ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
246
+ │ Database │ │ Redis │ │ S3 │
247
+ │ (Archive) │ │(Processing) │ │ (Compliance)│
248
+ │ Publish-Only│ │ Pub/Sub │ │Archive-Only │
249
+ └─────────────┘ └─────────────┘ └─────────────┘
250
+ │ │ │
251
+ ▼ ▼ ▼
252
+ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
253
+ │ Audit │ │ Subscribers │ │ Long-term │
254
+ │ Trails │ │ Get Messages│ │ Storage │
255
+ │ Reports │ │ Immediately │ │ │
256
+ └─────────────┘ └─────────────┘ └─────────────┘
257
+ ```
258
+
259
+ ### Database Transport: Publish-Only Implementation
260
+
261
+ ```ruby
262
+ class DatabaseTransport < Base
263
+ # Database transport does NOT support subscriptions
264
+ def subscribe(message_class, process_method, filter_options = {})
265
+ raise NotImplementedError,
266
+ "DatabaseTransport is publish-only. Use RedisTransport for message processing subscriptions."
267
+ end
268
+
269
+ # Only implement publishing for persistent archiving
270
+ def do_publish(message_class, serialized_message)
271
+ message_data = JSON.parse(serialized_message)
272
+ header = message_data['header']
273
+ payload = message_data['payload']
274
+
275
+ # Simple INSERT - optimized for archival, not processing
276
+ @connection_pool.with do |conn|
277
+ conn.execute(<<~SQL, [
278
+ header['uuid'],
279
+ header['message_class'],
280
+ header['published_at'],
281
+ header['publisher_pid'],
282
+ header['version'],
283
+ header['serializer'],
284
+ header['from'],
285
+ header['to'],
286
+ header['reply_to'],
287
+ payload,
288
+ 'json',
289
+ 'archived' # Status: archived, not for processing
290
+ ])
291
+ INSERT INTO smart_messages (
292
+ uuid, message_class, published_at, publisher_pid, version, serializer,
293
+ from_entity, to_entity, reply_to, payload, payload_format, status
294
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
295
+ SQL
296
+ end
297
+ end
298
+
299
+ # Simplified connection management (no complex subscription threads)
300
+ def connected?
301
+ @connection_pool.with { |conn| conn.execute("SELECT 1").first }
302
+ true
303
+ rescue
304
+ false
305
+ end
306
+
307
+ def connect
308
+ # Database connections are managed by connection pool
309
+ # No subscription threads to start
310
+ end
311
+
312
+ def disconnect
313
+ # No subscription threads to stop
314
+ @connection_pool&.shutdown { |conn| conn.close }
315
+ end
316
+ end
317
+ ```
318
+
319
+ ### Multi-Transport Message Configuration
320
+
321
+ Messages can be configured to publish to multiple transports simultaneously:
322
+
323
+ ```ruby
324
+ class OrderMessage < SmartMessage::Base
325
+ property :order_id, required: true
326
+ property :amount, required: true
327
+ property :customer_id, required: true
328
+
329
+ config do
330
+ # Multi-transport: Redis for processing + Database for archiving
331
+ transport [
332
+ redis_transport, # Real-time pub/sub processing
333
+ database_transport # Persistent archive (publish-only)
334
+ ]
335
+ serializer SmartMessage::Serializer::JSON.new
336
+ end
337
+ end
338
+
339
+ # Publishing sends to ALL configured transports
340
+ message = OrderMessage.new(order_id: "123", amount: 99.99, customer_id: "cust_456")
341
+ message.from = "order_service"
342
+ message.to = "payment_service"
343
+ message.publish # → Redis pub/sub (immediate) + Database INSERT (archived)
344
+ ```
345
+
346
+ ### Environment-Specific Transport Configurations
347
+
348
+ ```ruby
349
+ # config/initializers/smart_message.rb
350
+
351
+ # Development: Redis only for speed
352
+ if Rails.env.development?
353
+ SmartMessage.configure do
354
+ default_transport redis_transport
355
+ end
356
+ end
357
+
358
+ # Production: Redis + Database + S3 for enterprise requirements
359
+ if Rails.env.production?
360
+ SmartMessage.configure do
361
+ default_transport [
362
+ redis_transport, # Real-time processing
363
+ database_transport(database_url: ENV['DATABASE_URL']), # Audit archive
364
+ s3_transport(bucket: ENV['AUDIT_BUCKET']) # Compliance storage
365
+ ]
366
+ end
367
+ end
368
+
369
+ # Testing: Memory only
370
+ if Rails.env.test?
371
+ SmartMessage.configure do
372
+ default_transport memory_transport
373
+ end
374
+ end
375
+ ```
376
+
377
+ ### Benefits of Publish-Only Database Transport
378
+
379
+ 1. **Simplified Implementation**: No subscription complexity, polling, or notification systems
380
+ 2. **High Performance**: Optimized for write-heavy archival workloads
381
+ 3. **Clear Separation**: Database = persistence, Redis = processing
382
+ 4. **Scalability**: Database optimized for storage, Redis optimized for speed
383
+ 5. **Reliability**: Every message guaranteed to be archived regardless of processing failures
384
+ 6. **Compliance**: Complete audit trail with ACID guarantees
385
+ 7. **Flexibility**: Add/remove archive transports without affecting processing
386
+
387
+ ### Multi-Transport Publishing Logic
388
+
389
+ SmartMessage Base class handles multi-transport publishing automatically:
390
+
391
+ ```ruby
392
+ # In SmartMessage::Base
393
+ def publish
394
+ validate!
395
+
396
+ # Support both single transport and array of transports
397
+ transports = Array(self.class.transport)
398
+
399
+ transports.each do |transport|
400
+ begin
401
+ serialized_message = serialize
402
+ transport.publish(self.class.name, serialized_message)
403
+ rescue => e
404
+ # Continue publishing to other transports even if one fails
405
+ logger.error "Failed to publish to #{transport.class.name}: #{e.message}"
406
+ # Could integrate with circuit breaker for fallback behavior
407
+ end
408
+ end
409
+ end
410
+ ```
411
+
412
+ This architecture provides the best of all worlds:
413
+ - **Redis speed** for real-time processing
414
+ - **Database persistence** for enterprise requirements
415
+ - **Simple implementation** with clear separation of concerns
416
+ - **Flexible configuration** for different environments
417
+
418
+ ## Subscription and Notification Strategy
419
+
420
+ ### Push vs Pull: Database Notification Systems
421
+
422
+ **Challenge**: Unlike Redis pub/sub which pushes messages instantly, databases require a mechanism to notify applications when new messages arrive. Traditional polling is inefficient and adds latency.
423
+
424
+ **Solution**: Use database-native push notification systems for real-time message delivery.
425
+
426
+ #### PostgreSQL LISTEN/NOTIFY (Recommended)
427
+ PostgreSQL provides a built-in pub/sub system that delivers true push notifications:
428
+
429
+ ```sql
430
+ -- Database trigger to notify on new messages
431
+ CREATE OR REPLACE FUNCTION notify_new_message()
432
+ RETURNS TRIGGER AS $$
433
+ BEGIN
434
+ -- Send notification with message details
435
+ PERFORM pg_notify('new_smart_message', json_build_object(
436
+ 'message_id', NEW.id,
437
+ 'message_class', NEW.message_class,
438
+ 'priority', NEW.priority,
439
+ 'to_entity', NEW.to_entity
440
+ )::text);
441
+
442
+ RETURN NEW;
443
+ END;
444
+ $$ LANGUAGE plpgsql;
445
+
446
+ -- Trigger fires automatically on INSERT
447
+ CREATE TRIGGER trigger_notify_new_message
448
+ AFTER INSERT ON smart_messages
449
+ FOR EACH ROW
450
+ EXECUTE FUNCTION notify_new_message();
451
+ ```
452
+
453
+ ```ruby
454
+ class DatabaseTransport < Base
455
+ def start_postgres_listener
456
+ @notification_thread = Thread.new do
457
+ @connection_pool.with do |conn|
458
+ # Subscribe to database notifications
459
+ conn.execute("LISTEN new_smart_message")
460
+
461
+ loop do
462
+ # Block until notification received (no polling!)
463
+ conn.raw_connection.wait_for_notify do |channel, pid, payload|
464
+ handle_notification(payload)
465
+ end
466
+ end
467
+ end
468
+ end
469
+ end
470
+
471
+ private
472
+
473
+ def handle_notification(payload)
474
+ message_info = JSON.parse(payload)
475
+ message_id = message_info['message_id']
476
+
477
+ # Fetch specific message and process immediately
478
+ message_data = fetch_message_by_id(message_id)
479
+ if message_data
480
+ # Convert to SmartMessage format and route
481
+ receive(message_data['message_class'], reconstruct_serialized_message(message_data))
482
+
483
+ # Mark as processing to prevent duplicate handling
484
+ mark_message_processing(message_id)
485
+ end
486
+ end
487
+
488
+ def fetch_message_by_id(message_id)
489
+ @connection_pool.with do |conn|
490
+ conn.execute(<<~SQL, [message_id]).first
491
+ SELECT * FROM smart_messages
492
+ WHERE id = $1 AND status = 'pending'
493
+ SQL
494
+ end
495
+ end
496
+ end
497
+ ```
498
+
499
+ #### MySQL/Other Databases (Polling Fallback)
500
+ For databases without native push notifications:
501
+
502
+ ```ruby
503
+ def start_polling_subscriber
504
+ @polling_thread = Thread.new do
505
+ loop do
506
+ poll_for_messages
507
+ sleep(@options[:poll_interval] || 1) # Default 1 second
508
+ end
509
+ end
510
+ end
511
+
512
+ def poll_for_messages
513
+ messages = retrieve_pending_messages(limit: @options[:batch_size] || 100)
514
+
515
+ messages.each do |message_data|
516
+ receive(message_data['message_class'], reconstruct_serialized_message(message_data))
517
+ mark_message_processing(message_data['id'])
518
+ end
519
+ end
520
+ ```
521
+
522
+ #### Hybrid Detection Strategy
523
+ ```ruby
524
+ def initialize(**options)
525
+ super
526
+ @notification_method = detect_notification_method
527
+ configure_subscriber
528
+ end
529
+
530
+ private
531
+
532
+ def detect_notification_method
533
+ case @connection_adapter_name
534
+ when /postgresql/i
535
+ :listen_notify
536
+ when /mysql/i
537
+ :polling # Could add MySQL events or external triggers
538
+ when /sqlite/i
539
+ :polling # Limited to single-process anyway
540
+ else
541
+ :polling
542
+ end
543
+ end
544
+
545
+ def start_subscriber
546
+ case @notification_method
547
+ when :listen_notify
548
+ start_postgres_listener
549
+ else
550
+ start_polling_subscriber
551
+ end
552
+ end
553
+ ```
554
+
555
+ ### Performance Comparison
556
+
557
+ | Method | Latency | CPU Usage | Database Support | Complexity |
558
+ |--------|---------|-----------|------------------|------------|
559
+ | **PostgreSQL LISTEN/NOTIFY** | ~1ms | Very Low | PostgreSQL | Medium |
560
+ | **MySQL Events** | ~1s | Low | MySQL | Medium |
561
+ | **Polling (1s interval)** | ~500ms avg | Medium | All | Low |
562
+ | **Polling (100ms interval)** | ~50ms avg | High | All | Low |
563
+
564
+ ### Benefits of PostgreSQL LISTEN/NOTIFY
565
+
566
+ - **Real-time Delivery**: Sub-millisecond notification latency
567
+ - **Zero Polling Overhead**: No constant database queries
568
+ - **Connection Resilience**: Automatic reconnection and notification replay
569
+ - **Scalable**: Multiple subscribers can listen to same channel
570
+ - **Native Integration**: Built into PostgreSQL, no external dependencies
571
+ - **Filtered Notifications**: Can include message metadata in notification payload
572
+
573
+ This approach gives database transport **the same real-time characteristics as Redis pub/sub** while maintaining all the persistence, ACID guarantees, and enterprise features that databases provide.
574
+
575
+ ## Implementation Architecture
576
+
577
+ ### Transport Class Structure
578
+ ```ruby
579
+ module SmartMessage
580
+ module Transport
581
+ class DatabaseTransport < Base
582
+ attr_reader :connection_pool, :batch_processor
583
+
584
+ def initialize(**options)
585
+ super
586
+ @connection_pool = setup_connection_pool
587
+ @batch_processor = BatchProcessor.new(self)
588
+ @pending_messages = Queue.new
589
+ setup_batch_timer if options[:enable_batching]
590
+ end
591
+
592
+ # Individual message publishing (immediate)
593
+ def publish(message_header, message_payload)
594
+ if @options[:enable_batching]
595
+ @pending_messages << [message_header, message_payload]
596
+ else
597
+ publish_single(message_header, message_payload)
598
+ end
599
+ end
600
+
601
+ # Batch publishing for high-throughput scenarios
602
+ def publish_batch(messages)
603
+ @connection_pool.with do |conn|
604
+ conn.transaction do
605
+ insert_data = messages.map { |header, payload| prepare_message_data(header, payload) }
606
+ conn.execute(batch_insert_sql, insert_data.flatten)
607
+ end
608
+ end
609
+ end
610
+
611
+ # Message retrieval with advanced routing
612
+ def retrieve_messages(entity_id: nil, limit: 100)
613
+ @connection_pool.with do |conn|
614
+ conn.execute(retrieval_sql, [entity_id, entity_id, Time.current, limit])
615
+ end
616
+ end
617
+
618
+ private
619
+
620
+ def retrieval_sql
621
+ <<~SQL
622
+ SELECT id, uuid, from_entity, to_entity, reply_to, message_class,
623
+ payload, published_at, priority
624
+ FROM smart_messages
625
+ WHERE processed_at IS NULL
626
+ AND process_after <= $3
627
+ AND (to_entity = $1 OR to_entity IS NULL OR $2 IS NULL)
628
+ ORDER BY priority DESC, published_at ASC
629
+ LIMIT $4
630
+ SQL
631
+ end
632
+ end
633
+ end
634
+ end
635
+ ```
636
+
637
+ ### Batch Processing System
638
+ ```ruby
639
+ class BatchProcessor
640
+ def initialize(transport)
641
+ @transport = transport
642
+ @batch = []
643
+ @mutex = Mutex.new
644
+ @batch_size = transport.options[:batch_size] || 100
645
+ @batch_timeout = transport.options[:batch_timeout] || 5.seconds
646
+ end
647
+
648
+ def add_message(header, payload)
649
+ @mutex.synchronize do
650
+ @batch << [header, payload]
651
+ flush_if_ready
652
+ end
653
+ end
654
+
655
+ def flush_if_ready
656
+ if @batch.size >= @batch_size
657
+ flush_batch
658
+ end
659
+ end
660
+
661
+ def flush_batch
662
+ return if @batch.empty?
663
+
664
+ batch_to_process = @batch.dup
665
+ @batch.clear
666
+
667
+ @transport.publish_batch(batch_to_process)
668
+ end
669
+ end
670
+ ```
671
+
672
+ ## Advanced Routing Queries
673
+
674
+ ### Entity-Specific and Broadcast Messaging
675
+ ```sql
676
+ -- Retrieve messages for specific entity or broadcast messages
677
+ SELECT * FROM smart_messages
678
+ WHERE processed_at IS NULL
679
+ AND (to_entity = 'user_123' OR to_entity IS NULL)
680
+ AND process_after <= NOW()
681
+ ORDER BY priority DESC, published_at ASC;
682
+ ```
683
+
684
+ ### Priority-Based Processing
685
+ ```sql
686
+ -- High priority messages first, then by publish time
687
+ SELECT * FROM smart_messages
688
+ WHERE processed_at IS NULL
689
+ AND message_class = 'OrderProcessingMessage'
690
+ ORDER BY priority DESC, published_at ASC
691
+ LIMIT 50;
692
+ ```
693
+
694
+ ### Content-Based Routing
695
+ ```sql
696
+ -- Route based on payload content using JSONB operators
697
+ SELECT * FROM smart_messages
698
+ WHERE processed_at IS NULL
699
+ AND message_class = 'NotificationMessage'
700
+ AND payload->>'urgency' = 'high'
701
+ AND payload->'recipient'->>'region' = 'us-west';
702
+ ```
703
+
704
+ ### Delayed Processing
705
+ ```sql
706
+ -- Messages scheduled for future processing
707
+ SELECT * FROM smart_messages
708
+ WHERE processed_at IS NULL
709
+ AND process_after <= NOW()
710
+ ORDER BY process_after ASC, priority DESC;
711
+ ```
712
+
713
+ ## Integration with SmartMessage Improvements
714
+
715
+ ### 1. Message Wrapper Enhancement Integration
716
+ The database schema naturally supports the proposed addressing system:
717
+ ```ruby
718
+ # Publishing with addressing
719
+ message = OrderMessage.new(order_id: "123", amount: 99.99)
720
+ message.from = "order_service"
721
+ message.to = "payment_service" # Specific targeting
722
+ message.reply_to = "order_service"
723
+ message.publish
724
+
725
+ # Broadcast (to_entity = NULL)
726
+ broadcast = SystemAlert.new(message: "Maintenance starting")
727
+ broadcast.from = "admin_service"
728
+ # No .to specified = broadcast
729
+ broadcast.publish
730
+ ```
731
+
732
+ ### 2. Circuit Breaker Integration
733
+ ```ruby
734
+ class DatabaseTransport < Base
735
+ include BreakerMachines::DSL
736
+
737
+ circuit :database_publish do
738
+ threshold failures: 5, within: 2.minutes
739
+ reset_after 30.seconds
740
+ fallback { |error| handle_publish_failure(error) }
741
+ end
742
+
743
+ def publish(message_header, message_payload)
744
+ circuit(:database_publish).wrap do
745
+ # Database publishing logic
746
+ end
747
+ end
748
+ end
749
+ ```
750
+
751
+ ### 3. Dead Letter Queue Integration
752
+ ```ruby
753
+ def mark_message_failed(message_id, error)
754
+ @connection_pool.with do |conn|
755
+ conn.transaction do
756
+ # Move to dead letter queue
757
+ conn.execute(insert_dead_letter_sql, [message_id, error.message])
758
+
759
+ # Update original message
760
+ conn.execute(
761
+ "UPDATE smart_messages SET processed_at = NOW(), last_error = $1 WHERE id = $2",
762
+ [error.message, message_id]
763
+ )
764
+ end
765
+ end
766
+ end
767
+ ```
768
+
769
+ ### 4. Ractor-Based Processing Integration
770
+ ```ruby
771
+ class DatabaseMessageProcessor
772
+ def initialize(database_transport)
773
+ @transport = database_transport
774
+ @ractor_pool = RactorPool.new(size: 4)
775
+ end
776
+
777
+ def process_messages
778
+ messages = @transport.retrieve_messages(limit: 100)
779
+
780
+ messages.each do |message_data|
781
+ @ractor_pool.post(message_data) do |data|
782
+ # Process in isolated Ractor
783
+ process_single_message(data)
784
+ end
785
+ end
786
+ end
787
+ end
788
+ ```
789
+
790
+ ## Performance Characteristics
791
+
792
+ ### Benchmarking Scenarios
793
+
794
+ **Single Message Operations:**
795
+ - Individual INSERT: ~1-2ms per message
796
+ - Individual SELECT: ~0.5-1ms per message
797
+ - Network latency typically dominates
798
+
799
+ **Batch Operations:**
800
+ - Batch INSERT (100 messages): ~10-20ms total (10-20x improvement)
801
+ - Bulk UPDATE (marking processed): ~5-10ms for 100 messages
802
+ - Transaction overhead amortized across batch
803
+
804
+ **Query Performance:**
805
+ - Indexed entity routing: Sub-millisecond
806
+ - Priority ordering: ~1-2ms for large queues
807
+ - JSONB content filtering: ~2-5ms depending on complexity
808
+
809
+ ### Scalability Considerations
810
+ - **Read Replicas**: Route message retrieval to read replicas
811
+ - **Partitioning**: Partition by message_class or date for large volumes
812
+ - **Archival**: Move old processed messages to archive tables
813
+ - **Connection Pooling**: Scale with database connection limits
814
+
815
+ ## Configuration Options
816
+
817
+ ```ruby
818
+ # Database transport configuration
819
+ database_transport = SmartMessage::Transport.create(:database,
820
+ # Database connection
821
+ database_url: ENV['DATABASE_URL'],
822
+ connection_pool_size: 10,
823
+
824
+ # Batching configuration
825
+ enable_batching: true,
826
+ batch_size: 100,
827
+ batch_timeout: 5.seconds,
828
+
829
+ # Processing options
830
+ default_priority: 0,
831
+ enable_delayed_processing: true,
832
+
833
+ # Reliability options
834
+ max_processing_attempts: 3,
835
+ dead_letter_queue_enabled: true,
836
+
837
+ # Performance options
838
+ retrieval_limit: 100,
839
+ enable_content_routing: true
840
+ )
841
+ ```
842
+
843
+ ## Use Cases
844
+
845
+ ### 1. Financial Transactions
846
+ - **ACID Requirements**: Transaction messages must be durable
847
+ - **Audit Trail**: Regulatory compliance requires complete history
848
+ - **Guaranteed Delivery**: Payment processing cannot lose messages
849
+ - **Priority Processing**: High-value transactions get priority
850
+
851
+ ### 2. Order Processing Systems
852
+ - **State Persistence**: Order state changes must survive failures
853
+ - **Entity Routing**: Messages targeted to specific services
854
+ - **Delayed Processing**: Scheduled order fulfillment
855
+ - **Batch Efficiency**: High-volume order processing
856
+
857
+ ### 3. Notification Systems
858
+ - **Content Routing**: Different notification types to different handlers
859
+ - **Priority Levels**: Urgent notifications processed first
860
+ - **Delivery Guarantees**: Critical notifications must be delivered
861
+ - **Scheduling**: Time-based notification delivery
862
+
863
+ ### 4. Enterprise Integration
864
+ - **Multiple Systems**: Database provides universal messaging layer
865
+ - **Gateway Patterns**: Transform messages between different formats
866
+ - **Monitoring**: Complete visibility into message flow
867
+ - **Compliance**: Audit trails for regulatory requirements
868
+
869
+ ## Migration Strategy
870
+
871
+ ### Phase 1: Basic Implementation
872
+ 1. Create database schema
873
+ 2. Implement basic DatabaseTransport class
874
+ 3. Add to transport registry
875
+ 4. Create basic publish/subscribe functionality
876
+
877
+ ### Phase 2: Addressing Integration
878
+ 1. Add FROM/TO/REPLY_TO fields to schema
879
+ 2. Implement entity-specific routing
880
+ 3. Update dispatcher to handle database retrieval
881
+ 4. Add broadcast vs targeted message support
882
+
883
+ ### Phase 3: Advanced Features
884
+ 1. Implement batch processing
885
+ 2. Add priority and delayed processing
886
+ 3. Create dead letter queue functionality
887
+ 4. Add content-based routing
888
+
889
+ ### Phase 4: Performance & Reliability
890
+ 1. Optimize queries and indexes
891
+ 2. Add connection pooling
892
+ 3. Implement circuit breakers
893
+ 4. Add monitoring and metrics
894
+
895
+ ## Testing Strategy
896
+
897
+ ### Unit Tests
898
+ ```ruby
899
+ RSpec.describe SmartMessage::Transport::DatabaseTransport do
900
+ let(:transport) { described_class.new(database_url: test_db_url) }
901
+
902
+ describe '#publish' do
903
+ it 'stores message in database' do
904
+ header = create_header(from: 'service_a', to: 'service_b')
905
+ payload = '{"test": true}'
906
+
907
+ transport.publish(header, payload)
908
+
909
+ message = SmartMessage::DatabaseMessage.last
910
+ expect(message.from_entity).to eq('service_a')
911
+ expect(message.to_entity).to eq('service_b')
912
+ expect(message.payload).to eq('{"test": true}')
913
+ end
914
+ end
915
+
916
+ describe '#retrieve_messages' do
917
+ it 'returns messages for specific entity' do
918
+ create_message(to_entity: 'service_a')
919
+ create_message(to_entity: 'service_b')
920
+ create_message(to_entity: nil) # broadcast
921
+
922
+ messages = transport.retrieve_messages(entity_id: 'service_a')
923
+
924
+ expect(messages.count).to eq(2) # targeted + broadcast
925
+ end
926
+ end
927
+ end
928
+ ```
929
+
930
+ ### Integration Tests
931
+ ```ruby
932
+ RSpec.describe 'Database Transport Integration' do
933
+ it 'handles complete message lifecycle' do
934
+ # Setup message class with database transport
935
+ class TestMessage < SmartMessage::Base
936
+ property :data
937
+
938
+ config do
939
+ transport database_transport
940
+ serializer SmartMessage::Serializer::JSON.new
941
+ end
942
+
943
+ def self.process(header, payload)
944
+ # Processing logic
945
+ end
946
+ end
947
+
948
+ # Subscribe
949
+ TestMessage.subscribe
950
+
951
+ # Publish
952
+ message = TestMessage.new(data: 'test')
953
+ message.from = 'test_service'
954
+ message.publish
955
+
956
+ # Verify storage and processing
957
+ expect(SmartMessage::DatabaseMessage.count).to eq(1)
958
+
959
+ # Simulate processing
960
+ transport.process_pending_messages
961
+
962
+ db_message = SmartMessage::DatabaseMessage.last
963
+ expect(db_message.processed_at).not_to be_nil
964
+ end
965
+ end
966
+ ```
967
+
968
+ ## Conclusion
969
+
970
+ Database transports represent a **significant architectural enhancement** to SmartMessage, enabling:
971
+
972
+ 1. **Enterprise-grade reliability** through persistence and ACID guarantees
973
+ 2. **Advanced routing capabilities** through SQL-based filtering and entity targeting
974
+ 3. **High-performance batching** for throughput-intensive applications
975
+ 4. **Complete observability** through built-in audit trails and message history
976
+ 5. **Natural integration** with other planned improvements (addressing, circuit breakers, Ractors)
977
+
978
+ This positions SmartMessage as a production-ready messaging framework capable of handling mission-critical applications while maintaining the simplicity and elegance of the current API.
979
+
980
+ The database transport complements rather than replaces existing transports - Redis for speed, Memory for testing, Database for reliability and persistence.