smart_message 0.0.13 → 0.0.16

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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +120 -0
  4. data/Gemfile.lock +3 -3
  5. data/README.md +71 -25
  6. data/docs/index.md +2 -0
  7. data/docs/reference/transports.md +46 -21
  8. data/docs/transports/memory-transport.md +2 -1
  9. data/docs/transports/multi-transport.md +484 -0
  10. data/examples/file/00_run_all_file_demos.rb +260 -0
  11. data/examples/file/01_basic_file_transport_demo.rb +237 -0
  12. data/examples/file/02_fifo_transport_demo.rb +289 -0
  13. data/examples/file/03_file_watching_demo.rb +332 -0
  14. data/examples/file/04_multi_transport_file_demo.rb +432 -0
  15. data/examples/file/README.md +257 -0
  16. data/examples/memory/00_run_all_demos.rb +317 -0
  17. data/examples/memory/01_message_deduplication_demo.rb +18 -30
  18. data/examples/memory/02_dead_letter_queue_demo.rb +9 -9
  19. data/examples/memory/03_point_to_point_orders.rb +3 -3
  20. data/examples/memory/04_publish_subscribe_events.rb +15 -15
  21. data/examples/memory/05_many_to_many_chat.rb +19 -19
  22. data/examples/memory/06_stdout_publish_only.rb +145 -0
  23. data/examples/memory/07_proc_handlers_demo.rb +13 -13
  24. data/examples/memory/08_custom_logger_demo.rb +136 -136
  25. data/examples/memory/09_error_handling_demo.rb +7 -7
  26. data/examples/memory/10_entity_addressing_basic.rb +25 -25
  27. data/examples/memory/11_entity_addressing_with_filtering.rb +32 -32
  28. data/examples/memory/12_regex_filtering_microservices.rb +10 -10
  29. data/examples/memory/14_global_configuration_demo.rb +12 -12
  30. data/examples/memory/README.md +34 -17
  31. data/examples/memory/log/demo_app.log.1 +100 -0
  32. data/examples/memory/log/demo_app.log.2 +100 -0
  33. data/examples/multi_transport_example.rb +114 -0
  34. data/examples/redis/01_smart_home_iot_demo.rb +20 -20
  35. data/examples/utilities/box_it.rb +12 -0
  36. data/examples/utilities/doing.rb +19 -0
  37. data/examples/utilities/temp.md +28 -0
  38. data/lib/smart_message/base.rb +5 -7
  39. data/lib/smart_message/errors.rb +3 -0
  40. data/lib/smart_message/header.rb +1 -1
  41. data/lib/smart_message/logger/default.rb +1 -1
  42. data/lib/smart_message/messaging.rb +36 -6
  43. data/lib/smart_message/plugins.rb +46 -4
  44. data/lib/smart_message/serializer/base.rb +1 -1
  45. data/lib/smart_message/serializer.rb +3 -2
  46. data/lib/smart_message/subscription.rb +18 -20
  47. data/lib/smart_message/transport/async_publish_queue.rb +284 -0
  48. data/lib/smart_message/transport/fifo_operations.rb +264 -0
  49. data/lib/smart_message/transport/file_operations.rb +200 -0
  50. data/lib/smart_message/transport/file_transport.rb +149 -0
  51. data/lib/smart_message/transport/file_watching.rb +72 -0
  52. data/lib/smart_message/transport/partitioned_files.rb +46 -0
  53. data/lib/smart_message/transport/stdout_transport.rb +50 -36
  54. data/lib/smart_message/transport/stdout_transport.rb.backup +88 -0
  55. data/lib/smart_message/version.rb +1 -1
  56. metadata +24 -10
  57. data/ideas/README.md +0 -41
  58. data/ideas/agents.md +0 -1001
  59. data/ideas/database_transport.md +0 -980
  60. data/ideas/improvement.md +0 -359
  61. data/ideas/meshage.md +0 -1788
  62. data/ideas/message_discovery.md +0 -178
  63. data/ideas/message_schema.md +0 -1381
  64. data/lib/smart_message/wrapper.rb.bak +0 -132
  65. /data/examples/memory/{06_pretty_print_demo.rb → 16_pretty_print_demo.rb} +0 -0
@@ -0,0 +1,484 @@
1
+ # Multi-Transport Publishing
2
+
3
+ **Send messages to multiple transports simultaneously for redundancy, integration, and migration scenarios.**
4
+
5
+ SmartMessage supports configuring messages with multiple transports, enabling sophisticated messaging patterns where a single `publish()` operation can deliver messages across different transport systems simultaneously.
6
+
7
+ ## Overview
8
+
9
+ Multi-transport publishing allows you to:
10
+
11
+ - **Redundancy**: Send critical messages to primary and backup systems
12
+ - **Integration**: Simultaneously deliver to production queues and logging/monitoring systems
13
+ - **Migration**: Gradually transition between transport systems without downtime
14
+ - **Fan-out**: Broadcast messages to multiple processing pipelines
15
+ - **Resilience**: Ensure message delivery succeeds as long as ANY transport is available
16
+
17
+ ## Basic Configuration
18
+
19
+ Configure multiple transports by passing an array to the `transport` method:
20
+
21
+ ```ruby
22
+ class OrderProcessingMessage < SmartMessage::Base
23
+ property :order_id, required: true
24
+ property :customer_id, required: true
25
+ property :amount, required: true
26
+
27
+ # Configure multiple transports
28
+ transport [
29
+ SmartMessage::Transport.create(:redis_queue, url: 'redis://primary:6379'),
30
+ SmartMessage::Transport.create(:redis, url: 'redis://backup:6379'),
31
+ SmartMessage::Transport::StdoutTransport.new(format: :json)
32
+ ]
33
+ end
34
+
35
+ # Publishing sends to ALL configured transports
36
+ message = OrderProcessingMessage.new(
37
+ order_id: "ORD-12345",
38
+ customer_id: "CUST-789",
39
+ amount: 149.99
40
+ )
41
+
42
+ message.publish # ✅ Publishes to Redis Queue, Redis Pub/Sub, and STDOUT
43
+ ```
44
+
45
+ ## Transport Introspection
46
+
47
+ SmartMessage provides utility methods to inspect and manage transport configurations:
48
+
49
+ ```ruby
50
+ # Check transport configuration
51
+ puts message.multiple_transports? # => true
52
+ puts message.single_transport? # => false
53
+ puts message.transports.length # => 3
54
+
55
+ # Access individual transports
56
+ message.transports.each_with_index do |transport, index|
57
+ puts "Transport #{index}: #{transport.class.name}"
58
+ end
59
+
60
+ # Get primary transport (first in array) for backward compatibility
61
+ primary = message.transport # Returns first transport
62
+ ```
63
+
64
+ ## Instance-Level Overrides
65
+
66
+ You can override class-level multi-transport configuration at the instance level:
67
+
68
+ ```ruby
69
+ class MonitoringMessage < SmartMessage::Base
70
+ property :metric, required: true
71
+
72
+ # Class-level: send to monitoring and backup
73
+ transport [
74
+ SmartMessage::Transport.create(:redis, url: 'redis://monitoring:6379'),
75
+ SmartMessage::Transport.create(:redis, url: 'redis://backup:6379')
76
+ ]
77
+ end
78
+
79
+ # Instance-level override for testing
80
+ test_message = MonitoringMessage.new(metric: "cpu_usage: 85%")
81
+ test_message.transport(SmartMessage::Transport::StdoutTransport.new)
82
+
83
+ puts test_message.single_transport? # => true (overridden)
84
+ test_message.publish # Only goes to STDOUT
85
+ ```
86
+
87
+ ## Error Handling and Resilience
88
+
89
+ Multi-transport publishing is designed to be resilient:
90
+
91
+ ### Partial Failures
92
+
93
+ When some transports succeed and others fail, publishing continues:
94
+
95
+ ```ruby
96
+ class CriticalAlert < SmartMessage::Base
97
+ property :alert_text, required: true
98
+
99
+ transport [
100
+ ReliableTransport.new, # ✅ Succeeds
101
+ FailingTransport.new, # ❌ Fails
102
+ BackupTransport.new # ✅ Succeeds
103
+ ]
104
+ end
105
+
106
+ alert = CriticalAlert.new(alert_text: "Database connection lost")
107
+ alert.publish # ✅ Succeeds! 2 out of 3 transports work
108
+
109
+ # Logs will show:
110
+ # [INFO] Published: CriticalAlert via ReliableTransport, BackupTransport
111
+ # [WARN] Failed transports for CriticalAlert: FailingTransport
112
+ ```
113
+
114
+ ### Complete Failures
115
+
116
+ Only when ALL transports fail does publishing raise an error:
117
+
118
+ ```ruby
119
+ class AllFailingMessage < SmartMessage::Base
120
+ property :data
121
+
122
+ transport [
123
+ FailingTransport.new, # ❌ Fails
124
+ AnotherFailingTransport.new # ❌ Fails
125
+ ]
126
+ end
127
+
128
+ message = AllFailingMessage.new(data: "test")
129
+
130
+ begin
131
+ message.publish
132
+ rescue SmartMessage::Errors::PublishError => e
133
+ puts e.message # "All transports failed: FailingTransport: connection error; AnotherFailingTransport: timeout"
134
+ end
135
+ ```
136
+
137
+ ### Error Logging
138
+
139
+ Multi-transport publishing provides comprehensive error logging:
140
+
141
+ ```ruby
142
+ # Example log output during partial failure:
143
+ [DEBUG] About to call transport.publish on RedisTransport
144
+ [DEBUG] transport.publish completed on RedisTransport
145
+ [ERROR] Transport FailingTransport failed: StandardError - Connection timeout
146
+ [DEBUG] About to call transport.publish on StdoutTransport
147
+ [DEBUG] transport.publish completed on StdoutTransport
148
+ [INFO] Published: MyMessage via RedisTransport, StdoutTransport
149
+ [WARN] Failed transports for MyMessage: FailingTransport
150
+ ```
151
+
152
+ ## Common Use Cases
153
+
154
+ ### 1. High-Availability Critical Messages
155
+
156
+ Ensure critical business messages reach their destination even if primary systems fail:
157
+
158
+ ```ruby
159
+ class PaymentProcessedMessage < SmartMessage::Base
160
+ property :payment_id, required: true
161
+ property :amount, required: true
162
+ property :status, required: true
163
+
164
+ # Primary processing + backup + audit trail
165
+ transport [
166
+ SmartMessage::Transport.create(:redis_queue,
167
+ url: 'redis://primary-cluster:6379',
168
+ queue_prefix: 'payments'
169
+ ),
170
+ SmartMessage::Transport.create(:redis,
171
+ url: 'redis://backup-cluster:6380'
172
+ ),
173
+ SmartMessage::Transport::StdoutTransport.new(
174
+ output: '/var/log/payments.log',
175
+ format: :json
176
+ )
177
+ ]
178
+ end
179
+ ```
180
+
181
+ ### 2. Development and Production Dual Publishing
182
+
183
+ Send messages to both production and development environments during migration:
184
+
185
+ ```ruby
186
+ class UserRegistrationMessage < SmartMessage::Base
187
+ property :user_id, required: true
188
+ property :email, required: true
189
+
190
+ # Dual publishing during migration
191
+ transport [
192
+ SmartMessage::Transport.create(:redis,
193
+ url: ENV['PRODUCTION_REDIS_URL']
194
+ ),
195
+ SmartMessage::Transport.create(:redis_queue,
196
+ url: ENV['NEW_SYSTEM_REDIS_URL'],
197
+ queue_prefix: 'migration'
198
+ )
199
+ ]
200
+ end
201
+ ```
202
+
203
+ ### 3. Monitoring and Alerting Integration
204
+
205
+ Combine business processing with operational monitoring:
206
+
207
+ ```ruby
208
+ class OrderFailureMessage < SmartMessage::Base
209
+ property :order_id, required: true
210
+ property :error_message, required: true
211
+ property :customer_impact, required: true
212
+
213
+ transport [
214
+ # Business processing
215
+ SmartMessage::Transport.create(:redis_queue,
216
+ url: 'redis://orders:6379'
217
+ ),
218
+
219
+ # Operations monitoring
220
+ SmartMessage::Transport.create(:webhook,
221
+ url: 'https://monitoring.company.com/alerts'
222
+ ),
223
+
224
+ # Development debugging
225
+ SmartMessage::Transport::StdoutTransport.new(format: :pretty)
226
+ ]
227
+ end
228
+ ```
229
+
230
+ ### 4. A/B Testing and Feature Rollouts
231
+
232
+ Send messages to old and new systems during feature rollouts:
233
+
234
+ ```ruby
235
+ class AnalyticsEventMessage < SmartMessage::Base
236
+ property :event_type, required: true
237
+ property :user_id, required: true
238
+ property :metadata, default: {}
239
+
240
+ transport [
241
+ # Existing analytics pipeline (stable)
242
+ SmartMessage::Transport.create(:redis,
243
+ url: 'redis://analytics-v1:6379'
244
+ ),
245
+
246
+ # New analytics pipeline (testing)
247
+ SmartMessage::Transport.create(:redis_queue,
248
+ url: 'redis://analytics-v2:6379',
249
+ queue_prefix: 'beta'
250
+ )
251
+ ]
252
+ end
253
+ ```
254
+
255
+ ## Performance Considerations
256
+
257
+ ### Sequential Processing
258
+
259
+ Transports are processed sequentially in the order configured:
260
+
261
+ ```ruby
262
+ # Order matters for performance
263
+ transport [
264
+ FastMemoryTransport.new, # Processed first (fast)
265
+ SlowNetworkTransport.new, # Processed second (slow)
266
+ AnotherFastTransport.new # Processed third (waits for slow)
267
+ ]
268
+ ```
269
+
270
+ **Recommendation**: Place fastest/most critical transports first.
271
+
272
+ ### Transport Independence
273
+
274
+ Each transport failure is isolated and doesn't affect others:
275
+
276
+ ```ruby
277
+ transport [
278
+ ReliableTransport.new, # Always succeeds
279
+ UnreliableTransport.new, # May fail, doesn't affect others
280
+ BackupTransport.new # Provides redundancy
281
+ ]
282
+ ```
283
+
284
+ ### Memory Usage
285
+
286
+ Each transport instance maintains its own connection and state:
287
+
288
+ ```ruby
289
+ # Each transport creates its own connection pool
290
+ transport [
291
+ SmartMessage::Transport.create(:redis, url: 'redis://server1:6379'),
292
+ SmartMessage::Transport.create(:redis, url: 'redis://server2:6379'),
293
+ SmartMessage::Transport.create(:redis, url: 'redis://server3:6379')
294
+ ]
295
+ # Total: 3 Redis connection pools
296
+ ```
297
+
298
+ ## Best Practices
299
+
300
+ ### 1. Limit Transport Count
301
+
302
+ Don't configure excessive transports as this impacts performance:
303
+
304
+ ```ruby
305
+ # ✅ Good: 2-4 transports for specific purposes
306
+ transport [
307
+ PrimaryTransport.new,
308
+ BackupTransport.new,
309
+ MonitoringTransport.new
310
+ ]
311
+
312
+ # ❌ Avoid: Too many transports
313
+ transport [
314
+ Transport1.new, Transport2.new, Transport3.new,
315
+ Transport4.new, Transport5.new, Transport6.new # Overkill
316
+ ]
317
+ ```
318
+
319
+ ### 2. Group by Purpose
320
+
321
+ Organize transports by their intended purpose:
322
+
323
+ ```ruby
324
+ class BusinessMessage < SmartMessage::Base
325
+ transport [
326
+ # Core business processing
327
+ SmartMessage::Transport.create(:redis_queue, url: primary_redis_url),
328
+
329
+ # Operational monitoring
330
+ SmartMessage::Transport::StdoutTransport.new(
331
+ output: '/var/log/business-events.log'
332
+ ),
333
+
334
+ # Disaster recovery backup
335
+ SmartMessage::Transport.create(:redis, url: backup_redis_url)
336
+ ]
337
+ end
338
+ ```
339
+
340
+ ### 3. Environment-Specific Configuration
341
+
342
+ Use environment variables for transport configuration:
343
+
344
+ ```ruby
345
+ class ConfigurableMessage < SmartMessage::Base
346
+ transport_configs = []
347
+
348
+ # Always include primary transport
349
+ transport_configs << SmartMessage::Transport.create(:redis_queue,
350
+ url: ENV['PRIMARY_REDIS_URL']
351
+ )
352
+
353
+ # Add backup transport in production
354
+ if Rails.env.production?
355
+ transport_configs << SmartMessage::Transport.create(:redis,
356
+ url: ENV['BACKUP_REDIS_URL']
357
+ )
358
+ end
359
+
360
+ # Add stdout transport in development
361
+ if Rails.env.development?
362
+ transport_configs << SmartMessage::Transport::StdoutTransport.new
363
+ end
364
+
365
+ transport transport_configs
366
+ end
367
+ ```
368
+
369
+ ### 4. Health Monitoring
370
+
371
+ Monitor the health of your multi-transport setup:
372
+
373
+ ```ruby
374
+ class HealthCheckMessage < SmartMessage::Base
375
+ property :timestamp, default: -> { Time.now }
376
+
377
+ transport [
378
+ PrimaryTransport.new,
379
+ BackupTransport.new
380
+ ]
381
+
382
+ # Class method to check transport health
383
+ def self.health_check
384
+ test_message = new(timestamp: Time.now)
385
+
386
+ begin
387
+ test_message.publish
388
+ { status: 'healthy', transports: 'all_operational' }
389
+ rescue SmartMessage::Errors::PublishError => e
390
+ { status: 'degraded', error: e.message }
391
+ end
392
+ end
393
+ end
394
+ ```
395
+
396
+ ## Migration Strategies
397
+
398
+ ### Gradual Migration
399
+
400
+ When migrating from one transport to another:
401
+
402
+ ```ruby
403
+ class MigrationMessage < SmartMessage::Base
404
+
405
+ # Phase 1: Dual publishing
406
+ transport [
407
+ OldTransport.new, # Keep existing system running
408
+ NewTransport.new # Start sending to new system
409
+ ]
410
+
411
+ # Phase 2: Monitor and validate new system
412
+ # Phase 3: Remove old transport when confident
413
+ end
414
+ ```
415
+
416
+ ### Blue-Green Deployment
417
+
418
+ Support blue-green deployments with transport switching:
419
+
420
+ ```ruby
421
+ class DeploymentMessage < SmartMessage::Base
422
+ def self.configure_for_deployment(color)
423
+ case color
424
+ when :blue
425
+ transport BlueEnvironmentTransport.new
426
+ when :green
427
+ transport GreenEnvironmentTransport.new
428
+ when :both
429
+ transport [
430
+ BlueEnvironmentTransport.new,
431
+ GreenEnvironmentTransport.new
432
+ ]
433
+ end
434
+ end
435
+ end
436
+ ```
437
+
438
+ ## Troubleshooting
439
+
440
+ ### Common Issues
441
+
442
+ **Issue**: Publishing seems slow
443
+ ```ruby
444
+ # Check transport order - slow transports block subsequent ones
445
+ transport [
446
+ SlowTransport.new, # ❌ Blocks others
447
+ FastTransport.new # Must wait for slow one
448
+ ]
449
+
450
+ # Solution: Reorder with fastest first
451
+ transport [
452
+ FastTransport.new, # ✅ Completes quickly
453
+ SlowTransport.new # Others don't wait
454
+ ]
455
+ ```
456
+
457
+ **Issue**: Partial failures not logged
458
+ ```ruby
459
+ # Ensure proper logging configuration
460
+ SmartMessage.configure do |config|
461
+ config.logger.level = :debug # Show all transport operations
462
+ end
463
+ ```
464
+
465
+ **Issue**: All transports failing unexpectedly
466
+ ```ruby
467
+ # Test each transport individually
468
+ message.transports.each_with_index do |transport, index|
469
+ begin
470
+ transport.publish(message)
471
+ puts "Transport #{index} (#{transport.class.name}): ✅ Success"
472
+ rescue => e
473
+ puts "Transport #{index} (#{transport.class.name}): ❌ Failed - #{e.message}"
474
+ end
475
+ end
476
+ ```
477
+
478
+ ## See Also
479
+
480
+ - [Transport Layer Overview](../reference/transports.md)
481
+ - [Redis Queue Transport](redis-transport.md)
482
+ - [Memory Transport](memory-transport.md)
483
+ - [Error Handling and Dead Letter Queues](../reference/dead-letter-queue.md)
484
+ - [Performance Optimization](../development/performance.md)