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,889 @@
1
+ # Redis Queue Transport - Advanced Routing Patterns
2
+
3
+ This guide covers advanced routing patterns and use cases for the Redis Queue Transport, helping you implement sophisticated message routing architectures.
4
+
5
+ ## Pattern Syntax Reference
6
+
7
+ ### Wildcard Meanings
8
+
9
+ | Symbol | Matches | Examples |
10
+ |--------|---------|----------|
11
+ | `#` | Zero or more words | `#` matches `a`, `a.b`, `a.b.c` |
12
+ | `*` | Exactly one word | `*` matches `a` but not `a.b` |
13
+ | `.` | Word separator | Literal dot character |
14
+
15
+ ### Pattern Structure
16
+
17
+ All patterns follow the routing key format:
18
+ ```
19
+ namespace.message_type.from_uuid.to_uuid
20
+ ```
21
+
22
+ Common pattern examples:
23
+ - `#.*.service_name` - All messages TO service_name
24
+ - `#.sender.*` - All messages FROM sender
25
+ - `namespace.#.*.*` - All messages in namespace
26
+ - `#.#.#.broadcast` - All broadcast messages
27
+
28
+ ## Basic Routing Patterns
29
+
30
+ ### 1. Service-to-Service Communication
31
+
32
+ ```ruby
33
+ # API Gateway routing requests to services
34
+ transport = SmartMessage::Transport::RedisQueueTransport.new
35
+
36
+ class ServiceRequest < SmartMessage::Base
37
+ transport :redis_queue
38
+ property :service, required: true
39
+ property :operation, required: true
40
+ property :payload, default: {}
41
+ end
42
+
43
+ # Route to user service
44
+ transport.subscribe_pattern("#.*.user_service") do |msg_class, data|
45
+ request = JSON.parse(data)
46
+ puts "👤 User Service: #{request['operation']}"
47
+
48
+ case request['operation']
49
+ when 'create_user'
50
+ create_user(request['payload'])
51
+ when 'get_user'
52
+ get_user(request['payload']['user_id'])
53
+ end
54
+ end
55
+
56
+ # Route to payment service
57
+ transport.subscribe_pattern("#.*.payment_service") do |msg_class, data|
58
+ request = JSON.parse(data)
59
+ puts "💳 Payment Service: #{request['operation']}"
60
+
61
+ case request['operation']
62
+ when 'process_payment'
63
+ process_payment(request['payload'])
64
+ when 'refund_payment'
65
+ refund_payment(request['payload'])
66
+ end
67
+ end
68
+
69
+ # API Gateway publishes requests
70
+ ServiceRequest.new(
71
+ service: 'user_service',
72
+ operation: 'create_user',
73
+ payload: { name: 'John Doe', email: 'john@example.com' },
74
+ _sm_header: { from: 'api_gateway', to: 'user_service' }
75
+ ).publish
76
+ ```
77
+
78
+ ### 2. Event-Driven Architecture
79
+
80
+ ```ruby
81
+ # Domain events with smart routing
82
+ class OrderEvent < SmartMessage::Base
83
+ transport :redis_queue
84
+ property :event_type, required: true
85
+ property :order_id, required: true
86
+ property :data, default: {}
87
+ end
88
+
89
+ # Multiple services react to order events
90
+ class InventoryService
91
+ def self.start
92
+ transport = SmartMessage::Transport::RedisQueueTransport.new
93
+
94
+ # Listen for order events that affect inventory
95
+ transport.subscribe_pattern("order.#.*.*") do |msg_class, data|
96
+ event = JSON.parse(data)
97
+
98
+ case event['event_type']
99
+ when 'order_placed'
100
+ reserve_inventory(event['order_id'], event['data']['items'])
101
+ when 'order_cancelled'
102
+ release_inventory(event['order_id'])
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ class ShippingService
109
+ def self.start
110
+ transport = SmartMessage::Transport::RedisQueueTransport.new
111
+
112
+ # Listen for paid orders
113
+ transport.subscribe_pattern("order.#.payment_service.*") do |msg_class, data|
114
+ event = JSON.parse(data)
115
+
116
+ if event['event_type'] == 'payment_confirmed'
117
+ schedule_shipping(event['order_id'])
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ # Publish order events
124
+ OrderEvent.new(
125
+ event_type: 'order_placed',
126
+ order_id: 'ORD-123',
127
+ data: { items: [{ sku: 'BOOK-001', qty: 2 }], customer_id: 'CUST-456' },
128
+ _sm_header: { from: 'order_service', to: 'inventory_service' }
129
+ ).publish
130
+ ```
131
+
132
+ ### 3. Multi-Tenant Routing
133
+
134
+ ```ruby
135
+ # Tenant isolation through routing patterns
136
+ class TenantMessage < SmartMessage::Base
137
+ transport :redis_queue
138
+ property :tenant_id, required: true
139
+ property :data, required: true
140
+ end
141
+
142
+ class TenantService
143
+ def initialize(tenant_id)
144
+ @tenant_id = tenant_id
145
+ @transport = SmartMessage::Transport::RedisQueueTransport.new
146
+ setup_subscriptions
147
+ end
148
+
149
+ private
150
+
151
+ def setup_subscriptions
152
+ # Only receive messages for this tenant
153
+ pattern = "#.#{@tenant_id}_*.*"
154
+
155
+ @transport.subscribe_pattern(pattern) do |msg_class, data|
156
+ message = JSON.parse(data)
157
+ puts "🏢 Tenant #{@tenant_id} processing: #{msg_class}"
158
+ process_tenant_message(message)
159
+ end
160
+
161
+ # Admin broadcasts to all tenants
162
+ @transport.subscribe_pattern("#.admin.*.broadcast") do |msg_class, data|
163
+ message = JSON.parse(data)
164
+ puts "📢 Admin broadcast to tenant #{@tenant_id}: #{message['subject']}"
165
+ process_admin_broadcast(message)
166
+ end
167
+ end
168
+ end
169
+
170
+ # Start tenant services
171
+ tenant_1_service = TenantService.new('tenant_123')
172
+ tenant_2_service = TenantService.new('tenant_456')
173
+
174
+ # Publish tenant-specific messages
175
+ TenantMessage.new(
176
+ tenant_id: 'tenant_123',
177
+ data: { user_count: 50 },
178
+ _sm_header: { from: 'tenant_123_analytics', to: 'tenant_123_dashboard' }
179
+ ).publish
180
+
181
+ # Admin broadcast
182
+ AdminBroadcast.new(
183
+ subject: 'Scheduled maintenance tonight',
184
+ message: 'System will be down from 2-4 AM',
185
+ _sm_header: { from: 'admin', to: 'broadcast' }
186
+ ).publish
187
+ ```
188
+
189
+ ## Advanced Routing Scenarios
190
+
191
+ ### 4. Priority-Based Routing
192
+
193
+ ```ruby
194
+ # Priority-based message routing
195
+ class PriorityMessage < SmartMessage::Base
196
+ transport :redis_queue
197
+ property :priority, required: true # critical, high, normal, low
198
+ property :data, required: true
199
+ end
200
+
201
+ class PriorityRouter
202
+ def self.start
203
+ transport = SmartMessage::Transport::RedisQueueTransport.new
204
+
205
+ # Route based on priority in the FROM field
206
+ transport.subscribe_pattern("priority.#.*.*") do |msg_class, data|
207
+ message = JSON.parse(data)
208
+
209
+ target_service = case message['priority']
210
+ when 'critical'
211
+ 'critical_processor'
212
+ when 'high'
213
+ 'high_priority_processor'
214
+ else
215
+ 'normal_processor'
216
+ end
217
+
218
+ # Re-route to priority-specific service
219
+ PriorityMessage.new(
220
+ priority: message['priority'],
221
+ data: message['data'],
222
+ _sm_header: {
223
+ from: 'priority_router',
224
+ to: target_service
225
+ }
226
+ ).publish
227
+ end
228
+ end
229
+ end
230
+
231
+ # Priority-specific processors
232
+ class CriticalProcessor
233
+ def self.start
234
+ transport = SmartMessage::Transport::RedisQueueTransport.new
235
+
236
+ transport.subscribe_pattern("#.*.critical_processor") do |msg_class, data|
237
+ message = JSON.parse(data)
238
+ puts "🚨 CRITICAL: Processing #{message['data']} immediately"
239
+ # Process with highest priority
240
+ end
241
+ end
242
+ end
243
+
244
+ # Publish priority messages
245
+ PriorityMessage.new(
246
+ priority: 'critical',
247
+ data: { alert: 'System overload detected' },
248
+ _sm_header: { from: 'monitoring', to: 'priority_router' }
249
+ ).publish
250
+ ```
251
+
252
+ ### 5. Geographic Routing
253
+
254
+ ```ruby
255
+ # Geographic region-based routing
256
+ class GeographicMessage < SmartMessage::Base
257
+ transport :redis_queue
258
+ property :region, required: true # us-east, us-west, eu, asia
259
+ property :data, required: true
260
+ end
261
+
262
+ # Regional processors
263
+ class RegionalProcessor
264
+ def initialize(region)
265
+ @region = region
266
+ @transport = SmartMessage::Transport::RedisQueueTransport.new
267
+ setup_subscriptions
268
+ end
269
+
270
+ private
271
+
272
+ def setup_subscriptions
273
+ # Process messages for this region
274
+ pattern = "#.*.#{@region}_processor"
275
+
276
+ @transport.subscribe_pattern(pattern) do |msg_class, data|
277
+ message = JSON.parse(data)
278
+ puts "🌍 #{@region.upcase} processing: #{message['data']}"
279
+ process_regional_data(message['data'])
280
+ end
281
+
282
+ # Global broadcasts
283
+ @transport.subscribe_pattern("#.*.global") do |msg_class, data|
284
+ message = JSON.parse(data)
285
+ puts "🌎 Global message in #{@region}: #{message['data']}"
286
+ process_global_message(message['data'])
287
+ end
288
+ end
289
+ end
290
+
291
+ # Geographic router
292
+ class GeographicRouter
293
+ def self.start
294
+ transport = SmartMessage::Transport::RedisQueueTransport.new
295
+
296
+ transport.subscribe_pattern("geo.#.*.*") do |msg_class, data|
297
+ message = JSON.parse(data)
298
+
299
+ # Route to regional processor
300
+ target = "#{message['region']}_processor"
301
+
302
+ GeographicMessage.new(
303
+ region: message['region'],
304
+ data: message['data'],
305
+ _sm_header: {
306
+ from: 'geo_router',
307
+ to: target
308
+ }
309
+ ).publish
310
+ end
311
+ end
312
+ end
313
+
314
+ # Start regional processors
315
+ us_east = RegionalProcessor.new('us_east')
316
+ us_west = RegionalProcessor.new('us_west')
317
+ eu = RegionalProcessor.new('eu')
318
+ ```
319
+
320
+ ### 6. Content-Based Routing
321
+
322
+ ```ruby
323
+ # Route messages based on content analysis
324
+ class ContentRouter
325
+ def self.start
326
+ transport = SmartMessage::Transport::RedisQueueTransport.new
327
+
328
+ # Analyze incoming messages and route appropriately
329
+ transport.subscribe_pattern("content.#.*.*") do |msg_class, data|
330
+ message = JSON.parse(data)
331
+ content = message['content']
332
+
333
+ # Determine routing based on content
334
+ routes = analyze_content(content)
335
+
336
+ routes.each do |service|
337
+ RoutedMessage.new(
338
+ content: content,
339
+ analysis_result: routes,
340
+ _sm_header: {
341
+ from: 'content_router',
342
+ to: service
343
+ }
344
+ ).publish
345
+ end
346
+ end
347
+ end
348
+
349
+ private
350
+
351
+ def self.analyze_content(content)
352
+ routes = []
353
+
354
+ # Text analysis routing
355
+ if content.match?(/urgent|emergency|critical/i)
356
+ routes << 'alert_service'
357
+ end
358
+
359
+ if content.match?(/order|purchase|buy/i)
360
+ routes << 'sales_service'
361
+ end
362
+
363
+ if content.match?(/bug|error|issue/i)
364
+ routes << 'support_service'
365
+ end
366
+
367
+ if content.match?/@\w+/) # Contains mentions
368
+ routes << 'notification_service'
369
+ end
370
+
371
+ routes << 'archive_service' # Always archive
372
+ routes.uniq
373
+ end
374
+ end
375
+ ```
376
+
377
+ ### 7. Workflow Routing
378
+
379
+ ```ruby
380
+ # Multi-step workflow routing
381
+ class WorkflowStep < SmartMessage::Base
382
+ transport :redis_queue
383
+ property :workflow_id, required: true
384
+ property :step_number, required: true
385
+ property :data, required: true
386
+ property :next_step
387
+ end
388
+
389
+ class WorkflowEngine
390
+ WORKFLOWS = {
391
+ 'order_processing' => [
392
+ 'validate_order',
393
+ 'check_inventory',
394
+ 'process_payment',
395
+ 'ship_order',
396
+ 'send_confirmation'
397
+ ],
398
+ 'user_onboarding' => [
399
+ 'verify_email',
400
+ 'setup_profile',
401
+ 'send_welcome',
402
+ 'assign_trial'
403
+ ]
404
+ }.freeze
405
+
406
+ def self.start
407
+ transport = SmartMessage::Transport::RedisQueueTransport.new
408
+
409
+ # Listen for workflow completions
410
+ transport.subscribe_pattern("workflow.#.*.*") do |msg_class, data|
411
+ step = JSON.parse(data)
412
+ advance_workflow(step)
413
+ end
414
+ end
415
+
416
+ private
417
+
418
+ def self.advance_workflow(completed_step)
419
+ workflow_type = determine_workflow_type(completed_step['workflow_id'])
420
+ steps = WORKFLOWS[workflow_type]
421
+ current_index = steps.index(completed_step['step_type'])
422
+
423
+ if current_index && current_index < steps.length - 1
424
+ next_step = steps[current_index + 1]
425
+
426
+ WorkflowStep.new(
427
+ workflow_id: completed_step['workflow_id'],
428
+ step_number: current_index + 2,
429
+ data: completed_step['data'],
430
+ next_step: next_step,
431
+ _sm_header: {
432
+ from: 'workflow_engine',
433
+ to: "#{next_step}_service"
434
+ }
435
+ ).publish
436
+ else
437
+ # Workflow complete
438
+ WorkflowComplete.new(
439
+ workflow_id: completed_step['workflow_id'],
440
+ _sm_header: {
441
+ from: 'workflow_engine',
442
+ to: 'workflow_monitor'
443
+ }
444
+ ).publish
445
+ end
446
+ end
447
+ end
448
+ ```
449
+
450
+ ## Complex Pattern Combinations
451
+
452
+ ### 8. Multi-Criteria Routing
453
+
454
+ ```ruby
455
+ # Complex routing with multiple criteria
456
+ class ComplexRouter
457
+ def self.start
458
+ transport = SmartMessage::Transport::RedisQueueTransport.new
459
+
460
+ # Route based on multiple message attributes
461
+ setup_routing_rules(transport)
462
+ end
463
+
464
+ private
465
+
466
+ def self.setup_routing_rules(transport)
467
+ # Rule 1: Critical messages from admin go to operations
468
+ transport.subscribe_pattern("#.admin.*.#") do |msg_class, data|
469
+ message = JSON.parse(data)
470
+
471
+ if message['severity'] == 'critical'
472
+ route_to_operations(message)
473
+ end
474
+ end
475
+
476
+ # Rule 2: Payment messages go to compliance if amount > $10,000
477
+ transport.subscribe_pattern("payment.#.*.*") do |msg_class, data|
478
+ message = JSON.parse(data)
479
+
480
+ if message['amount'] && message['amount'] > 10000
481
+ route_to_compliance(message)
482
+ end
483
+ end
484
+
485
+ # Rule 3: Messages from EU customers go to GDPR processor
486
+ transport.subscribe_pattern("#.*.#") do |msg_class, data|
487
+ message = JSON.parse(data)
488
+
489
+ if eu_customer?(message['customer_data'])
490
+ route_to_gdpr_processor(message)
491
+ end
492
+ end
493
+
494
+ # Rule 4: Time-sensitive messages during business hours
495
+ transport.subscribe_pattern("#.*.#") do |msg_class, data|
496
+ message = JSON.parse(data)
497
+
498
+ if message['time_sensitive'] && business_hours?
499
+ route_to_priority_processor(message)
500
+ elsif message['time_sensitive']
501
+ route_to_delayed_processor(message)
502
+ end
503
+ end
504
+ end
505
+ end
506
+ ```
507
+
508
+ ### 9. Fan-out and Aggregation
509
+
510
+ ```ruby
511
+ # Fan-out pattern: One message to many processors
512
+ class FanOutMessage < SmartMessage::Base
513
+ transport :redis_queue
514
+ property :data, required: true
515
+ property :processors, required: true # Array of target processors
516
+ end
517
+
518
+ class FanOutRouter
519
+ def self.start
520
+ transport = SmartMessage::Transport::RedisQueueTransport.new
521
+
522
+ transport.subscribe_pattern("fanout.#.*.*") do |msg_class, data|
523
+ message = JSON.parse(data)
524
+
525
+ # Send to each specified processor
526
+ message['processors'].each do |processor|
527
+ ProcessingTask.new(
528
+ data: message['data'],
529
+ original_message_id: message['message_id'],
530
+ _sm_header: {
531
+ from: 'fanout_router',
532
+ to: processor
533
+ }
534
+ ).publish
535
+ end
536
+ end
537
+ end
538
+ end
539
+
540
+ # Aggregation pattern: Many results back to one
541
+ class AggregationCollector
542
+ def initialize
543
+ @results = {}
544
+ @transport = SmartMessage::Transport::RedisQueueTransport.new
545
+ setup_subscriptions
546
+ end
547
+
548
+ private
549
+
550
+ def setup_subscriptions
551
+ @transport.subscribe_pattern("#.*.aggregation_collector") do |msg_class, data|
552
+ result = JSON.parse(data)
553
+ collect_result(result)
554
+ end
555
+ end
556
+
557
+ def collect_result(result)
558
+ message_id = result['original_message_id']
559
+ @results[message_id] ||= []
560
+ @results[message_id] << result
561
+
562
+ # Check if we have all expected results
563
+ if all_results_collected?(message_id)
564
+ publish_aggregated_result(message_id, @results[message_id])
565
+ @results.delete(message_id)
566
+ end
567
+ end
568
+ end
569
+ ```
570
+
571
+ ### 10. Circuit Breaker Pattern with Routing
572
+
573
+ ```ruby
574
+ # Route around failing services
575
+ class CircuitBreakerRouter
576
+ def initialize
577
+ @circuit_states = {} # service_name => :closed | :open | :half_open
578
+ @failure_counts = {}
579
+ @last_failure_time = {}
580
+ @transport = SmartMessage::Transport::RedisQueueTransport.new
581
+ setup_routing
582
+ end
583
+
584
+ private
585
+
586
+ def setup_routing
587
+ # Monitor service health
588
+ @transport.subscribe_pattern("health.#.*.*") do |msg_class, data|
589
+ health_report = JSON.parse(data)
590
+ update_circuit_state(health_report['service'], health_report['status'])
591
+ end
592
+
593
+ # Route requests based on circuit state
594
+ @transport.subscribe_pattern("request.#.*.*") do |msg_class, data|
595
+ request = JSON.parse(data)
596
+ service = request['target_service']
597
+
598
+ case @circuit_states[service]
599
+ when :open
600
+ # Route to fallback or reject
601
+ route_to_fallback(request, service)
602
+ when :half_open
603
+ # Allow limited requests
604
+ if should_allow_request?(service)
605
+ route_to_service(request, service)
606
+ else
607
+ route_to_fallback(request, service)
608
+ end
609
+ else # :closed (healthy)
610
+ route_to_service(request, service)
611
+ end
612
+ end
613
+ end
614
+
615
+ def route_to_fallback(request, failed_service)
616
+ fallback_service = determine_fallback(failed_service)
617
+
618
+ if fallback_service
619
+ FallbackRequest.new(
620
+ original_service: failed_service,
621
+ request_data: request,
622
+ _sm_header: {
623
+ from: 'circuit_breaker_router',
624
+ to: fallback_service
625
+ }
626
+ ).publish
627
+ else
628
+ # No fallback available
629
+ ErrorResponse.new(
630
+ error: "Service #{failed_service} unavailable",
631
+ _sm_header: {
632
+ from: 'circuit_breaker_router',
633
+ to: request['callback_service']
634
+ }
635
+ ).publish
636
+ end
637
+ end
638
+ end
639
+ ```
640
+
641
+ ## Pattern Testing and Debugging
642
+
643
+ ### Pattern Validation
644
+
645
+ ```ruby
646
+ # Test pattern matching
647
+ class PatternTester
648
+ def self.test_pattern(pattern, test_keys)
649
+ transport = SmartMessage::Transport::RedisQueueTransport.new
650
+
651
+ puts "Testing pattern: #{pattern}"
652
+ puts "-" * 40
653
+
654
+ test_keys.each do |key|
655
+ matches = transport.send(:routing_key_matches_pattern?, key, pattern)
656
+ status = matches ? "✅ MATCH" : "❌ NO MATCH"
657
+ puts "#{status}: #{key}"
658
+ end
659
+
660
+ transport.disconnect
661
+ end
662
+ end
663
+
664
+ # Test cases
665
+ test_keys = [
666
+ 'order.ordermessage.api_gateway.payment_service',
667
+ 'user.usercreated.signup_service.notification_service',
668
+ 'alert.systemalert.monitoring.broadcast',
669
+ 'payment.paymentprocessed.payment_service.order_service'
670
+ ]
671
+
672
+ PatternTester.test_pattern("#.*.payment_service", test_keys)
673
+ PatternTester.test_pattern("order.#.*.*", test_keys)
674
+ PatternTester.test_pattern("#.#.#.broadcast", test_keys)
675
+ ```
676
+
677
+ ### Pattern Performance Analysis
678
+
679
+ ```ruby
680
+ # Analyze pattern matching performance
681
+ class PatternPerformance
682
+ def self.benchmark_patterns(patterns, test_keys, iterations = 1000)
683
+ transport = SmartMessage::Transport::RedisQueueTransport.new
684
+
685
+ patterns.each do |pattern|
686
+ start_time = Time.now
687
+
688
+ iterations.times do
689
+ test_keys.each do |key|
690
+ transport.send(:routing_key_matches_pattern?, key, pattern)
691
+ end
692
+ end
693
+
694
+ duration = Time.now - start_time
695
+ total_tests = iterations * test_keys.size
696
+ rate = total_tests / duration
697
+
698
+ puts "Pattern: #{pattern}"
699
+ puts " Tests: #{total_tests}"
700
+ puts " Time: #{duration.round(4)}s"
701
+ puts " Rate: #{rate.round(0)} matches/sec"
702
+ puts ""
703
+ end
704
+
705
+ transport.disconnect
706
+ end
707
+ end
708
+
709
+ patterns = [
710
+ "#.*.payment_service",
711
+ "order.#.*.*",
712
+ "#.api_gateway.*",
713
+ "#.#.#.broadcast"
714
+ ]
715
+
716
+ PatternPerformance.benchmark_patterns(patterns, test_keys)
717
+ ```
718
+
719
+ ### Routing Table Analysis
720
+
721
+ ```ruby
722
+ # Analyze routing efficiency
723
+ class RoutingAnalyzer
724
+ def self.analyze(transport)
725
+ routing_table = transport.routing_table
726
+
727
+ puts "📊 Routing Table Analysis"
728
+ puts "=" * 30
729
+
730
+ # Pattern complexity analysis
731
+ simple_patterns = 0
732
+ wildcard_patterns = 0
733
+ complex_patterns = 0
734
+
735
+ routing_table.each do |pattern, queues|
736
+ if pattern.include?('#') || pattern.include?('*')
737
+ if pattern.count('#') + pattern.count('*') > 2
738
+ complex_patterns += 1
739
+ else
740
+ wildcard_patterns += 1
741
+ end
742
+ else
743
+ simple_patterns += 1
744
+ end
745
+ end
746
+
747
+ puts "Pattern Types:"
748
+ puts " Simple: #{simple_patterns}"
749
+ puts " Wildcard: #{wildcard_patterns}"
750
+ puts " Complex: #{complex_patterns}"
751
+ puts ""
752
+
753
+ # Queue distribution
754
+ queue_counts = routing_table.values.map(&:size)
755
+ avg_queues = queue_counts.sum.to_f / queue_counts.size
756
+
757
+ puts "Queue Distribution:"
758
+ puts " Total patterns: #{routing_table.size}"
759
+ puts " Total queues: #{queue_counts.sum}"
760
+ puts " Avg queues/pattern: #{avg_queues.round(2)}"
761
+ puts " Max queues/pattern: #{queue_counts.max}"
762
+ puts ""
763
+
764
+ # Potential overlaps
765
+ overlapping_patterns = find_overlapping_patterns(routing_table.keys)
766
+ if overlapping_patterns.any?
767
+ puts "⚠️ Potentially overlapping patterns:"
768
+ overlapping_patterns.each do |pair|
769
+ puts " #{pair[0]} ↔ #{pair[1]}"
770
+ end
771
+ else
772
+ puts "✅ No overlapping patterns detected"
773
+ end
774
+ end
775
+
776
+ private
777
+
778
+ def self.find_overlapping_patterns(patterns)
779
+ overlaps = []
780
+
781
+ patterns.combination(2) do |p1, p2|
782
+ if patterns_might_overlap?(p1, p2)
783
+ overlaps << [p1, p2]
784
+ end
785
+ end
786
+
787
+ overlaps
788
+ end
789
+
790
+ def self.patterns_might_overlap?(p1, p2)
791
+ # Simple heuristic - both have wildcards in same positions
792
+ p1_parts = p1.split('.')
793
+ p2_parts = p2.split('.')
794
+
795
+ return false if p1_parts.size != p2_parts.size
796
+
797
+ p1_parts.zip(p2_parts).any? do |part1, part2|
798
+ (part1 == '#' || part1 == '*') && (part2 == '#' || part2 == '*')
799
+ end
800
+ end
801
+ end
802
+
803
+ # Analyze current routing
804
+ transport = SmartMessage::Transport::RedisQueueTransport.new
805
+ RoutingAnalyzer.analyze(transport)
806
+ ```
807
+
808
+ ## Best Practices for Pattern Design
809
+
810
+ ### 1. Pattern Hierarchy
811
+
812
+ ```ruby
813
+ # Organize patterns from specific to general
814
+ patterns = [
815
+ "emergency.alert.security.critical", # Most specific
816
+ "emergency.alert.security.*", # Department-specific
817
+ "emergency.alert.*.*", # Alert type-specific
818
+ "emergency.#.*.*", # Emergency namespace
819
+ "#.#.#.critical", # Priority-specific
820
+ "#.#.#.broadcast" # Broadcast messages
821
+ ]
822
+ ```
823
+
824
+ ### 2. Naming Conventions
825
+
826
+ ```ruby
827
+ # Use consistent naming patterns
828
+ PATTERN_CONVENTIONS = {
829
+ # Service routing
830
+ service_inbound: "#.*.{service_name}",
831
+ service_outbound: "#{service_name}.#.*.*",
832
+
833
+ # Event routing
834
+ domain_events: "#{domain}.#.*.*",
835
+ global_events: "#.#.#.broadcast",
836
+
837
+ # Priority routing
838
+ critical_messages: "#.#.#.critical",
839
+ urgent_messages: "#.#.#.urgent",
840
+
841
+ # Geographic routing
842
+ regional_messages: "#.*.{region}_*",
843
+ global_messages: "#.*.global"
844
+ }.freeze
845
+ ```
846
+
847
+ ### 3. Pattern Documentation
848
+
849
+ ```ruby
850
+ # Document your routing patterns
851
+ class RoutingDocumentation
852
+ PATTERNS = {
853
+ "#.*.payment_service" => {
854
+ description: "All messages directed to payment service",
855
+ use_case: "Payment processing requests from any source",
856
+ examples: [
857
+ "order.paymentrequest.api_gateway.payment_service",
858
+ "refund.refundrequest.customer_service.payment_service"
859
+ ],
860
+ performance: "High volume - ensure adequate consumers"
861
+ },
862
+
863
+ "emergency.#.*.*" => {
864
+ description: "All emergency messages regardless of routing",
865
+ use_case: "Emergency monitoring and logging",
866
+ examples: [
867
+ "emergency.fire.building_sensor.fire_department",
868
+ "emergency.medical.mobile_app.ambulance_service"
869
+ ],
870
+ performance: "Critical - requires immediate processing"
871
+ }
872
+ }.freeze
873
+
874
+ def self.document_pattern(pattern)
875
+ info = PATTERNS[pattern]
876
+ return unless info
877
+
878
+ puts "Pattern: #{pattern}"
879
+ puts "Description: #{info[:description]}"
880
+ puts "Use Case: #{info[:use_case]}"
881
+ puts "Examples:"
882
+ info[:examples].each { |ex| puts " - #{ex}" }
883
+ puts "Performance Notes: #{info[:performance]}"
884
+ puts ""
885
+ end
886
+ end
887
+ ```
888
+
889
+ Advanced routing patterns enable sophisticated message architectures that can adapt to complex business requirements while maintaining high performance and reliability. Use these patterns as building blocks to create messaging systems that scale with your application's needs.