smart_message 0.0.9 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -0
- data/Gemfile.lock +1 -1
- data/README.md +101 -3
- data/docs/architecture.md +139 -69
- data/docs/message_deduplication.md +488 -0
- data/examples/10_message_deduplication.rb +209 -0
- data/lib/smart_message/base.rb +2 -0
- data/lib/smart_message/ddq/base.rb +71 -0
- data/lib/smart_message/ddq/memory.rb +109 -0
- data/lib/smart_message/ddq/redis.rb +168 -0
- data/lib/smart_message/ddq.rb +31 -0
- data/lib/smart_message/deduplication.rb +174 -0
- data/lib/smart_message/dispatcher.rb +175 -18
- data/lib/smart_message/subscription.rb +10 -7
- data/lib/smart_message/version.rb +1 -1
- metadata +8 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8485ad851b6868c57b813977a4b2be3b1e06fe2843510a5b64c79468da3a65cf
|
4
|
+
data.tar.gz: 1c2345c52d1dd57202a83a49d3d4e7769f14b2855d0a08745d3ed4c970ef0f0e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 26cfdd1030e880074e557f7bc315220995b3267ec0a11fd4d0f621933e2101f40f35da425649388b83bf8055246934e6c9f8e60a281246e04e5cd89763c33e07
|
7
|
+
data.tar.gz: 25d66186e9ebe3f3fcf595e7093ec08c50db83d84205fcb4567b0c69804e44b80496693c40e36a0ea30b9f315a36d2070e701977bec6a0660f3c3bda327f1d88
|
data/CHANGELOG.md
CHANGED
@@ -7,6 +7,29 @@ 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
|
+
|
10
33
|
## [0.0.9] 2025-08-20
|
11
34
|
### Added
|
12
35
|
- **Advanced Logging Configuration System**: Comprehensive logger configuration with multiple output formats and options
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -19,6 +19,7 @@ SmartMessage is a message abstraction framework that decouples business logic fr
|
|
19
19
|
- **Concurrent Processing**: Thread-safe message routing using `Concurrent::CachedThreadPool`
|
20
20
|
- **Advanced Logging System**: Comprehensive logging with colorized console output, JSON structured logging, and file rolling
|
21
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
|
22
23
|
- **Development Tools**: STDOUT and in-memory transports for testing
|
23
24
|
- **Production Ready**: Redis transport with automatic reconnection and error handling
|
24
25
|
- **Dead Letter Queue**: File-based DLQ with JSON Lines format for failed message capture and replay
|
@@ -201,7 +202,103 @@ DevService.subscribe(to: /^(dev|staging)-.*/)
|
|
201
202
|
ProdService.subscribe(to: /^prod-.*/)
|
202
203
|
```
|
203
204
|
|
204
|
-
### 5.
|
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
|
205
302
|
|
206
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:
|
207
304
|
|
@@ -412,9 +509,10 @@ Pluggable message encoding/decoding:
|
|
412
509
|
#### Dispatcher
|
413
510
|
Concurrent message routing engine that:
|
414
511
|
- Uses thread pools for async processing
|
415
|
-
- Routes messages to subscribed handlers
|
416
|
-
- Provides processing statistics
|
512
|
+
- Routes messages to subscribed handlers with handler-scoped deduplication
|
513
|
+
- Provides processing statistics and DDQ management
|
417
514
|
- Handles graceful shutdown
|
515
|
+
- Maintains separate DDQ instances per handler for isolated deduplication tracking
|
418
516
|
|
419
517
|
### Plugin Architecture
|
420
518
|
|
data/docs/architecture.md
CHANGED
@@ -16,37 +16,53 @@ SmartMessage is designed around the principle that **messages should be independ
|
|
16
16
|
|
17
17
|
## Architecture Overview
|
18
18
|
|
19
|
-
```
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
19
|
+
```mermaid
|
20
|
+
graph TB
|
21
|
+
subgraph "SmartMessage Core"
|
22
|
+
Base[SmartMessage::Base]
|
23
|
+
Header[Message Header<br/>• UUID<br/>• Timestamps<br/>• Addressing]
|
24
|
+
Props[Message Properties<br/>• Business Data<br/>• Validation<br/>• Versioning]
|
25
|
+
end
|
26
|
+
|
27
|
+
subgraph "Plugin System"
|
28
|
+
Transport[Transport Plugin<br/>• publish()<br/>• subscribe()<br/>• Memory/Redis/STDOUT]
|
29
|
+
Serializer[Serializer Plugin<br/>• encode()<br/>• decode()<br/>• JSON/Custom]
|
30
|
+
Logger[Logger Plugin<br/>• Structured logging<br/>• Multiple outputs<br/>• Colorization]
|
31
|
+
end
|
32
|
+
|
33
|
+
subgraph "Message Processing"
|
34
|
+
Dispatcher[Dispatcher<br/>• Route messages<br/>• Thread pool<br/>• Subscriptions<br/>• DDQ management]
|
35
|
+
DDQ[Deduplication Queue<br/>• Handler-scoped<br/>• Memory/Redis storage<br/>• O(1) performance<br/>• Circular buffer]
|
36
|
+
Handlers[Message Handlers<br/>• Default handler<br/>• Block handlers<br/>• Proc handlers<br/>• Method handlers]
|
37
|
+
end
|
38
|
+
|
39
|
+
subgraph "Reliability Layer"
|
40
|
+
CircuitBreaker[Circuit Breaker<br/>• Failure thresholds<br/>• Automatic fallback<br/>• Recovery detection]
|
41
|
+
DLQ[Dead Letter Queue<br/>• Failed messages<br/>• Replay mechanism<br/>• JSON Lines format]
|
42
|
+
end
|
43
|
+
|
44
|
+
subgraph "Monitoring"
|
45
|
+
Stats[Statistics<br/>• Message counts<br/>• Processing metrics<br/>• Thread pool status]
|
46
|
+
Filters[Message Filtering<br/>• Entity-aware routing<br/>• Regex patterns<br/>• Broadcast handling]
|
47
|
+
end
|
48
|
+
|
49
|
+
Base --> Header
|
50
|
+
Base --> Props
|
51
|
+
Base --> Transport
|
52
|
+
Base --> Serializer
|
53
|
+
Base --> Logger
|
54
|
+
|
55
|
+
Transport --> Dispatcher
|
56
|
+
Dispatcher --> DDQ
|
57
|
+
Dispatcher --> Handlers
|
58
|
+
Dispatcher --> Stats
|
59
|
+
Dispatcher --> Filters
|
60
|
+
|
61
|
+
Transport --> CircuitBreaker
|
62
|
+
CircuitBreaker --> DLQ
|
63
|
+
|
64
|
+
DDQ -.-> Stats
|
65
|
+
Handlers -.-> Stats
|
50
66
|
```
|
51
67
|
|
52
68
|
## Core Components
|
@@ -126,38 +142,84 @@ end
|
|
126
142
|
|
127
143
|
### 4. Dispatcher
|
128
144
|
|
129
|
-
Routes incoming messages to appropriate handlers using concurrent processing.
|
145
|
+
Routes incoming messages to appropriate handlers using concurrent processing with integrated deduplication.
|
130
146
|
|
131
147
|
**Key Responsibilities:**
|
132
148
|
- Message routing based on class
|
133
|
-
- Thread pool management
|
149
|
+
- Thread pool management
|
134
150
|
- Subscription catalog management
|
135
|
-
-
|
151
|
+
- Handler-scoped DDQ management
|
152
|
+
- Message filtering and statistics collection
|
136
153
|
|
137
|
-
**Location:** `lib/smart_message/dispatcher.rb
|
154
|
+
**Location:** `lib/smart_message/dispatcher.rb`
|
138
155
|
|
139
156
|
```ruby
|
140
157
|
dispatcher = SmartMessage::Dispatcher.new
|
141
158
|
dispatcher.add("MyMessage", "MyMessage.process")
|
142
159
|
dispatcher.route(header, payload)
|
160
|
+
|
161
|
+
# DDQ integration is automatic when enabled
|
162
|
+
MyMessage.enable_deduplication!
|
163
|
+
```
|
164
|
+
|
165
|
+
### 5. Deduplication Queue (DDQ)
|
166
|
+
|
167
|
+
Handler-scoped message deduplication system preventing duplicate processing.
|
168
|
+
|
169
|
+
**Key Responsibilities:**
|
170
|
+
- UUID-based duplicate detection
|
171
|
+
- Handler isolation (each handler gets own DDQ)
|
172
|
+
- Memory and Redis storage backends
|
173
|
+
- O(1) performance with hybrid Array + Set data structure
|
174
|
+
|
175
|
+
**Architecture:**
|
176
|
+
```mermaid
|
177
|
+
graph LR
|
178
|
+
subgraph "Handler A DDQ"
|
179
|
+
A1[Circular Array]
|
180
|
+
A2[Lookup Set]
|
181
|
+
A3[Mutex Lock]
|
182
|
+
end
|
183
|
+
|
184
|
+
subgraph "Handler B DDQ"
|
185
|
+
B1[Circular Array]
|
186
|
+
B2[Lookup Set]
|
187
|
+
B3[Mutex Lock]
|
188
|
+
end
|
189
|
+
|
190
|
+
Message[Incoming Message<br/>UUID: abc-123] --> Dispatcher
|
191
|
+
Dispatcher --> |Check Handler A| A2
|
192
|
+
Dispatcher --> |Check Handler B| B2
|
193
|
+
|
194
|
+
A2 --> |Not Found| ProcessA[Process with Handler A]
|
195
|
+
B2 --> |Found| SkipB[Skip Handler B - Duplicate]
|
196
|
+
|
197
|
+
ProcessA --> |Add UUID| A1
|
198
|
+
ProcessA --> |Add UUID| A2
|
143
199
|
```
|
144
200
|
|
145
|
-
|
201
|
+
**Location:** `lib/smart_message/deduplication.rb`, `lib/smart_message/ddq/`
|
202
|
+
|
203
|
+
### 6. Message Headers
|
146
204
|
|
147
|
-
Standard metadata attached to every message.
|
205
|
+
Standard metadata attached to every message with entity addressing support.
|
148
206
|
|
149
207
|
**Key Responsibilities:**
|
150
208
|
- Message identification (UUID)
|
151
|
-
- Routing information (message class)
|
209
|
+
- Routing information (message class, version)
|
152
210
|
- Tracking data (timestamps, process IDs)
|
211
|
+
- Entity addressing (from, to, reply_to)
|
153
212
|
|
154
|
-
**Location:** `lib/smart_message/header.rb
|
213
|
+
**Location:** `lib/smart_message/header.rb`
|
155
214
|
|
156
215
|
```ruby
|
157
216
|
header = message._sm_header
|
158
217
|
puts header.uuid # "550e8400-e29b-41d4-a716-446655440000"
|
159
218
|
puts header.message_class # "MyMessage"
|
160
219
|
puts header.published_at # 2025-08-17 10:30:00 UTC
|
220
|
+
puts header.from # "payment-service"
|
221
|
+
puts header.to # "order-service"
|
222
|
+
puts header.version # 1
|
161
223
|
```
|
162
224
|
|
163
225
|
## Message Lifecycle
|
@@ -177,17 +239,27 @@ end
|
|
177
239
|
|
178
240
|
### 2. Subscription Phase
|
179
241
|
```ruby
|
242
|
+
# Basic subscription
|
180
243
|
OrderMessage.subscribe
|
181
|
-
|
244
|
+
|
245
|
+
# Subscription with filtering
|
246
|
+
OrderMessage.subscribe(from: /^payment-.*/, to: 'order-service')
|
247
|
+
OrderMessage.subscribe('PaymentService.process', broadcast: true)
|
248
|
+
|
249
|
+
# Each subscription gets its own DDQ automatically
|
250
|
+
# DDQ Key: "OrderMessage:OrderMessage.process"
|
251
|
+
# DDQ Key: "OrderMessage:PaymentService.process"
|
182
252
|
```
|
183
253
|
|
184
254
|
### 3. Publishing Phase
|
185
255
|
```ruby
|
186
256
|
order = OrderMessage.new(order_id: "123", amount: 99.99)
|
257
|
+
order.from("order-service").to("payment-service")
|
187
258
|
order.publish
|
188
|
-
# 1. Creates header with UUID, timestamp,
|
189
|
-
# 2. Encodes message via serializer
|
259
|
+
# 1. Creates header with UUID, timestamp, addressing
|
260
|
+
# 2. Encodes message via serializer
|
190
261
|
# 3. Sends via transport
|
262
|
+
# 4. Circuit breaker monitors for failures
|
191
263
|
```
|
192
264
|
|
193
265
|
### 4. Receiving Phase
|
@@ -195,9 +267,10 @@ order.publish
|
|
195
267
|
# Transport receives message
|
196
268
|
transport.receive(header, payload)
|
197
269
|
# 1. Routes to dispatcher
|
198
|
-
# 2. Dispatcher
|
199
|
-
# 3.
|
200
|
-
# 4.
|
270
|
+
# 2. Dispatcher checks DDQ for duplicates per handler
|
271
|
+
# 3. Applies message filters (from/to/broadcast)
|
272
|
+
# 4. Spawns thread for processing matching handlers
|
273
|
+
# 5. Marks UUID as processed in handler's DDQ
|
201
274
|
```
|
202
275
|
|
203
276
|
### 5. Message Handler Processing
|
@@ -382,29 +455,19 @@ dlq.enqueue(header, payload, error: "Validation failed")
|
|
382
455
|
|
383
456
|
**DLQ Architecture:**
|
384
457
|
|
385
|
-
```
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
│ │Transport │ │Dead Letter │ │
|
399
|
-
│ │ │ │ Queue │ │
|
400
|
-
│ └──────────┘ └─────────────┘ │
|
401
|
-
│ │ │
|
402
|
-
│ ▼ │
|
403
|
-
│ ┌─────────────┐ │
|
404
|
-
│ │ Replay │ │
|
405
|
-
│ │ Mechanism │ │
|
406
|
-
│ └─────────────┘ │
|
407
|
-
└─────────────────────────────────────────────────────────────┘
|
458
|
+
```mermaid
|
459
|
+
graph TB
|
460
|
+
Publish[Message Publishing]
|
461
|
+
CB[Circuit Breaker<br/>Monitoring]
|
462
|
+
Transport[Transport<br/>Success]
|
463
|
+
DLQ[Dead Letter Queue<br/>Failure Storage]
|
464
|
+
Replay[Replay Mechanism<br/>Manual/Automated]
|
465
|
+
|
466
|
+
Publish --> CB
|
467
|
+
CB --> |Success| Transport
|
468
|
+
CB --> |Failure| DLQ
|
469
|
+
DLQ --> Replay
|
470
|
+
Replay --> |Retry| Publish
|
408
471
|
```
|
409
472
|
|
410
473
|
**DLQ Features:**
|
@@ -417,7 +480,7 @@ dlq.enqueue(header, payload, error: "Validation failed")
|
|
417
480
|
|
418
481
|
### Built-in Statistics
|
419
482
|
|
420
|
-
SmartMessage automatically collects processing statistics:
|
483
|
+
SmartMessage automatically collects processing statistics including DDQ metrics:
|
421
484
|
|
422
485
|
```ruby
|
423
486
|
# Statistics are collected for:
|
@@ -427,6 +490,11 @@ SS.add(message_class, process_method, 'routed')
|
|
427
490
|
# Access statistics
|
428
491
|
puts SS.stat
|
429
492
|
puts SS.get("MyMessage", "publish")
|
493
|
+
|
494
|
+
# DDQ-specific statistics
|
495
|
+
stats = OrderMessage.ddq_stats
|
496
|
+
puts "DDQ utilization: #{stats[:utilization]}%"
|
497
|
+
puts "Current count: #{stats[:current_count]}"
|
430
498
|
```
|
431
499
|
|
432
500
|
### Monitoring Points
|
@@ -435,6 +503,8 @@ puts SS.get("MyMessage", "publish")
|
|
435
503
|
2. **Message Routing**: Count of routed messages per processor
|
436
504
|
3. **Thread Pool**: Queue length, completed tasks, running status
|
437
505
|
4. **Transport Status**: Connection status, message counts
|
506
|
+
5. **DDQ Metrics**: Utilization, duplicate detection rates, memory usage
|
507
|
+
6. **Message Filtering**: Filter match rates, entity-aware routing statistics
|
438
508
|
|
439
509
|
## Configuration Architecture
|
440
510
|
|