smart_message 0.0.8 → 0.0.10

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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.irbrc +24 -0
  4. data/CHANGELOG.md +119 -0
  5. data/Gemfile.lock +6 -1
  6. data/README.md +389 -17
  7. data/docs/README.md +3 -1
  8. data/docs/addressing.md +119 -13
  9. data/docs/architecture.md +184 -46
  10. data/docs/dead_letter_queue.md +673 -0
  11. data/docs/dispatcher.md +87 -0
  12. data/docs/examples.md +59 -1
  13. data/docs/getting-started.md +8 -1
  14. data/docs/logging.md +382 -326
  15. data/docs/message_deduplication.md +488 -0
  16. data/docs/message_filtering.md +451 -0
  17. data/examples/01_point_to_point_orders.rb +54 -53
  18. data/examples/02_publish_subscribe_events.rb +14 -10
  19. data/examples/03_many_to_many_chat.rb +16 -8
  20. data/examples/04_redis_smart_home_iot.rb +20 -10
  21. data/examples/05_proc_handlers.rb +12 -11
  22. data/examples/06_custom_logger_example.rb +95 -100
  23. data/examples/07_error_handling_scenarios.rb +4 -2
  24. data/examples/08_entity_addressing_basic.rb +18 -6
  25. data/examples/08_entity_addressing_with_filtering.rb +27 -9
  26. data/examples/09_dead_letter_queue_demo.rb +559 -0
  27. data/examples/09_regex_filtering_microservices.rb +407 -0
  28. data/examples/10_header_block_configuration.rb +263 -0
  29. data/examples/10_message_deduplication.rb +209 -0
  30. data/examples/11_global_configuration_example.rb +219 -0
  31. data/examples/README.md +102 -0
  32. data/examples/dead_letters.jsonl +12 -0
  33. data/examples/performance_metrics/benchmark_results_ractor_20250818_205603.json +135 -0
  34. data/examples/performance_metrics/benchmark_results_ractor_20250818_205831.json +135 -0
  35. data/examples/performance_metrics/benchmark_results_test_20250818_204942.json +130 -0
  36. data/examples/performance_metrics/benchmark_results_threadpool_20250818_204942.json +130 -0
  37. data/examples/performance_metrics/benchmark_results_threadpool_20250818_204959.json +130 -0
  38. data/examples/performance_metrics/benchmark_results_threadpool_20250818_205044.json +130 -0
  39. data/examples/performance_metrics/benchmark_results_threadpool_20250818_205109.json +130 -0
  40. data/examples/performance_metrics/benchmark_results_threadpool_20250818_205252.json +130 -0
  41. data/examples/performance_metrics/benchmark_results_unknown_20250819_172852.json +130 -0
  42. data/examples/performance_metrics/compare_benchmarks.rb +519 -0
  43. data/examples/performance_metrics/dead_letters.jsonl +3100 -0
  44. data/examples/performance_metrics/performance_benchmark.rb +344 -0
  45. data/examples/show_logger.rb +367 -0
  46. data/examples/show_me.rb +145 -0
  47. data/examples/temp.txt +94 -0
  48. data/examples/tmux_chat/bot_agent.rb +4 -2
  49. data/examples/tmux_chat/human_agent.rb +4 -2
  50. data/examples/tmux_chat/room_monitor.rb +4 -2
  51. data/examples/tmux_chat/shared_chat_system.rb +6 -3
  52. data/lib/smart_message/addressing.rb +259 -0
  53. data/lib/smart_message/base.rb +123 -599
  54. data/lib/smart_message/circuit_breaker.rb +2 -1
  55. data/lib/smart_message/configuration.rb +199 -0
  56. data/lib/smart_message/ddq/base.rb +71 -0
  57. data/lib/smart_message/ddq/memory.rb +109 -0
  58. data/lib/smart_message/ddq/redis.rb +168 -0
  59. data/lib/smart_message/ddq.rb +31 -0
  60. data/lib/smart_message/dead_letter_queue.rb +27 -10
  61. data/lib/smart_message/deduplication.rb +174 -0
  62. data/lib/smart_message/dispatcher.rb +259 -61
  63. data/lib/smart_message/header.rb +5 -0
  64. data/lib/smart_message/logger/base.rb +21 -1
  65. data/lib/smart_message/logger/default.rb +88 -138
  66. data/lib/smart_message/logger/lumberjack.rb +324 -0
  67. data/lib/smart_message/logger/null.rb +81 -0
  68. data/lib/smart_message/logger.rb +17 -9
  69. data/lib/smart_message/messaging.rb +100 -0
  70. data/lib/smart_message/plugins.rb +132 -0
  71. data/lib/smart_message/serializer/base.rb +25 -8
  72. data/lib/smart_message/serializer/json.rb +5 -4
  73. data/lib/smart_message/subscription.rb +196 -0
  74. data/lib/smart_message/transport/base.rb +72 -41
  75. data/lib/smart_message/transport/memory_transport.rb +7 -5
  76. data/lib/smart_message/transport/redis_transport.rb +15 -45
  77. data/lib/smart_message/transport/stdout_transport.rb +18 -8
  78. data/lib/smart_message/transport.rb +1 -34
  79. data/lib/smart_message/utilities.rb +142 -0
  80. data/lib/smart_message/version.rb +1 -1
  81. data/lib/smart_message/versioning.rb +85 -0
  82. data/lib/smart_message/wrapper.rb.bak +132 -0
  83. data/lib/smart_message.rb +74 -28
  84. data/smart_message.gemspec +3 -0
  85. metadata +83 -3
  86. data/lib/smart_message/serializer.rb +0 -10
  87. data/lib/smart_message/wrapper.rb +0 -43
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e9fe12143456d1bc485554ad2d9f465a93e1d751860805bb2b5ee7496cccf031
4
- data.tar.gz: bf4a18a9506120da4283a091e7ee6b921d02a01696c07bec92217883bea4e330
3
+ metadata.gz: 8485ad851b6868c57b813977a4b2be3b1e06fe2843510a5b64c79468da3a65cf
4
+ data.tar.gz: 1c2345c52d1dd57202a83a49d3d4e7769f14b2855d0a08745d3ed4c970ef0f0e
5
5
  SHA512:
6
- metadata.gz: ad5f81928567ffdbc6a980b02777c2468804a7a4f248c4c7b34690942c356f69859f525aaef02b463a02b2dd1efe76e321194117e7730a28ac99257f501ee9a8
7
- data.tar.gz: 2bdab0d12acb85994e1121ef1308386f776bf36e08a086102cebdd9d1279198b2c89d9a160250ab9dca32e648305abffe0b32c87d63c2c5b4ec2ee43d77787d1
6
+ metadata.gz: 26cfdd1030e880074e557f7bc315220995b3267ec0a11fd4d0f621933e2101f40f35da425649388b83bf8055246934e6c9f8e60a281246e04e5cd89763c33e07
7
+ data.tar.gz: 25d66186e9ebe3f3fcf595e7093ec08c50db83d84205fcb4567b0c69804e44b80496693c40e36a0ea30b9f315a36d2070e701977bec6a0660f3c3bda327f1d88
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ /log/
1
2
  /*.log
2
3
  /.bundle/
3
4
  /.yardoc
data/.irbrc ADDED
@@ -0,0 +1,24 @@
1
+ # smart_message/.irbrc
2
+
3
+ require_relative './lib/smart_message'
4
+
5
+ SmartMessage.configure do |config|
6
+ config.logger = STDOUT
7
+ config.log_level = :info
8
+ config.log_format = :text
9
+ config.log_colorize = true
10
+ end
11
+
12
+ LOG = SmartMessage.configuration.default_logger
13
+
14
+ class TheMessage < SmartMessage::Base
15
+ version 3
16
+ description "my simple message"
17
+
18
+ header do
19
+ from 'dewayne'
20
+ to 'madbomber'
21
+ end
22
+
23
+ property :data, required: true
24
+ end
data/CHANGELOG.md CHANGED
@@ -7,6 +7,125 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.0.10] 2025-08-20
11
+ ### Added
12
+ - **Handler-Scoped Message Deduplication**: Advanced DDQ (Deduplication Queue) system with automatic handler isolation
13
+ - Handler-only DDQ scoping using `"MessageClass:HandlerMethod"` key format for natural isolation
14
+ - Automatic subscriber identification eliminates need for explicit `me:` parameter in API
15
+ - Cross-process deduplication support with independent DDQ instances per handler
16
+ - Memory and Redis storage backends with O(1) performance using hybrid Array + Set data structure
17
+ - Seamless integration with dispatcher - no changes required to existing subscription code
18
+ - Per-handler statistics and monitoring capabilities with DDQ utilization tracking
19
+ - Thread-safe circular buffer implementation with automatic eviction of oldest entries
20
+ - Configuration DSL: `ddq_size`, `ddq_storage`, `enable_deduplication!`, `disable_deduplication!`
21
+ - Comprehensive documentation and examples demonstrating distributed message processing scenarios
22
+
23
+ ### Fixed
24
+ - **Message Filtering Logic**: Fixed critical bug in subscription filtering where nil broadcast filters caused incorrect behavior
25
+ - **Root Cause**: `filters.key?(:broadcast)` returned true even when broadcast value was nil
26
+ - **Solution**: Changed condition to check for non-nil values: `filters[:to] || filters[:broadcast]`
27
+ - **Impact**: Subscription filtering now works correctly with nil filter values and maintains backward compatibility
28
+ - **Circuit Breaker Test Compatibility**: Added error handling for non-existent message classes in DDQ initialization
29
+ - Added rescue blocks around `constantize` calls to gracefully handle fake test classes
30
+ - DDQ initialization now skips gracefully for test classes that cannot be constantized
31
+ - Maintains proper DDQ functionality for real message classes while supporting test scenarios
32
+
33
+ ## [0.0.9] 2025-08-20
34
+ ### Added
35
+ - **Advanced Logging Configuration System**: Comprehensive logger configuration with multiple output formats and options
36
+ - New SmartMessage configuration options: `log_level`, `log_format`, `log_colorize`, `log_include_source`, `log_structured_data`, `log_options`
37
+ - Support for symbol-based log levels: `:info`, `:debug`, `:warn`, `:error`, `:fatal`
38
+ - Colorized console output with customizable color schemes using ANSI terminal colors
39
+ - File-based logging without colorization for clean log files
40
+ - JSON structured logging support with metadata inclusion
41
+ - Log rolling capabilities: size-based and date-based rolling with configurable retention
42
+ - Source location tracking for debugging (file, line number, method)
43
+ - Complete Lumberjack logger integration with SmartMessage configuration system
44
+ - New comprehensive logger demonstration: `examples/show_logger.rb`
45
+ - Application-level logger access through `SmartMessage.configuration.default_logger`
46
+ - **Transport Layer Abstraction**: Complete refactoring from legacy Broker to modern Transport architecture
47
+ - New `SmartMessage::Transport` module providing pluggable message delivery backends
48
+ - Transport registry system for dynamic plugin discovery and registration
49
+ - Base transport class with standardized interface for all implementations
50
+ - Memory, STDOUT, and Redis transport implementations with production-ready features
51
+ - File-based transport support for inter-process communication
52
+ - **Message Wrapper Architecture**: Unified message envelope system for cleaner dataflow
53
+ - New `SmartMessage::Wrapper::Base` class consolidating header and payload
54
+ - Simplified method signatures throughout message processing pipeline
55
+ - `_sm_` prefixed properties to avoid collision with user message definitions
56
+ - Support for different initialization patterns and automatic header generation
57
+ - **HeaderDSL for Configuration**: Simplified message class setup with declarative syntax
58
+ - New `SmartMessage::Addressing::HeaderDSL` providing cleaner class-level configuration
59
+ - Declarative `from`, `to`, `reply_to` methods for entity addressing
60
+ - Automatic header field configuration without boilerplate code
61
+ - **Advanced Message Filtering**: Regular expression support for flexible subscription patterns
62
+ - Regex pattern matching for `from:` and `to:` filters (e.g., `from: /^payment-.*/`)
63
+ - Array filters combining exact strings and patterns: `from: ['admin', /^system-.*/]`
64
+ - Environment-based routing patterns for dev/staging/production separation
65
+ - Service pattern routing for microservices architecture
66
+ - New example demonstrating regex filtering in microservices (`09_regex_filtering_microservices.rb`)
67
+ - **Performance Benchmarking Tools**: Comprehensive performance measurement infrastructure
68
+ - New benchmark suite comparing thread pool and Ractor implementations
69
+ - JSON-based benchmark result storage with detailed metrics
70
+ - Benchmark comparison tool for analyzing performance across runs
71
+ - Ractor-based message processing implementation for parallel execution
72
+ - **Improved Documentation Structure**: Complete documentation overhaul
73
+ - New modular documentation in `docs/` directory covering all major features
74
+ - Dedicated guides for transports, serializers, dispatcher, and filtering
75
+ - Architecture overview with component relationships
76
+ - Troubleshooting guide for common issues
77
+ - Example README with comprehensive usage patterns
78
+
79
+ ### Changed
80
+ - **BREAKING: Transport API Migration**: Complete replacement of Broker with Transport
81
+ - All `broker` references must be updated to `transport`
82
+ - `SmartMessage::Broker` removed in favor of `SmartMessage::Transport`
83
+ - Transport implementations now in `lib/smart_message/transport/` directory
84
+ - Updated all examples and tests to use new transport terminology
85
+ - **Simplified Module Structure**: Cleaner separation of concerns
86
+ - Extracted addressing logic into `SmartMessage::Addressing` module
87
+ - Separated messaging functionality into `SmartMessage::Messaging` module
88
+ - Created dedicated `SmartMessage::Plugins` module for plugin management
89
+ - Moved versioning logic to `SmartMessage::Versioning` module
90
+ - Utilities consolidated in `SmartMessage::Utilities` module
91
+ - **Enhanced Error Messages**: More descriptive error handling throughout
92
+ - Improved header validation error messages with context
93
+ - Better transport registration error reporting
94
+ - Clearer serialization failure messages
95
+
96
+ ### Fixed
97
+ - **Message Processing Simplification**: Removed unnecessary complexity in message wrapper
98
+ - Eliminated redundant processing steps in wrapper initialization
99
+ - Streamlined header and payload handling
100
+ - Fixed potential race conditions in concurrent message processing
101
+ - **Header Method Handling**: Improved reliability of header field access
102
+ - Fixed edge cases in header method delegation
103
+ - Ensured consistent behavior across all header field operations
104
+ - Better error messages for invalid header operations
105
+
106
+ ### Enhanced
107
+ - **Developer Experience**: Significant improvements to API usability
108
+ - More intuitive transport registration and discovery
109
+ - Cleaner message class definition with HeaderDSL
110
+ - Simplified subscription syntax with powerful filtering
111
+ - Better separation between framework internals and user code
112
+ - **Testing Infrastructure**: Expanded test coverage
113
+ - New tests for transport layer abstraction
114
+ - Comprehensive filtering tests including regex patterns
115
+ - Performance benchmark test suite
116
+ - Proc handler integration tests
117
+ - **Example Programs**: Enhanced educational value
118
+ - Added performance benchmarking examples
119
+ - New regex filtering demonstration for microservices
120
+ - Dead letter queue demonstration with retry scenarios
121
+ - Updated all examples to use modern transport architecture
122
+
123
+ ### Deprecated
124
+ - **Broker System**: Legacy broker implementation marked for removal
125
+ - `SmartMessage::Broker` and all subclasses deprecated
126
+ - Migration path provided through transport layer
127
+ - Broker terminology replaced with transport throughout codebase
128
+
10
129
  ## [0.0.8] 2025-08-19
11
130
 
12
131
  ### Added
data/Gemfile.lock CHANGED
@@ -1,12 +1,15 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- smart_message (0.0.7)
4
+ smart_message (0.0.10)
5
5
  activesupport
6
6
  breaker_machines
7
+ colorize
7
8
  concurrent-ruby
8
9
  hashie
10
+ lumberjack
9
11
  redis
12
+ zeitwerk
10
13
 
11
14
  GEM
12
15
  remote: https://rubygems.org/
@@ -33,6 +36,7 @@ GEM
33
36
  concurrent-ruby (~> 1.3)
34
37
  state_machines (>= 0.50.0)
35
38
  zeitwerk (~> 2.7)
39
+ colorize (1.1.0)
36
40
  concurrent-ruby (1.3.5)
37
41
  connection_pool (2.5.3)
38
42
  debug_me (1.1.1)
@@ -41,6 +45,7 @@ GEM
41
45
  i18n (1.14.7)
42
46
  concurrent-ruby (~> 1.0)
43
47
  logger (1.7.0)
48
+ lumberjack (1.4.0)
44
49
  minitest (5.25.5)
45
50
  minitest-power_assert (0.3.1)
46
51
  minitest
data/README.md CHANGED
@@ -10,15 +10,20 @@ SmartMessage is a message abstraction framework that decouples business logic fr
10
10
  - **Transport Abstraction**: Plugin architecture supporting multiple message transports (Redis, RabbitMQ, Kafka, etc.)
11
11
  - **Serialization Flexibility**: Pluggable serialization formats (JSON, MessagePack, etc.)
12
12
  - **Entity-to-Entity Addressing**: Built-in FROM/TO/REPLY_TO addressing for point-to-point and broadcast messaging patterns
13
+ - **Advanced Message Filtering**: Filter subscriptions using exact strings, regular expressions, or mixed arrays for precise message routing
13
14
  - **Schema Versioning**: Built-in version management with automatic compatibility validation
14
15
  - **Comprehensive Validation**: Property validation with custom error messages and automatic validation before publishing
15
16
  - **Message Documentation**: Built-in documentation support for message classes and properties with automatic defaults
16
17
  - **Flexible Message Handlers**: Multiple subscription patterns - default methods, custom methods, blocks, procs, and lambdas
17
18
  - **Dual-Level Configuration**: Class and instance-level plugin overrides for gateway patterns
18
19
  - **Concurrent Processing**: Thread-safe message routing using `Concurrent::CachedThreadPool`
20
+ - **Advanced Logging System**: Comprehensive logging with colorized console output, JSON structured logging, and file rolling
19
21
  - **Built-in Statistics**: Message processing metrics and monitoring
22
+ - **Message Deduplication**: Handler-scoped deduplication queues (DDQ) with memory or Redis storage for preventing duplicate message processing
20
23
  - **Development Tools**: STDOUT and in-memory transports for testing
21
24
  - **Production Ready**: Redis transport with automatic reconnection and error handling
25
+ - **Dead Letter Queue**: File-based DLQ with JSON Lines format for failed message capture and replay
26
+ - **Circuit Breaker Integration**: Production-grade reliability with BreakerMachines for automatic fallback and recovery
22
27
 
23
28
  ## Installation
24
29
 
@@ -48,11 +53,18 @@ class OrderMessage < SmartMessage::Base
48
53
  # Add a description for the message class
49
54
  description "Represents customer order data for processing and fulfillment"
50
55
 
51
- # Configure entity addressing
56
+ # Configure entity addressing (Method 1: Direct methods)
52
57
  from 'order-service'
53
58
  to 'fulfillment-service' # Point-to-point message
54
59
  reply_to 'order-service' # Responses come back here
55
60
 
61
+ # Alternative Method 2: Using header block
62
+ # header do
63
+ # from 'order-service'
64
+ # to 'fulfillment-service'
65
+ # reply_to 'order-service'
66
+ # end
67
+
56
68
  # Required properties with validation
57
69
  property :order_id,
58
70
  required: true,
@@ -159,12 +171,139 @@ end
159
171
  OrderMessage.subscribe(audit_handler)
160
172
  ```
161
173
 
162
- ### 4. Entity Addressing
174
+ ### 4. Message Filtering (NEW!)
175
+
176
+ SmartMessage supports powerful message filtering using exact strings, regular expressions, or arrays:
177
+
178
+ ```ruby
179
+ # Filter by exact sender
180
+ OrderMessage.subscribe(from: 'payment-service')
181
+
182
+ # Filter by sender pattern (all payment services)
183
+ OrderMessage.subscribe(from: /^payment-.*/)
184
+
185
+ # Filter by multiple senders
186
+ OrderMessage.subscribe(from: ['admin', 'system', 'monitoring'])
187
+
188
+ # Mixed exact and pattern matching
189
+ OrderMessage.subscribe(from: ['admin', /^system-.*/, 'legacy-service'])
190
+
191
+ # Filter by recipient patterns
192
+ OrderMessage.subscribe(to: /^(dev|staging)-.*/)
193
+
194
+ # Combined filtering
195
+ OrderMessage.subscribe(
196
+ from: /^admin-.*/,
197
+ to: ['order-service', /^fulfillment-.*/]
198
+ )
199
+
200
+ # Environment-based routing
201
+ DevService.subscribe(to: /^(dev|staging)-.*/)
202
+ ProdService.subscribe(to: /^prod-.*/)
203
+ ```
204
+
205
+ ### 5. Message Deduplication
206
+
207
+ SmartMessage provides handler-scoped message deduplication to prevent duplicate processing of messages with the same UUID. Each handler gets its own Deduplication Queue (DDQ) that tracks recently processed message UUIDs.
208
+
209
+ #### Basic Deduplication Setup
210
+
211
+ ```ruby
212
+ class OrderMessage < SmartMessage::Base
213
+ version 1
214
+ property :order_id, required: true
215
+ property :amount, required: true
216
+
217
+ from "order-service"
218
+
219
+ # Configure deduplication
220
+ ddq_size 100 # Track last 100 message UUIDs
221
+ ddq_storage :memory # Use memory storage (or :redis for distributed)
222
+ enable_deduplication! # Enable deduplication for this message class
223
+
224
+ def self.process(message)
225
+ puts "Processing order: #{message.order_id}"
226
+ # Business logic here
227
+ end
228
+ end
229
+ ```
230
+
231
+ #### Handler-Scoped Isolation
232
+
233
+ Each handler gets its own DDQ scope, preventing cross-contamination between different subscribers:
234
+
235
+ ```ruby
236
+ # Each handler gets separate deduplication tracking
237
+ OrderMessage.subscribe('PaymentService.process') # DDQ: "OrderMessage:PaymentService.process"
238
+ OrderMessage.subscribe('FulfillmentService.handle') # DDQ: "OrderMessage:FulfillmentService.handle"
239
+ OrderMessage.subscribe('AuditService.log_order') # DDQ: "OrderMessage:AuditService.log_order"
240
+
241
+ # Same handler across message classes = separate DDQs
242
+ PaymentMessage.subscribe('PaymentService.process') # DDQ: "PaymentMessage:PaymentService.process"
243
+ InvoiceMessage.subscribe('PaymentService.process') # DDQ: "InvoiceMessage:PaymentService.process"
244
+ ```
245
+
246
+ #### Storage Options
247
+
248
+ ```ruby
249
+ # Memory-based DDQ (single process)
250
+ class LocalMessage < SmartMessage::Base
251
+ ddq_size 50
252
+ ddq_storage :memory
253
+ enable_deduplication!
254
+ end
255
+
256
+ # Redis-based DDQ (distributed/multi-process)
257
+ class DistributedMessage < SmartMessage::Base
258
+ ddq_size 1000
259
+ ddq_storage :redis, redis_url: 'redis://localhost:6379', redis_db: 1
260
+ enable_deduplication!
261
+ end
262
+ ```
263
+
264
+ #### DDQ Statistics and Management
265
+
266
+ ```ruby
267
+ # Check deduplication configuration
268
+ config = OrderMessage.ddq_config
269
+ puts "Enabled: #{config[:enabled]}"
270
+ puts "Size: #{config[:size]}"
271
+ puts "Storage: #{config[:storage]}"
272
+
273
+ # Get DDQ statistics
274
+ stats = OrderMessage.ddq_stats
275
+ puts "Current count: #{stats[:current_count]}"
276
+ puts "Utilization: #{stats[:utilization]}%"
277
+
278
+ # Clear DDQ if needed
279
+ OrderMessage.clear_ddq!
280
+
281
+ # Check if specific UUID is duplicate
282
+ OrderMessage.duplicate_uuid?("some-uuid-123")
283
+ ```
284
+
285
+ #### How Deduplication Works
286
+
287
+ 1. **Message Receipt**: When a message arrives, the dispatcher checks the handler's DDQ for the message UUID
288
+ 2. **Duplicate Detection**: If UUID exists in DDQ, the message is ignored (logged but not processed)
289
+ 3. **Processing**: If UUID is new, the message is processed by the handler
290
+ 4. **UUID Storage**: After successful processing, the UUID is added to the handler's DDQ
291
+ 5. **Circular Buffer**: When DDQ reaches capacity, oldest UUIDs are evicted to make room for new ones
292
+
293
+ #### Benefits
294
+
295
+ - **Handler Isolation**: Each handler maintains independent deduplication state
296
+ - **Cross-Process Support**: Redis DDQ enables deduplication across multiple processes
297
+ - **Memory Efficient**: Circular buffer with configurable size limits memory usage
298
+ - **High Performance**: O(1) UUID lookup using hybrid array + set data structure
299
+ - **Automatic Integration**: Seamlessly works with existing subscription patterns
300
+
301
+ ### 6. Entity Addressing
163
302
 
164
- SmartMessage supports entity-to-entity addressing with FROM/TO/REPLY_TO fields for advanced message routing:
303
+ SmartMessage supports entity-to-entity addressing with FROM/TO/REPLY_TO fields for advanced message routing. You can configure addressing using three different approaches:
165
304
 
305
+ #### Method 1: Direct Class Methods
166
306
  ```ruby
167
- # Point-to-point messaging
168
307
  class PaymentMessage < SmartMessage::Base
169
308
  version 1
170
309
  from 'payment-service' # Required: sender identity
@@ -174,26 +313,67 @@ class PaymentMessage < SmartMessage::Base
174
313
  property :amount, required: true
175
314
  property :account_id, required: true
176
315
  end
316
+ ```
177
317
 
178
- # Broadcast messaging (no 'to' specified)
179
- class SystemAnnouncementMessage < SmartMessage::Base
318
+ #### Method 2: Header Block DSL
319
+ ```ruby
320
+ class PaymentMessage < SmartMessage::Base
180
321
  version 1
181
- from 'admin-service' # Required: sender identity
182
- # No 'to' field = broadcast to all subscribers
183
322
 
184
- property :message, required: true
185
- property :priority, default: 'normal'
323
+ # Configure all addressing in a single block
324
+ header do
325
+ from 'payment-service'
326
+ to 'bank-gateway'
327
+ reply_to 'payment-service'
328
+ end
329
+
330
+ property :amount, required: true
331
+ property :account_id, required: true
186
332
  end
333
+ ```
187
334
 
188
- # Instance-level addressing override
335
+ #### Method 3: Instance-Level Configuration
336
+ ```ruby
337
+
338
+ # Create payment instance
189
339
  payment = PaymentMessage.new(amount: 100.00, account_id: "ACCT-123")
190
- payment.to('backup-gateway') # Override destination for this instance
191
- payment.publish
192
340
 
193
- # Access addressing information
194
- puts payment._sm_header.from # => 'payment-service'
341
+ # Override addressing at instance level
342
+ payment.to('backup-gateway') # Method chaining supported
343
+ payment.from('urgent-processor')
344
+
345
+ # Alternative setter syntax
346
+ payment.from = 'urgent-processor'
347
+ payment.to = 'backup-gateway'
348
+
349
+ # Access addressing (shortcut methods)
350
+ puts payment.from # => 'urgent-processor'
351
+ puts payment.to # => 'backup-gateway'
352
+ puts payment.reply_to # => 'payment-service'
353
+
354
+ # Access via header (full path)
355
+ puts payment._sm_header.from # => 'urgent-processor'
195
356
  puts payment._sm_header.to # => 'backup-gateway'
196
357
  puts payment._sm_header.reply_to # => 'payment-service'
358
+
359
+ # Publish with updated addressing
360
+ payment.publish
361
+ ```
362
+
363
+ #### Broadcast Messaging Example
364
+ ```ruby
365
+ class SystemAnnouncementMessage < SmartMessage::Base
366
+ version 1
367
+
368
+ # Using header block for broadcast configuration
369
+ header do
370
+ from 'admin-service' # Required: sender identity
371
+ # No 'to' field = broadcast to all subscribers
372
+ end
373
+
374
+ property :message, required: true
375
+ property :priority, default: 'normal'
376
+ end
197
377
  ```
198
378
 
199
379
  #### Messaging Patterns Supported
@@ -203,6 +383,104 @@ puts payment._sm_header.reply_to # => 'payment-service'
203
383
  - **Request-Reply**: Use `reply_to` field to specify response routing
204
384
  - **Gateway Patterns**: Override addressing at instance level for message forwarding
205
385
 
386
+ ## Logging Configuration
387
+
388
+ SmartMessage includes a comprehensive logging system with support for multiple output formats, colorization, and file rolling capabilities.
389
+
390
+ ### Basic Logging Configuration
391
+
392
+ ```ruby
393
+ # Configure SmartMessage logging
394
+ SmartMessage.configure do |config|
395
+ config.logger = STDOUT # Output destination (file path, STDOUT, STDERR)
396
+ config.log_level = :info # Log level (:debug, :info, :warn, :error, :fatal)
397
+ config.log_format = :text # Output format (:text, :json)
398
+ config.log_colorize = true # Enable colorized console output
399
+ config.log_include_source = false # Include source file/line information
400
+ config.log_structured_data = false # Enable structured data logging
401
+ end
402
+
403
+ # Access the configured logger in your application
404
+ logger = SmartMessage.configuration.default_logger
405
+ logger.info("Application started", component: "main", pid: Process.pid)
406
+ ```
407
+
408
+ ### Advanced Logging Features
409
+
410
+ #### Colorized Console Output
411
+ ```ruby
412
+ SmartMessage.configure do |config|
413
+ config.logger = STDOUT
414
+ config.log_colorize = true
415
+ config.log_format = :text
416
+ end
417
+
418
+ logger = SmartMessage.configuration.default_logger
419
+ logger.debug("Debug message") # Green background, white text
420
+ logger.info("Info message") # White text
421
+ logger.warn("Warning message") # Yellow background, white bold text
422
+ logger.error("Error message") # Light red background, white bold text
423
+ logger.fatal("Fatal message") # Light red background, yellow bold text
424
+ ```
425
+
426
+ #### JSON Structured Logging
427
+ ```ruby
428
+ SmartMessage.configure do |config|
429
+ config.logger = "log/application.log"
430
+ config.log_format = :json
431
+ config.log_structured_data = true
432
+ config.log_include_source = true
433
+ end
434
+
435
+ logger = SmartMessage.configuration.default_logger
436
+ logger.info("User action",
437
+ user_id: 12345,
438
+ action: "login",
439
+ ip_address: "192.168.1.1")
440
+ # Output: {"timestamp":"2025-01-15T10:30:45.123Z","level":"INFO","message":"User action","user_id":12345,"action":"login","ip_address":"192.168.1.1","source":"app.rb:42:in `authenticate`"}
441
+ ```
442
+
443
+ #### File Rolling Configuration
444
+ ```ruby
445
+ SmartMessage.configure do |config|
446
+ config.logger = "log/application.log"
447
+ config.log_options = {
448
+ # Size-based rolling
449
+ roll_by_size: true,
450
+ max_file_size: 10 * 1024 * 1024, # 10 MB
451
+ keep_files: 5, # Keep 5 old files
452
+
453
+ # Date-based rolling (alternative to size-based)
454
+ roll_by_date: false, # Set to true for date-based
455
+ date_pattern: '%Y-%m-%d' # Daily rolling pattern
456
+ }
457
+ end
458
+ ```
459
+
460
+ ### SmartMessage Integration
461
+
462
+ SmartMessage classes automatically use the configured logger:
463
+
464
+ ```ruby
465
+ class OrderMessage < SmartMessage::Base
466
+ property :order_id, required: true
467
+ property :amount, required: true
468
+
469
+ def process
470
+ # Logger is automatically available
471
+ logger.info("Processing order",
472
+ order_id: order_id,
473
+ amount: amount,
474
+ header: _sm_header.to_h,
475
+ payload: _sm_payload)
476
+ end
477
+ end
478
+
479
+ # Messages inherit the global logger configuration
480
+ message = OrderMessage.new(order_id: "123", amount: 99.99)
481
+ message.publish # Uses configured logger for any internal logging
482
+ ```
483
+
206
484
  ## Architecture
207
485
 
208
486
  ### Core Components
@@ -231,9 +509,10 @@ Pluggable message encoding/decoding:
231
509
  #### Dispatcher
232
510
  Concurrent message routing engine that:
233
511
  - Uses thread pools for async processing
234
- - Routes messages to subscribed handlers
235
- - Provides processing statistics
512
+ - Routes messages to subscribed handlers with handler-scoped deduplication
513
+ - Provides processing statistics and DDQ management
236
514
  - Handles graceful shutdown
515
+ - Maintains separate DDQ instances per handler for isolated deduplication tracking
237
516
 
238
517
  ### Plugin Architecture
239
518
 
@@ -644,6 +923,99 @@ puts message._sm_header.to
644
923
  puts message._sm_header.reply_to
645
924
  ```
646
925
 
926
+ ### Dead Letter Queue
927
+
928
+ SmartMessage includes a comprehensive file-based Dead Letter Queue system for handling failed messages:
929
+
930
+ ```ruby
931
+ # Configure global DLQ (optional - defaults to 'dead_letters.jsonl')
932
+ SmartMessage::DeadLetterQueue.configure_default('/var/log/app/dlq.jsonl')
933
+
934
+ # Or use environment-based configuration
935
+ SmartMessage::DeadLetterQueue.configure_default(
936
+ ENV.fetch('SMART_MESSAGE_DLQ_PATH', 'dead_letters.jsonl')
937
+ )
938
+
939
+ # Access the default DLQ instance
940
+ dlq = SmartMessage::DeadLetterQueue.default
941
+
942
+ # Create a custom DLQ instance for specific needs
943
+ custom_dlq = SmartMessage::DeadLetterQueue.new('/tmp/critical_failures.jsonl')
944
+ ```
945
+
946
+ #### DLQ Operations
947
+
948
+ ```ruby
949
+ # Messages are automatically captured when circuit breakers trip
950
+ # But you can also manually enqueue failed messages:
951
+ dlq.enqueue(
952
+ message._sm_header,
953
+ message_payload,
954
+ error: "Connection timeout",
955
+ transport: "Redis",
956
+ retry_count: 3
957
+ )
958
+
959
+ # Inspect queue status
960
+ puts "Queue size: #{dlq.size}"
961
+ puts "Next message: #{dlq.peek}" # Look without removing
962
+
963
+ # Get statistics
964
+ stats = dlq.statistics
965
+ puts "Total messages: #{stats[:total]}"
966
+ puts "By error type: #{stats[:by_error]}"
967
+ puts "By message class: #{stats[:by_class]}"
968
+ ```
969
+
970
+ #### Message Replay
971
+
972
+ ```ruby
973
+ # Replay messages back through their original transport
974
+ dlq.replay_one # Replay oldest message
975
+ dlq.replay_batch(10) # Replay next 10 messages
976
+ dlq.replay_all # Replay entire queue
977
+
978
+ # Replay with a different transport
979
+ redis_transport = SmartMessage::Transport.create(:redis)
980
+ dlq.replay_one(redis_transport) # Override original transport
981
+ ```
982
+
983
+ #### Administrative Functions
984
+
985
+ ```ruby
986
+ # Filter messages for analysis
987
+ failed_orders = dlq.filter_by_class('OrderMessage')
988
+ timeout_errors = dlq.filter_by_error_pattern(/timeout/i)
989
+
990
+ # Export messages within a time range
991
+ yesterday = Time.now - 86400
992
+ today = Time.now
993
+ recent_failures = dlq.export_range(yesterday, today)
994
+
995
+ # Clear the queue when needed
996
+ dlq.clear # Remove all messages
997
+ ```
998
+
999
+ #### Integration with Circuit Breakers
1000
+
1001
+ Dead Letter Queue is automatically integrated with circuit breakers:
1002
+
1003
+ ```ruby
1004
+ class PaymentMessage < SmartMessage::Base
1005
+ config do
1006
+ transport SmartMessage::Transport.create(:redis)
1007
+ # Messages automatically go to DLQ when circuit breaker trips
1008
+ end
1009
+ end
1010
+
1011
+ # Monitor circuit breaker status
1012
+ transport = PaymentMessage.transport
1013
+ stats = transport.transport_circuit_stats
1014
+ if stats[:transport_publish][:open]
1015
+ puts "Circuit open - messages going to DLQ"
1016
+ end
1017
+ ```
1018
+
647
1019
  ## Development
648
1020
 
649
1021
  After checking out the repo, run: