smart_message 0.0.16 → 0.0.17
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 +64 -0
- data/Gemfile.lock +4 -4
- data/README.md +10 -6
- data/docs/guides/transport-selection.md +361 -0
- data/docs/reference/transports.md +42 -18
- data/docs/transports/file-transport.md +535 -0
- data/docs/transports/multi-transport.md +1 -1
- data/docs/transports/redis-transport.md +1 -1
- data/docs/transports/stdout-transport.md +580 -0
- data/examples/memory/06_stdout_publish_only.rb +70 -97
- data/lib/smart_message/transport/file_operations.rb +39 -7
- data/lib/smart_message/transport/file_transport.rb +5 -2
- data/lib/smart_message/transport/stdout_transport.rb +5 -93
- data/lib/smart_message/version.rb +1 -1
- data/mkdocs.yml +4 -5
- metadata +4 -2
- data/examples/memory/log/demo_app.log.1 +0 -100
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 31da3cbbad04e7c1c5c6c4957e9cbe19fd2b5ef3b4eb13079f6daa5056cf5f93
|
4
|
+
data.tar.gz: f418df55d5e4e40b8ad942eec2c553ae6f6275a85a1a1fe8063addcee8ddc2f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 72876daadfbf2d4bc817ceaa0e41d5564e537a4baf71b36fb4042ed217c63802bf1500ff51bdcce9b19c8765ad9be2a7d8e6fbc288e937ec30a64334fa5e3d1f
|
7
|
+
data.tar.gz: e663de462e0221c88ca90352ef11861b99b7ed43b43a941899e67b9dfc584c68a1af9c2b86a5f09188fd2ee528308869eb92a267920bdf8fc52e197e30c1eb91
|
data/CHANGELOG.md
CHANGED
@@ -7,6 +7,70 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## [0.0.17] 2025-09-11
|
11
|
+
|
12
|
+
### Enhanced
|
13
|
+
- **FileTransport Message Handling**: Simplified FileTransport publish method to only handle message objects
|
14
|
+
- **Architecture Clarification**: FileTransport now exclusively accepts SmartMessage objects with `_sm_header`
|
15
|
+
- **Message Processing**: Proper extraction of message class from `message._sm_header.message_class`
|
16
|
+
- **Serialization Flow**: Clean serialization pipeline using `encode_message(message)` before file operations
|
17
|
+
- **Code Quality**: Eliminated unnecessary backward compatibility code for raw string payloads
|
18
|
+
- **Demo Program Simplification**: Streamlined 06 demo with minimal message properties
|
19
|
+
- **Property Reduction**: DemoMessage now uses only `first_name` and `last_name` properties for clarity
|
20
|
+
- **Format Examples**: Three clear format demonstrations (Alice Johnson in :pretty, Bob Smith & Carol Williams in :jsonl, David Brown, Emma Davis & Frank Miller in :json)
|
21
|
+
- **Educational Value**: Simplified output makes format differences more apparent and easier to understand
|
22
|
+
- **Documentation Updates**: Updated usage examples and JQ query patterns to reflect simple property structure
|
23
|
+
|
24
|
+
### Fixed
|
25
|
+
- **FileTransport Test Compatibility**: Removed invalid compatibility test for raw string publishing
|
26
|
+
- **Issue**: Test `test_publish_compatibility_method` was passing raw strings to FileTransport.publish
|
27
|
+
- **Architecture Decision**: FileTransport should only handle SmartMessage objects, not raw strings
|
28
|
+
- **Solution**: Removed the invalid test that conflicted with proper message object architecture
|
29
|
+
- **Impact**: Test suite now properly validates FileTransport's message-only publishing contract
|
30
|
+
- **StdoutTransport Architecture**: Simplified StdoutTransport to minimal subclass of FileTransport
|
31
|
+
- **Inheritance**: StdoutTransport now inherits all functionality from FileTransport with minimal 6-line implementation
|
32
|
+
- **Option Merging**: Fixed critical bug where `file_path: $stdout` always overwrote user-provided options
|
33
|
+
- **Solution**: Changed from `options.merge(defaults)` to `defaults.merge(options)` for proper option precedence
|
34
|
+
- **Flexibility**: StdoutTransport can now write to files when `file_path` option is provided, while defaulting to STDOUT
|
35
|
+
- **FileTransport Format Support**: Added comprehensive output formatting capabilities to FileTransport
|
36
|
+
- **Format Options**: Implemented `:json` (raw), `:jsonl` (JSON with newline), and `:pretty` (amazing_print formatting)
|
37
|
+
- **Pretty Printing**: Added amazing_print integration for `:pretty` format using serializer's `decode` method
|
38
|
+
- **Serializer Integration**: Pretty format uses transport's serializer to deserialize messages back to Ruby objects
|
39
|
+
- **Fallback Handling**: Graceful fallback to raw output when amazing_print is unavailable or deserialization fails
|
40
|
+
- **FileTransport IO Object Support**: Enhanced FileTransport to handle IO objects properly
|
41
|
+
- **IO Detection**: Added `respond_to?(:write)` checks to distinguish IO objects from file paths
|
42
|
+
- **Directory Operations**: Skip directory creation for IO objects in `ensure_directory_exists`
|
43
|
+
- **File Operations**: Return IO objects directly in `open_file_handle` instead of trying to open them
|
44
|
+
- **Compatibility**: Maintains full backward compatibility with string file paths
|
45
|
+
|
46
|
+
### Fixed
|
47
|
+
- **StdoutTransport Option Precedence**: Fixed critical configuration bug preventing file output
|
48
|
+
- **Issue**: `super(options.merge(file_path: $stdout))` caused defaults to always override user options
|
49
|
+
- **Impact**: StdoutTransport could not write to files when `file_path` was provided
|
50
|
+
- **Fix**: Reversed merge order to `defaults.merge(options)` for proper option precedence
|
51
|
+
- **Result**: StdoutTransport now correctly respects user-provided file paths while defaulting to STDOUT
|
52
|
+
- **FileOperations Type Safety**: Enhanced type checking for file vs IO operations
|
53
|
+
- **Issue**: `File.dirname` called on IO objects caused "no implicit conversion" errors
|
54
|
+
- **Solution**: Added `respond_to?(:write)` checks throughout FileOperations module
|
55
|
+
- **Methods Fixed**: `ensure_directory_exists`, `open_file_handle`, and related file operations
|
56
|
+
- **Robustness**: FileTransport now handles both file paths and IO objects seamlessly
|
57
|
+
|
58
|
+
### Added
|
59
|
+
- **Pretty Format Demo**: Enhanced STDOUT transport demo with comprehensive format examples
|
60
|
+
- **Demo Update**: `examples/memory/06_stdout_publish_only.rb` now demonstrates all three formats
|
61
|
+
- **Format Examples**: LogMessage (jsonl), MetricsMessage (json), and DebugMessage (pretty)
|
62
|
+
- **Complex Data**: DebugMessage showcases pretty formatting with nested data structures
|
63
|
+
- **Educational Value**: Clear documentation of format differences and use cases
|
64
|
+
|
65
|
+
### Tests
|
66
|
+
- **Complete Test Suite**: All transport tests now pass without errors
|
67
|
+
- **Test Results**: 313 runs, 930 assertions, 0 failures, 0 errors, 27 skips
|
68
|
+
- **StdoutTransport Tests**: Fixed all TypeError issues related to IO object handling
|
69
|
+
- **FileTransport Integration**: Verified format support and IO object compatibility
|
70
|
+
- **Test Cleanup**: Removed invalid test that attempted to publish raw strings to FileTransport
|
71
|
+
- **Architecture Validation**: Test suite now properly validates message-only publishing contract
|
72
|
+
- **Regression Prevention**: Test coverage ensures option merging bug cannot reoccur
|
73
|
+
|
10
74
|
## [0.0.16] 2025-09-10
|
11
75
|
|
12
76
|
### Added
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
smart_message (0.0.
|
4
|
+
smart_message (0.0.17)
|
5
5
|
activesupport
|
6
6
|
async
|
7
7
|
async-redis
|
@@ -30,7 +30,7 @@ GEM
|
|
30
30
|
tzinfo (~> 2.0, >= 2.0.5)
|
31
31
|
uri (>= 0.13.1)
|
32
32
|
amazing_print (1.8.1)
|
33
|
-
async (2.
|
33
|
+
async (2.32.0)
|
34
34
|
console (~> 1.29)
|
35
35
|
fiber-annotation
|
36
36
|
io-event (~> 1.11)
|
@@ -47,10 +47,10 @@ GEM
|
|
47
47
|
base64 (0.3.0)
|
48
48
|
benchmark (0.4.1)
|
49
49
|
bigdecimal (3.2.3)
|
50
|
-
breaker_machines (0.
|
50
|
+
breaker_machines (0.5.0)
|
51
51
|
activesupport (>= 7.2)
|
52
52
|
concurrent-ruby (~> 1.3)
|
53
|
-
state_machines (>= 0.
|
53
|
+
state_machines (>= 0.100.0)
|
54
54
|
zeitwerk (~> 2.7)
|
55
55
|
colorize (1.1.0)
|
56
56
|
concurrent-ruby (1.3.5)
|
data/README.md
CHANGED
@@ -667,28 +667,32 @@ OrderMessage.new(
|
|
667
667
|
|
668
668
|
### STDOUT Transport (Publish-Only)
|
669
669
|
|
670
|
-
The STDOUT transport is designed for publish-only scenarios - perfect for debugging, logging, or integration with external systems.
|
670
|
+
The STDOUT transport is designed for publish-only scenarios - perfect for debugging, logging, or integration with external systems. Built as a minimal subclass of FileTransport, it inherits comprehensive formatting capabilities.
|
671
671
|
|
672
672
|
```ruby
|
673
673
|
# Basic STDOUT output (publish-only)
|
674
674
|
transport = SmartMessage::Transport::StdoutTransport.new
|
675
675
|
|
676
|
-
#
|
676
|
+
# JSON Lines format - one message per line (default)
|
677
|
+
transport = SmartMessage::Transport::StdoutTransport.new(format: :jsonl)
|
678
|
+
|
679
|
+
# Pretty-printed format with amazing_print for human reading
|
677
680
|
transport = SmartMessage::Transport::StdoutTransport.new(format: :pretty)
|
678
681
|
|
679
|
-
# JSON format
|
682
|
+
# Compact JSON format without newlines
|
680
683
|
transport = SmartMessage::Transport::StdoutTransport.new(format: :json)
|
681
684
|
|
682
685
|
# Output to file instead of STDOUT
|
683
|
-
transport = SmartMessage::Transport::StdoutTransport.new(
|
686
|
+
transport = SmartMessage::Transport::StdoutTransport.new(file_path: "messages.log")
|
684
687
|
```
|
685
688
|
|
686
689
|
**Key Features:**
|
687
690
|
- **Publish-only**: No message processing or loopback
|
688
691
|
- **Subscription attempts are ignored** with warning logs
|
689
|
-
- **
|
692
|
+
- **Three formats**: `:jsonl` (default), `:pretty` for debugging, `:json` for compact output
|
693
|
+
- **Flexible Output**: Defaults to STDOUT but can write to files when `file_path` specified
|
690
694
|
- **Perfect for**: debugging, logging, piping to external tools
|
691
|
-
- **Use cases**: `./app | jq`, `./app | fluentd`, development monitoring
|
695
|
+
- **Use cases**: `./app | jq '.first_name'`, `./app | fluentd`, development monitoring
|
692
696
|
|
693
697
|
**For local message processing, use MemoryTransport instead:**
|
694
698
|
```ruby
|
@@ -0,0 +1,361 @@
|
|
1
|
+
# Transport Selection Guide
|
2
|
+
|
3
|
+
Choosing the right transport for your SmartMessage application is crucial for performance, reliability, and maintainability. This guide provides comprehensive information about each available transport and decision matrices to help you select the optimal transport configuration.
|
4
|
+
|
5
|
+
## Available Transports
|
6
|
+
|
7
|
+
### Memory Transport
|
8
|
+
**In-memory message storage for development and testing**
|
9
|
+
|
10
|
+
- **Type**: In-memory queue with optional auto-processing
|
11
|
+
- **Best For**: Unit testing, development, rapid prototyping, message inspection
|
12
|
+
- **Key Features**:
|
13
|
+
- No external dependencies
|
14
|
+
- Thread-safe operations
|
15
|
+
- Message inspection capabilities
|
16
|
+
- Configurable memory limits
|
17
|
+
- Fastest performance (~0.01ms latency)
|
18
|
+
- **Limitations**: Single-process only, no persistence, memory usage grows with volume
|
19
|
+
- **Use Cases**: Unit tests, development debugging, in-memory message queuing
|
20
|
+
|
21
|
+
### Redis Transport
|
22
|
+
**Production-ready Redis pub/sub for distributed messaging**
|
23
|
+
|
24
|
+
- **Type**: Redis pub/sub with broadcast delivery
|
25
|
+
- **Best For**: Production messaging, microservices communication, real-time applications
|
26
|
+
- **Key Features**:
|
27
|
+
- Distributed messaging support
|
28
|
+
- Automatic reconnection handling
|
29
|
+
- High throughput (80K+ messages/second)
|
30
|
+
- Low latency (~1ms)
|
31
|
+
- Thread-based subscriber model
|
32
|
+
- **Limitations**: No message persistence, no pattern matching, all subscribers receive all messages
|
33
|
+
- **Use Cases**: Production systems, scalable architectures, service-to-service messaging
|
34
|
+
|
35
|
+
### STDOUT Transport
|
36
|
+
**Console and file output with multiple formatting options**
|
37
|
+
|
38
|
+
- **Type**: Output-only transport with formatting capabilities
|
39
|
+
- **Best For**: Development debugging, application logging, message tracing, integration testing
|
40
|
+
- **Key Features**:
|
41
|
+
- Three output formats (`:pretty`, `:jsonl`, `:json`)
|
42
|
+
- Console or file output
|
43
|
+
- Optional loopback processing
|
44
|
+
- Human-readable pretty printing
|
45
|
+
- Thread-safe file operations
|
46
|
+
- **Limitations**: Not suitable for production messaging, single output destination
|
47
|
+
- **Use Cases**: Development debugging, structured logging, message flow tracing
|
48
|
+
|
49
|
+
### File Transport
|
50
|
+
**Base class for file-based messaging**
|
51
|
+
|
52
|
+
- **Type**: Abstract base class for file-based transports
|
53
|
+
- **Best For**: Custom file-based transport implementations, message archiving
|
54
|
+
- **Key Features**:
|
55
|
+
- Automatic directory creation
|
56
|
+
- Thread-safe file operations
|
57
|
+
- Message serialization handling
|
58
|
+
- Extensible architecture for custom transports
|
59
|
+
- **Limitations**: Rarely used directly, requires custom implementation
|
60
|
+
- **Use Cases**: Custom transport development, message persistence, audit trails
|
61
|
+
|
62
|
+
### Multi-Transport Publishing
|
63
|
+
**Simultaneous publishing to multiple transports**
|
64
|
+
|
65
|
+
- **Type**: Configuration pattern for publishing to multiple destinations
|
66
|
+
- **Best For**: High availability, migration scenarios, monitoring integration, redundancy
|
67
|
+
- **Key Features**:
|
68
|
+
- Publish to multiple transports with single `publish()` call
|
69
|
+
- Resilient to partial failures
|
70
|
+
- Sequential processing with error isolation
|
71
|
+
- Transport introspection methods
|
72
|
+
- **Limitations**: Sequential processing can impact performance, memory usage scales with transport count
|
73
|
+
- **Use Cases**: Critical message redundancy, gradual migration, operational monitoring
|
74
|
+
|
75
|
+
## Transport Selection Matrix
|
76
|
+
|
77
|
+
### By Development Phase
|
78
|
+
|
79
|
+
| Phase | Primary Transport | Secondary Transport | Use Case |
|
80
|
+
|-------|------------------|-------------------|----------|
|
81
|
+
| **Unit Testing** | Memory | - | Fast, isolated, inspectable |
|
82
|
+
| **Development** | STDOUT (pretty) | Memory (loopback) | Human-readable debugging |
|
83
|
+
| **Integration Testing** | STDOUT (jsonl) | Memory | Structured output, verification |
|
84
|
+
| **Staging** | Redis | STDOUT (file) | Production-like with logging |
|
85
|
+
| **Production** | Redis | Multi-transport | Scalable with redundancy |
|
86
|
+
|
87
|
+
### By Use Case
|
88
|
+
|
89
|
+
| Use Case | Recommended Transport | Configuration | Rationale |
|
90
|
+
|----------|----------------------|---------------|-----------|
|
91
|
+
| **Unit Tests** | Memory | `auto_process: true` | No dependencies, fast, inspectable |
|
92
|
+
| **Development Debugging** | STDOUT | `format: :pretty, loopback: true` | Human-readable with local processing |
|
93
|
+
| **Application Logging** | STDOUT | `format: :jsonl, file_path: 'app.log'` | Structured logs for analysis |
|
94
|
+
| **Message Tracing** | STDOUT | `format: :json, file_path: '/tmp/trace.log'` | Compact format for debugging |
|
95
|
+
| **Production Messaging** | Redis | `url: ENV['REDIS_URL']` | Distributed, reliable, scalable |
|
96
|
+
| **Critical Messages** | Multi-transport | `[Redis, STDOUT(file), Redis(backup)]` | Redundancy and audit trail |
|
97
|
+
| **Migration Scenarios** | Multi-transport | `[OldTransport, NewTransport]` | Gradual transition |
|
98
|
+
| **Development→Production** | Environment-based | Switch based on `Rails.env` | Appropriate for each environment |
|
99
|
+
|
100
|
+
### By Architecture Pattern
|
101
|
+
|
102
|
+
#### Single Application (Monolith)
|
103
|
+
```ruby
|
104
|
+
# Development
|
105
|
+
transport: SmartMessage::Transport::StdoutTransport.new(format: :pretty)
|
106
|
+
|
107
|
+
# Production
|
108
|
+
transport: SmartMessage::Transport::RedisTransport.new(url: ENV['REDIS_URL'])
|
109
|
+
```
|
110
|
+
|
111
|
+
#### Microservices Architecture
|
112
|
+
```ruby
|
113
|
+
# High-availability critical messages
|
114
|
+
transport: [
|
115
|
+
SmartMessage::Transport::RedisTransport.new(url: primary_redis),
|
116
|
+
SmartMessage::Transport::RedisTransport.new(url: backup_redis),
|
117
|
+
SmartMessage::Transport::StdoutTransport.new(file_path: '/var/log/audit.log')
|
118
|
+
]
|
119
|
+
```
|
120
|
+
|
121
|
+
#### Event-Driven System
|
122
|
+
```ruby
|
123
|
+
# Events with monitoring
|
124
|
+
transport: [
|
125
|
+
SmartMessage::Transport::RedisTransport.new(url: event_redis),
|
126
|
+
SmartMessage::Transport::StdoutTransport.new(
|
127
|
+
format: :jsonl,
|
128
|
+
file_path: '/var/log/events.log'
|
129
|
+
)
|
130
|
+
]
|
131
|
+
```
|
132
|
+
|
133
|
+
## Decision Tree
|
134
|
+
|
135
|
+
### Step 1: Environment Classification
|
136
|
+
```
|
137
|
+
Are you in...?
|
138
|
+
├── Unit Testing → Memory Transport
|
139
|
+
├── Development → STDOUT Transport (pretty format)
|
140
|
+
├── Integration Testing → STDOUT Transport (jsonl format)
|
141
|
+
└── Production → Continue to Step 2
|
142
|
+
```
|
143
|
+
|
144
|
+
### Step 2: Message Criticality (Production)
|
145
|
+
```
|
146
|
+
How critical are your messages?
|
147
|
+
├── Low criticality → Redis Transport (single)
|
148
|
+
├── Medium criticality → Redis + STDOUT file logging
|
149
|
+
└── High criticality → Multi-transport (Redis primary + backup + audit)
|
150
|
+
```
|
151
|
+
|
152
|
+
### Step 3: Scale Requirements
|
153
|
+
```
|
154
|
+
Expected message volume?
|
155
|
+
├── Low (<1K/day) → Any transport suitable
|
156
|
+
├── Medium (1K-100K/day) → Redis Transport recommended
|
157
|
+
└── High (>100K/day) → Redis Transport + performance tuning
|
158
|
+
```
|
159
|
+
|
160
|
+
### Step 4: Integration Requirements
|
161
|
+
```
|
162
|
+
Need external integration?
|
163
|
+
├── Log aggregation → STDOUT Transport (jsonl to file)
|
164
|
+
├── Monitoring systems → Multi-transport (Redis + STDOUT)
|
165
|
+
├── Audit requirements → Multi-transport with file logging
|
166
|
+
└── None → Single transport sufficient
|
167
|
+
```
|
168
|
+
|
169
|
+
## Configuration Examples
|
170
|
+
|
171
|
+
### Environment-Based Configuration
|
172
|
+
```ruby
|
173
|
+
class ApplicationMessage < SmartMessage::Base
|
174
|
+
transport case Rails.env
|
175
|
+
when 'test'
|
176
|
+
SmartMessage::Transport::MemoryTransport.new(auto_process: true)
|
177
|
+
when 'development'
|
178
|
+
SmartMessage::Transport::StdoutTransport.new(
|
179
|
+
format: :pretty,
|
180
|
+
loopback: true
|
181
|
+
)
|
182
|
+
when 'staging'
|
183
|
+
[
|
184
|
+
SmartMessage::Transport::RedisTransport.new(url: ENV['REDIS_URL']),
|
185
|
+
SmartMessage::Transport::StdoutTransport.new(
|
186
|
+
format: :jsonl,
|
187
|
+
file_path: '/var/log/staging.log'
|
188
|
+
)
|
189
|
+
]
|
190
|
+
when 'production'
|
191
|
+
[
|
192
|
+
SmartMessage::Transport::RedisTransport.new(url: ENV['PRIMARY_REDIS_URL']),
|
193
|
+
SmartMessage::Transport::RedisTransport.new(url: ENV['BACKUP_REDIS_URL']),
|
194
|
+
SmartMessage::Transport::StdoutTransport.new(
|
195
|
+
format: :jsonl,
|
196
|
+
file_path: '/var/log/production.log'
|
197
|
+
)
|
198
|
+
]
|
199
|
+
end
|
200
|
+
end
|
201
|
+
```
|
202
|
+
|
203
|
+
### Message-Type Based Selection
|
204
|
+
```ruby
|
205
|
+
# High-volume, low-criticality events
|
206
|
+
class UserActivityMessage < SmartMessage::Base
|
207
|
+
transport SmartMessage::Transport::RedisTransport.new(url: ENV['REDIS_URL'])
|
208
|
+
end
|
209
|
+
|
210
|
+
# Critical business events
|
211
|
+
class PaymentProcessedMessage < SmartMessage::Base
|
212
|
+
transport [
|
213
|
+
SmartMessage::Transport::RedisTransport.new(url: ENV['PRIMARY_REDIS_URL']),
|
214
|
+
SmartMessage::Transport::RedisTransport.new(url: ENV['BACKUP_REDIS_URL']),
|
215
|
+
SmartMessage::Transport::StdoutTransport.new(
|
216
|
+
format: :jsonl,
|
217
|
+
file_path: '/var/log/payments.log'
|
218
|
+
)
|
219
|
+
]
|
220
|
+
end
|
221
|
+
|
222
|
+
# Development/debugging messages
|
223
|
+
class DebugMessage < SmartMessage::Base
|
224
|
+
transport SmartMessage::Transport::StdoutTransport.new(
|
225
|
+
format: :pretty,
|
226
|
+
loopback: true
|
227
|
+
)
|
228
|
+
end
|
229
|
+
```
|
230
|
+
|
231
|
+
## Performance Considerations
|
232
|
+
|
233
|
+
### Latency Comparison
|
234
|
+
| Transport | Typical Latency | Best Use |
|
235
|
+
|-----------|----------------|----------|
|
236
|
+
| Memory | ~0.01ms | Unit tests, development |
|
237
|
+
| STDOUT | ~1ms | Logging, debugging |
|
238
|
+
| Redis | ~1ms | Production messaging |
|
239
|
+
| Multi-transport | Sum of individual transports | Critical messages |
|
240
|
+
|
241
|
+
### Throughput Comparison
|
242
|
+
| Transport | Throughput | Limiting Factor |
|
243
|
+
|-----------|------------|----------------|
|
244
|
+
| Memory | Highest | CPU and memory |
|
245
|
+
| STDOUT | Medium | I/O operations |
|
246
|
+
| Redis | High | Network and Redis performance |
|
247
|
+
| Multi-transport | Lowest individual transport | Sequential processing |
|
248
|
+
|
249
|
+
### Resource Usage
|
250
|
+
| Transport | Memory Usage | External Dependencies | Setup Complexity |
|
251
|
+
|-----------|--------------|----------------------|------------------|
|
252
|
+
| Memory | Grows with volume | None | Minimal |
|
253
|
+
| STDOUT | Minimal | None | Minimal |
|
254
|
+
| Redis | Low | Redis server | Medium |
|
255
|
+
| File | Minimal | None | Minimal |
|
256
|
+
|
257
|
+
## Migration Strategies
|
258
|
+
|
259
|
+
### Development to Production
|
260
|
+
```ruby
|
261
|
+
# Phase 1: Development (Memory/STDOUT)
|
262
|
+
transport: SmartMessage::Transport::MemoryTransport.new
|
263
|
+
|
264
|
+
# Phase 2: Integration Testing (STDOUT with file)
|
265
|
+
transport: SmartMessage::Transport::StdoutTransport.new(
|
266
|
+
format: :jsonl,
|
267
|
+
file_path: '/tmp/integration.log'
|
268
|
+
)
|
269
|
+
|
270
|
+
# Phase 3: Staging (Redis + logging)
|
271
|
+
transport: [
|
272
|
+
SmartMessage::Transport::RedisTransport.new(url: staging_redis),
|
273
|
+
SmartMessage::Transport::StdoutTransport.new(file_path: '/var/log/staging.log')
|
274
|
+
]
|
275
|
+
|
276
|
+
# Phase 4: Production (Multi-transport)
|
277
|
+
transport: [
|
278
|
+
SmartMessage::Transport::RedisTransport.new(url: primary_redis),
|
279
|
+
SmartMessage::Transport::RedisTransport.new(url: backup_redis)
|
280
|
+
]
|
281
|
+
```
|
282
|
+
|
283
|
+
### Transport Evolution
|
284
|
+
```ruby
|
285
|
+
# Start simple
|
286
|
+
class MyMessage < SmartMessage::Base
|
287
|
+
transport SmartMessage::Transport::MemoryTransport.new
|
288
|
+
end
|
289
|
+
|
290
|
+
# Add logging
|
291
|
+
class MyMessage < SmartMessage::Base
|
292
|
+
transport SmartMessage::Transport::StdoutTransport.new(format: :jsonl)
|
293
|
+
end
|
294
|
+
|
295
|
+
# Scale to production
|
296
|
+
class MyMessage < SmartMessage::Base
|
297
|
+
transport SmartMessage::Transport::RedisTransport.new(url: ENV['REDIS_URL'])
|
298
|
+
end
|
299
|
+
|
300
|
+
# Add redundancy
|
301
|
+
class MyMessage < SmartMessage::Base
|
302
|
+
transport [
|
303
|
+
SmartMessage::Transport::RedisTransport.new(url: ENV['PRIMARY_REDIS']),
|
304
|
+
SmartMessage::Transport::RedisTransport.new(url: ENV['BACKUP_REDIS'])
|
305
|
+
]
|
306
|
+
end
|
307
|
+
```
|
308
|
+
|
309
|
+
## Best Practices
|
310
|
+
|
311
|
+
### General Guidelines
|
312
|
+
1. **Start Simple**: Begin with Memory/STDOUT transports in development
|
313
|
+
2. **Match Environment**: Use appropriate transports for each environment
|
314
|
+
3. **Consider Criticality**: More critical messages need more redundant transports
|
315
|
+
4. **Monitor Performance**: Track latency and throughput in production
|
316
|
+
5. **Plan Migration**: Design transport evolution from development to production
|
317
|
+
|
318
|
+
### Transport-Specific
|
319
|
+
- **Memory**: Use in tests and development only, set reasonable message limits
|
320
|
+
- **STDOUT**: Use `:pretty` for development, `:jsonl` for structured logging
|
321
|
+
- **Redis**: Configure proper connection pooling and reconnection settings
|
322
|
+
- **Multi-transport**: Limit to 2-4 transports, order by speed/criticality
|
323
|
+
|
324
|
+
### Environment Configuration
|
325
|
+
- **Development**: Readable formats, loopback enabled for testing
|
326
|
+
- **Testing**: Fast, isolated transports with deterministic behavior
|
327
|
+
- **Staging**: Production-like configuration with additional logging
|
328
|
+
- **Production**: Redundant, monitored, with proper error handling
|
329
|
+
|
330
|
+
## Troubleshooting
|
331
|
+
|
332
|
+
### Common Issues
|
333
|
+
|
334
|
+
**Slow message publishing**
|
335
|
+
- Check multi-transport ordering (put fastest first)
|
336
|
+
- Verify Redis connection health
|
337
|
+
- Monitor file I/O performance
|
338
|
+
|
339
|
+
**Messages not appearing**
|
340
|
+
- Verify transport configuration matches environment
|
341
|
+
- Check Redis connectivity and permissions
|
342
|
+
- Ensure file paths are writable
|
343
|
+
|
344
|
+
**Memory issues**
|
345
|
+
- Set limits on Memory transport
|
346
|
+
- Monitor multi-transport memory usage
|
347
|
+
- Check for message accumulation in development
|
348
|
+
|
349
|
+
**Test failures**
|
350
|
+
- Use Memory transport for predictable test behavior
|
351
|
+
- Clear messages between tests
|
352
|
+
- Mock external transport dependencies
|
353
|
+
|
354
|
+
## Related Documentation
|
355
|
+
|
356
|
+
- [Multi-Transport Publishing](../transports/multi-transport.md) - Detailed multi-transport patterns
|
357
|
+
- [Memory Transport](../transports/memory-transport.md) - Development and testing transport
|
358
|
+
- [Redis Transport](../transports/redis-transport.md) - Production messaging transport
|
359
|
+
- [STDOUT Transport](../transports/stdout-transport.md) - Output and logging transport
|
360
|
+
- [File Transport](../transports/file-transport.md) - Base class for file-based transports
|
361
|
+
- [Transport Overview](../reference/transports.md) - Technical transport reference
|
@@ -33,29 +33,36 @@ message.publish # ✅ Publishes to all three transports
|
|
33
33
|
|
34
34
|
### STDOUT Transport
|
35
35
|
|
36
|
-
**Publish-only transport** perfect for debugging, logging, and integration with external systems.
|
36
|
+
**Publish-only transport** perfect for debugging, logging, and integration with external systems. Built as a minimal subclass of FileTransport, inheriting comprehensive formatting and IO handling capabilities.
|
37
37
|
|
38
38
|
**Features:**
|
39
39
|
- **Publish-only**: No message processing or loopback capability
|
40
|
-
-
|
40
|
+
- **Three output formats**: `:jsonl` (default), `:pretty` (amazing_print), `:json` (compact)
|
41
|
+
- **Flexible output**: Defaults to STDOUT but can write to files
|
42
|
+
- **Smart IO handling**: Automatically handles both IO objects and file paths
|
41
43
|
- Subscription attempts are ignored with warning logs
|
42
44
|
- Perfect for piping to external tools and log aggregators
|
43
45
|
- No external dependencies
|
44
46
|
|
47
|
+
**📚 See [STDOUT Transport Documentation](../transports/stdout-transport.md) for comprehensive usage examples.**
|
48
|
+
|
45
49
|
**Usage:**
|
46
50
|
|
47
51
|
```ruby
|
48
|
-
# Basic STDOUT output
|
52
|
+
# Basic STDOUT output with default JSONL format
|
49
53
|
transport = SmartMessage::Transport::StdoutTransport.new
|
50
54
|
|
51
|
-
#
|
55
|
+
# JSON Lines format - one message per line (default)
|
56
|
+
transport = SmartMessage::Transport::StdoutTransport.new(format: :jsonl)
|
57
|
+
|
58
|
+
# Pretty-printed format with amazing_print for debugging
|
52
59
|
transport = SmartMessage::Transport::StdoutTransport.new(format: :pretty)
|
53
60
|
|
54
|
-
# JSON format
|
61
|
+
# Compact JSON format without newlines
|
55
62
|
transport = SmartMessage::Transport::StdoutTransport.new(format: :json)
|
56
63
|
|
57
|
-
# Output to file instead of
|
58
|
-
transport = SmartMessage::Transport::StdoutTransport.new(
|
64
|
+
# Output to file instead of STDOUT
|
65
|
+
transport = SmartMessage::Transport::StdoutTransport.new(file_path: "messages.log")
|
59
66
|
|
60
67
|
# Configure in message class
|
61
68
|
class LogMessage < SmartMessage::Base
|
@@ -65,25 +72,42 @@ class LogMessage < SmartMessage::Base
|
|
65
72
|
config do
|
66
73
|
transport SmartMessage::Transport::StdoutTransport.new(
|
67
74
|
format: :json,
|
68
|
-
|
75
|
+
file_path: "app.log"
|
69
76
|
)
|
70
77
|
end
|
71
78
|
end
|
72
79
|
```
|
73
80
|
|
74
81
|
**Options:**
|
75
|
-
- `format` (Symbol): Output format - `:
|
76
|
-
- `
|
82
|
+
- `format` (Symbol): Output format - `:jsonl` (default), `:pretty`, `:json`
|
83
|
+
- `file_path` (String|IO): Output destination - filename string or IO object (default: `$stdout`)
|
84
|
+
- All FileTransport options are inherited and available
|
77
85
|
|
78
86
|
**Important:** For local message processing during development, use **MemoryTransport** instead.
|
79
87
|
|
80
|
-
**
|
88
|
+
**Format Examples:**
|
89
|
+
|
90
|
+
**JSONL Format (default):**
|
91
|
+
```json
|
92
|
+
{"_sm_header":{"uuid":"abc-123","message_class":"DemoMessage"},"first_name":"Alice","last_name":"Johnson"}
|
93
|
+
{"_sm_header":{"uuid":"def-456","message_class":"DemoMessage"},"first_name":"Bob","last_name":"Smith"}
|
81
94
|
```
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
95
|
+
|
96
|
+
**Pretty Format:**
|
97
|
+
```ruby
|
98
|
+
{
|
99
|
+
"_sm_header" => {
|
100
|
+
"uuid" => "abc-123",
|
101
|
+
"message_class" => "DemoMessage"
|
102
|
+
},
|
103
|
+
"first_name" => "Alice",
|
104
|
+
"last_name" => "Johnson"
|
105
|
+
}
|
106
|
+
```
|
107
|
+
|
108
|
+
**JSON Format:**
|
109
|
+
```json
|
110
|
+
{"_sm_header":{"uuid":"abc-123"},"first_name":"Alice"}{"_sm_header":{"uuid":"def-456"},"first_name":"Bob"}
|
87
111
|
```
|
88
112
|
|
89
113
|
### Memory Transport
|
@@ -517,8 +541,8 @@ Each transport may have specific options:
|
|
517
541
|
```ruby
|
518
542
|
# STDOUT specific (publish-only)
|
519
543
|
SmartMessage::Transport::StdoutTransport.new(
|
520
|
-
format: :json
|
521
|
-
|
544
|
+
format: :jsonl, # :jsonl (default), :pretty, :json
|
545
|
+
file_path: "/var/log/messages.log"
|
522
546
|
)
|
523
547
|
|
524
548
|
# Memory specific
|