smart_message 0.0.12 → 0.0.13

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 (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +35 -1
  3. data/Gemfile.lock +5 -5
  4. data/docs/core-concepts/architecture.md +5 -10
  5. data/docs/getting-started/examples.md +0 -12
  6. data/docs/getting-started/quick-start.md +4 -9
  7. data/docs/index.md +4 -4
  8. data/docs/reference/serializers.md +160 -488
  9. data/docs/reference/transports.md +1 -125
  10. data/docs/transports/redis-transport-comparison.md +215 -350
  11. data/docs/transports/redis-transport.md +3 -22
  12. data/examples/README.md +6 -9
  13. data/examples/city_scenario/README.md +1 -1
  14. data/examples/city_scenario/messages/emergency_911_message.rb +0 -1
  15. data/examples/city_scenario/messages/emergency_resolved_message.rb +0 -1
  16. data/examples/city_scenario/messages/fire_dispatch_message.rb +0 -1
  17. data/examples/city_scenario/messages/fire_emergency_message.rb +0 -1
  18. data/examples/city_scenario/messages/health_check_message.rb +0 -1
  19. data/examples/city_scenario/messages/health_status_message.rb +0 -1
  20. data/examples/city_scenario/messages/police_dispatch_message.rb +0 -1
  21. data/examples/city_scenario/messages/silent_alarm_message.rb +0 -1
  22. data/examples/memory/01_message_deduplication_demo.rb +0 -2
  23. data/examples/memory/02_dead_letter_queue_demo.rb +0 -3
  24. data/examples/memory/03_point_to_point_orders.rb +0 -2
  25. data/examples/memory/04_publish_subscribe_events.rb +0 -1
  26. data/examples/memory/05_many_to_many_chat.rb +0 -3
  27. data/examples/memory/07_proc_handlers_demo.rb +0 -1
  28. data/examples/memory/08_custom_logger_demo.rb +0 -4
  29. data/examples/memory/09_error_handling_demo.rb +0 -3
  30. data/examples/memory/10_entity_addressing_basic.rb +0 -6
  31. data/examples/memory/11_entity_addressing_with_filtering.rb +0 -4
  32. data/examples/memory/12_regex_filtering_microservices.rb +0 -1
  33. data/examples/memory/13_header_block_configuration.rb +0 -5
  34. data/examples/memory/14_global_configuration_demo.rb +0 -2
  35. data/examples/memory/15_logger_demo.rb +0 -1
  36. data/examples/memory/README.md +3 -3
  37. data/examples/redis/01_smart_home_iot_demo.rb +0 -4
  38. data/examples/redis/README.md +0 -2
  39. data/lib/smart_message/base.rb +19 -10
  40. data/lib/smart_message/configuration.rb +2 -23
  41. data/lib/smart_message/dead_letter_queue.rb +1 -1
  42. data/lib/smart_message/messaging.rb +3 -62
  43. data/lib/smart_message/plugins.rb +1 -42
  44. data/lib/smart_message/transport/base.rb +42 -8
  45. data/lib/smart_message/transport/memory_transport.rb +23 -4
  46. data/lib/smart_message/transport/redis_transport.rb +11 -0
  47. data/lib/smart_message/transport/registry.rb +0 -1
  48. data/lib/smart_message/transport/stdout_transport.rb +28 -10
  49. data/lib/smart_message/transport.rb +0 -1
  50. data/lib/smart_message/version.rb +1 -1
  51. metadata +2 -28
  52. data/docs/guides/redis-queue-getting-started.md +0 -697
  53. data/docs/guides/redis-queue-patterns.md +0 -889
  54. data/docs/guides/redis-queue-production.md +0 -1091
  55. data/docs/transports/redis-enhanced-transport.md +0 -524
  56. data/docs/transports/redis-queue-transport.md +0 -1304
  57. data/examples/redis_enhanced/README.md +0 -319
  58. data/examples/redis_enhanced/enhanced_01_basic_patterns.rb +0 -233
  59. data/examples/redis_enhanced/enhanced_02_fluent_api.rb +0 -331
  60. data/examples/redis_enhanced/enhanced_03_dual_publishing.rb +0 -281
  61. data/examples/redis_enhanced/enhanced_04_advanced_routing.rb +0 -419
  62. data/examples/redis_queue/01_basic_messaging.rb +0 -221
  63. data/examples/redis_queue/01_comprehensive_examples.rb +0 -508
  64. data/examples/redis_queue/02_pattern_routing.rb +0 -405
  65. data/examples/redis_queue/03_fluent_api.rb +0 -422
  66. data/examples/redis_queue/04_load_balancing.rb +0 -486
  67. data/examples/redis_queue/05_microservices.rb +0 -735
  68. data/examples/redis_queue/06_emergency_alerts.rb +0 -777
  69. data/examples/redis_queue/07_queue_management.rb +0 -587
  70. data/examples/redis_queue/README.md +0 -366
  71. data/examples/redis_queue/enhanced_01_basic_patterns.rb +0 -233
  72. data/examples/redis_queue/enhanced_02_fluent_api.rb +0 -331
  73. data/examples/redis_queue/enhanced_03_dual_publishing.rb +0 -281
  74. data/examples/redis_queue/enhanced_04_advanced_routing.rb +0 -419
  75. data/examples/redis_queue/redis_queue_architecture.svg +0 -148
  76. data/lib/smart_message/transport/redis_enhanced_transport.rb +0 -399
  77. data/lib/smart_message/transport/redis_queue_transport.rb +0 -555
@@ -1,573 +1,245 @@
1
- # Serializers
1
+ # Transport-Based Serialization
2
2
 
3
- Serializers handle the encoding and decoding of message content, transforming Ruby objects into wire formats suitable for transmission and storage.
3
+ In SmartMessage's architecture, serialization is handled at the transport level rather than being configured for individual messages. Each transport manages its own optimal serialization format, eliminating the need for separate serializer configuration.
4
4
 
5
5
  ## Overview
6
6
 
7
- Serializers are responsible for:
8
- - **Encoding**: Converting SmartMessage instances to transmittable formats
9
- - **Decoding**: Converting received data back to Ruby objects
10
- - **Format Support**: Handling different data formats (JSON, XML, MessagePack, etc.)
11
- - **Type Safety**: Ensuring data integrity during conversion
7
+ Transport-based serialization provides:
8
+ - **Automatic Format Selection**: Each transport chooses its optimal serialization format
9
+ - **Simplified Configuration**: No need to configure serializers separately
10
+ - **Format Optimization**: Transports can choose the best format for their medium
11
+ - **Consistent Behavior**: All messages using a transport share the same serialization format
12
12
 
13
- ## Built-in Serializers
13
+ ## Transport Serialization Formats
14
14
 
15
- ### JSON Serializer
16
-
17
- The default serializer that converts messages to/from JSON format.
18
-
19
- **Features:**
20
- - Human-readable output
21
- - Wide compatibility
22
- - Built on Ruby's standard JSON library
23
- - Automatic property serialization
24
-
25
- **Usage:**
15
+ ### Memory Transport
16
+ - **Format**: No serialization (objects passed directly)
17
+ - **Use case**: Testing and development where no network transmission occurs
18
+ - **Performance**: Fastest possible (no encoding/decoding overhead)
26
19
 
27
20
  ```ruby
28
- # Basic usage
29
- serializer = SmartMessage::Serializer::Json.new
30
-
31
- # Configure in message class
32
- class UserMessage < SmartMessage::Base
33
- property :user_id
34
- property :email
35
- property :preferences
36
-
37
- config do
38
- serializer SmartMessage::Serializer::Json.new
39
- end
40
- end
41
-
42
- # Manual encoding/decoding
43
- message = UserMessage.new(user_id: 123, email: "user@example.com")
44
- encoded = serializer.encode(message)
45
- # => '{"user_id":123,"email":"user@example.com","preferences":null}'
21
+ # Memory transport - no serialization needed
22
+ transport = SmartMessage::Transport::MemoryTransport.new
46
23
  ```
47
24
 
48
- **Encoding Behavior:**
49
- - All defined properties are included
50
- - Nil values are preserved
51
- - Internal `_sm_` properties are included in serialization
52
- - Uses Ruby's `#to_json` method under the hood
53
-
54
- ## Serializer Interface
55
-
56
- All serializers must implement the `SmartMessage::Serializer::Base` interface:
57
-
58
- ### Required Methods
25
+ ### STDOUT Transport
26
+ - **Format**: JSON (human-readable)
27
+ - **Use case**: Debugging, development logging, message inspection
28
+ - **Features**: Pretty-printed output for easy reading
59
29
 
60
30
  ```ruby
61
- class CustomSerializer < SmartMessage::Serializer::Base
62
- def initialize(options = {})
63
- @options = options
64
- # Custom initialization
65
- end
66
-
67
- # Convert SmartMessage instance to wire format
68
- def encode(message_instance)
69
- # Transform message_instance to your format
70
- # Return string or binary data
71
- end
72
-
73
- # Convert wire format back to hash
74
- def decode(payload)
75
- # Transform payload string back to hash
76
- # Return hash suitable for SmartMessage.new(hash)
77
- end
78
- end
31
+ # STDOUT transport - uses JSON for readability
32
+ transport = SmartMessage::Transport::StdoutTransport.new(
33
+ format: :pretty # or :json for compact format
34
+ )
79
35
  ```
80
36
 
81
- ### Example: MessagePack Serializer
37
+ ### Redis Transport
38
+ - **Format**: MessagePack (primary), JSON (fallback)
39
+ - **Use case**: Production messaging where efficiency matters
40
+ - **Benefits**: Compact binary format reduces network overhead
82
41
 
83
42
  ```ruby
84
- require 'msgpack'
85
-
86
- class MessagePackSerializer < SmartMessage::Serializer::Base
87
- def encode(message_instance)
88
- message_instance.to_h.to_msgpack
89
- end
90
-
91
- def decode(payload)
92
- MessagePack.unpack(payload)
93
- end
94
- end
95
-
96
- # Usage
97
- class BinaryMessage < SmartMessage::Base
98
- property :data
99
- property :timestamp
100
-
101
- config do
102
- serializer MessagePackSerializer.new
103
- end
104
- end
43
+ # Redis transport - automatically uses MessagePack if available
44
+ transport = SmartMessage::Transport::RedisTransport.new(
45
+ url: 'redis://localhost:6379'
46
+ )
105
47
  ```
106
48
 
107
- ### Example: XML Serializer
49
+ ## How It Works
108
50
 
109
- ```ruby
110
- require 'nokogiri'
111
-
112
- class XMLSerializer < SmartMessage::Serializer::Base
113
- def encode(message_instance)
114
- data = message_instance.to_h
115
- builder = Nokogiri::XML::Builder.new do |xml|
116
- xml.message do
117
- data.each do |key, value|
118
- xml.send(key, value)
119
- end
120
- end
121
- end
122
- builder.to_xml
123
- end
124
-
125
- def decode(payload)
126
- doc = Nokogiri::XML(payload)
127
- hash = {}
128
- doc.xpath('//message/*').each do |node|
129
- hash[node.name] = node.text
130
- end
131
- hash
132
- end
133
- end
134
- ```
51
+ ### Transport Serialization Process
135
52
 
136
- ## Serialization Patterns
53
+ 1. **Message Publishing**:
54
+ ```ruby
55
+ message = OrderMessage.new(order_id: "123", amount: 99.99)
56
+ message.publish # Transport handles serialization automatically
57
+ ```
137
58
 
138
- ### Type Coercion
59
+ 2. **Automatic Encoding**: Transport calls its serializer internally
60
+ ```ruby
61
+ # Inside transport.publish(message):
62
+ serialized = transport.serializer.encode(message.to_hash)
63
+ ```
139
64
 
140
- Handle type conversions during serialization:
141
-
142
- ```ruby
143
- class TypedSerializer < SmartMessage::Serializer::Base
144
- def encode(message_instance)
145
- data = message_instance.to_h
146
-
147
- # Convert specific types
148
- data.transform_values do |value|
149
- case value
150
- when Time
151
- value.iso8601
152
- when Date
153
- value.to_s
154
- when BigDecimal
155
- value.to_f
156
- else
157
- value
158
- end
159
- end.to_json
160
- end
161
-
162
- def decode(payload)
163
- data = JSON.parse(payload)
164
-
165
- # Convert back from strings
166
- data.transform_values do |value|
167
- case value
168
- when /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/
169
- Time.parse(value)
170
- else
171
- value
172
- end
173
- end
174
- end
175
- end
176
- ```
65
+ 3. **Message Receiving**: Transport deserializes automatically
66
+ ```ruby
67
+ # Inside transport.receive(serialized_data):
68
+ data = transport.serializer.decode(serialized_data)
69
+ message = MessageClass.new(data)
70
+ ```
177
71
 
178
- ### Nested Object Serialization
72
+ ### Message Structure
179
73
 
180
- Handle complex nested structures:
74
+ All messages are serialized as flat hashes with the `_sm_header` property containing routing metadata:
181
75
 
182
76
  ```ruby
183
- class NestedSerializer < SmartMessage::Serializer::Base
184
- def encode(message_instance)
185
- data = deep_serialize(message_instance.to_h)
186
- JSON.generate(data)
187
- end
188
-
189
- def decode(payload)
190
- data = JSON.parse(payload)
191
- deep_deserialize(data)
192
- end
193
-
194
- private
195
-
196
- def deep_serialize(obj)
197
- case obj
198
- when Hash
199
- obj.transform_values { |v| deep_serialize(v) }
200
- when Array
201
- obj.map { |v| deep_serialize(v) }
202
- when SmartMessage::Base
203
- # Serialize nested messages
204
- obj.to_h
205
- else
206
- obj
207
- end
208
- end
209
-
210
- def deep_deserialize(obj)
211
- case obj
212
- when Hash
213
- obj.transform_values { |v| deep_deserialize(v) }
214
- when Array
215
- obj.map { |v| deep_deserialize(v) }
216
- else
217
- obj
218
- end
219
- end
220
- end
77
+ {
78
+ _sm_header: {
79
+ uuid: "...",
80
+ message_class: "OrderMessage",
81
+ published_at: "2025-01-09T...",
82
+ from: "order-service",
83
+ to: "fulfillment-service",
84
+ serializer: "SmartMessage::Serializer::Json"
85
+ },
86
+ order_id: "123",
87
+ amount: 99.99,
88
+ items: ["Widget A", "Widget B"]
89
+ }
221
90
  ```
222
91
 
223
- ## Serialization Options
92
+ ## Custom Transport Serializers
224
93
 
225
- ### Configurable Serializers
94
+ You can specify a custom serializer when creating a transport:
226
95
 
227
96
  ```ruby
228
- class ConfigurableJSONSerializer < SmartMessage::Serializer::Base
229
- def initialize(options = {})
230
- @pretty = options[:pretty] || false
231
- @exclude_nil = options[:exclude_nil] || false
232
- @date_format = options[:date_format] || :iso8601
233
- end
234
-
235
- def encode(message_instance)
236
- data = message_instance.to_h
237
-
238
- # Remove nil values if requested
239
- data = data.compact if @exclude_nil
240
-
241
- # Format dates
242
- data = format_dates(data)
243
-
244
- # Generate JSON
245
- if @pretty
246
- JSON.pretty_generate(data)
247
- else
248
- JSON.generate(data)
249
- end
97
+ # Custom serializer for a transport
98
+ class MyCustomSerializer
99
+ def encode(data_hash)
100
+ # Your encoding logic here
101
+ # Must return a string
250
102
  end
251
-
252
- private
253
-
254
- def format_dates(data)
255
- data.transform_values do |value|
256
- case value
257
- when Time, Date
258
- case @date_format
259
- when :iso8601
260
- value.iso8601
261
- when :unix
262
- value.to_i
263
- when :rfc2822
264
- value.rfc2822
265
- else
266
- value.to_s
267
- end
268
- else
269
- value
270
- end
271
- end
272
- end
273
- end
274
103
 
275
- # Usage with options
276
- class TimestampMessage < SmartMessage::Base
277
- property :event
278
- property :timestamp
279
-
280
- config do
281
- serializer ConfigurableJSONSerializer.new(
282
- pretty: true,
283
- exclude_nil: true,
284
- date_format: :unix
285
- )
104
+ def decode(serialized_string)
105
+ # Your decoding logic here
106
+ # Must return a hash
286
107
  end
287
108
  end
288
- ```
289
109
 
290
- ## Error Handling
110
+ # Use custom serializer with transport
111
+ transport = SmartMessage::Transport::RedisTransport.new(
112
+ serializer: MyCustomSerializer.new,
113
+ url: 'redis://localhost:6379'
114
+ )
115
+ ```
291
116
 
292
- ### Serialization Errors
117
+ ## Built-in Serializer Classes
293
118
 
294
- Handle encoding/decoding failures gracefully:
119
+ SmartMessage includes these serializer implementations that transports use internally:
295
120
 
121
+ ### JSON Serializer
296
122
  ```ruby
297
- class SafeSerializer < SmartMessage::Serializer::Base
298
- def encode(message_instance)
299
- JSON.generate(message_instance.to_h)
300
- rescue JSON::GeneratorError => e
301
- # Log the error
302
- puts "Serialization failed: #{e.message}"
303
-
304
- # Fallback to simple string representation
305
- message_instance.to_h.to_s
306
- end
307
-
308
- def decode(payload)
309
- JSON.parse(payload)
310
- rescue JSON::ParserError => e
311
- # Log the error
312
- puts "Deserialization failed: #{e.message}"
313
-
314
- # Return error indicator or empty hash
315
- { "_error" => "Failed to deserialize: #{e.message}" }
316
- end
317
- end
123
+ SmartMessage::Serializer::Json.new
318
124
  ```
125
+ - Human-readable format
126
+ - Wide compatibility
127
+ - Used by STDOUT transport and as fallback
319
128
 
320
- ### Validation During Serialization
321
-
129
+ ### MessagePack Serializer
322
130
  ```ruby
323
- class ValidatingSerializer < SmartMessage::Serializer::Base
324
- def encode(message_instance)
325
- validate_before_encoding(message_instance)
326
- JSON.generate(message_instance.to_h)
327
- end
328
-
329
- def decode(payload)
330
- data = JSON.parse(payload)
331
- validate_after_decoding(data)
332
- data
333
- end
334
-
335
- private
336
-
337
- def validate_before_encoding(message)
338
- required_fields = message.class.properties.select do |prop|
339
- message.class.required?(prop)
340
- end
341
-
342
- missing = required_fields.select { |field| message[field].nil? }
343
-
344
- if missing.any?
345
- raise "Missing required fields: #{missing.join(', ')}"
346
- end
347
- end
348
-
349
- def validate_after_decoding(data)
350
- unless data.is_a?(Hash)
351
- raise "Expected hash, got #{data.class}"
352
- end
353
-
354
- # Additional validation logic
355
- end
356
- end
131
+ SmartMessage::Serializer::MessagePack.new
357
132
  ```
133
+ - Binary format for efficiency
134
+ - Smaller payload size
135
+ - Used by Redis transport when available
358
136
 
359
- ## Performance Considerations
360
-
361
- ### Binary Serialization
137
+ ## Migration from Message-Level Serializers
362
138
 
363
- For high-performance scenarios, consider binary formats:
139
+ If you were previously configuring serializers at the message level, here's how to migrate:
364
140
 
141
+ ### Before (Message-Level Configuration)
365
142
  ```ruby
366
- class ProtobufSerializer < SmartMessage::Serializer::Base
367
- def initialize(proto_class)
368
- @proto_class = proto_class
369
- end
370
-
371
- def encode(message_instance)
372
- proto_obj = @proto_class.new(message_instance.to_h)
373
- proto_obj.serialize_to_string
374
- end
375
-
376
- def decode(payload)
377
- proto_obj = @proto_class.parse(payload)
378
- proto_obj.to_h
379
- end
380
- end
381
-
382
- # Usage
383
- UserProto = Google::Protobuf::DescriptorPool.generated_pool.lookup("User").msgclass
384
-
385
- class UserMessage < SmartMessage::Base
386
- property :user_id
387
- property :name
143
+ class OrderMessage < SmartMessage::Base
144
+ property :order_id
145
+ property :amount
388
146
 
389
147
  config do
390
- serializer ProtobufSerializer.new(UserProto)
391
- end
392
- end
393
- ```
394
-
395
- ### Streaming Serialization
396
-
397
- For large messages, consider streaming:
398
-
399
- ```ruby
400
- class StreamingSerializer < SmartMessage::Serializer::Base
401
- def encode(message_instance)
402
- StringIO.new.tap do |io|
403
- JSON.dump(message_instance.to_h, io)
404
- end.string
405
- end
406
-
407
- def decode(payload)
408
- StringIO.new(payload).tap do |io|
409
- JSON.load(io)
410
- end
148
+ transport SmartMessage::Transport::RedisTransport.new
149
+ serializer SmartMessage::Serializer::Json.new # ❌ No longer needed
411
150
  end
412
151
  end
413
152
  ```
414
153
 
415
- ## Compression Support
416
-
417
- ### Compressed Serialization
418
-
154
+ ### After (Transport-Level Serialization)
419
155
  ```ruby
420
- class CompressedJSONSerializer < SmartMessage::Serializer::Base
421
- def encode(message_instance)
422
- json_data = JSON.generate(message_instance.to_h)
423
- Zlib::Deflate.deflate(json_data)
424
- end
156
+ class OrderMessage < SmartMessage::Base
157
+ property :order_id
158
+ property :amount
425
159
 
426
- def decode(payload)
427
- json_data = Zlib::Inflate.inflate(payload)
428
- JSON.parse(json_data)
160
+ config do
161
+ # Transport automatically handles serialization
162
+ transport SmartMessage::Transport::RedisTransport.new
429
163
  end
430
164
  end
431
165
 
432
- # Usage for large messages
433
- class LargeDataMessage < SmartMessage::Base
434
- property :dataset
435
- property :metadata
166
+ # Or specify custom serializer for transport
167
+ class OrderMessage < SmartMessage::Base
168
+ property :order_id
169
+ property :amount
436
170
 
437
171
  config do
438
- serializer CompressedJSONSerializer.new
172
+ transport SmartMessage::Transport::RedisTransport.new(
173
+ serializer: MyCustomSerializer.new
174
+ )
439
175
  end
440
176
  end
441
177
  ```
442
178
 
443
- ## Testing Serializers
179
+ ## Serialization Best Practices
180
+
181
+ ### 1. Let Transports Choose
182
+ Let each transport use its optimal format:
183
+ - Memory: No serialization
184
+ - STDOUT: JSON for readability
185
+ - Redis: MessagePack for efficiency
444
186
 
445
- ### Serializer Testing Patterns
187
+ ### 2. Custom Serializers
188
+ Only use custom serializers when you have specific requirements:
189
+ - Special data formats (XML, Protocol Buffers)
190
+ - Encryption/compression needs
191
+ - Legacy system compatibility
192
+
193
+ ### 3. Testing
194
+ Test with actual transports to ensure serialization works correctly:
446
195
 
447
196
  ```ruby
448
- RSpec.describe CustomSerializer do
449
- let(:serializer) { CustomSerializer.new }
450
- let(:message) do
451
- TestMessage.new(
452
- user_id: 123,
453
- email: "test@example.com",
454
- created_at: Time.parse("2025-08-17T10:30:00Z")
455
- )
456
- end
457
-
458
- describe "#encode" do
459
- it "produces valid output" do
460
- result = serializer.encode(message)
461
- expect(result).to be_a(String)
462
- expect(result).not_to be_empty
463
- end
197
+ RSpec.describe OrderMessage do
198
+ it "serializes correctly with Redis transport" do
199
+ transport = SmartMessage::Transport::RedisTransport.new
200
+ message = OrderMessage.new(order_id: "123", amount: 99.99)
464
201
 
465
- it "includes all properties" do
466
- result = serializer.encode(message)
467
- # Format-specific assertions
468
- end
469
- end
470
-
471
- describe "#decode" do
472
- it "roundtrips correctly" do
473
- encoded = serializer.encode(message)
474
- decoded = serializer.decode(encoded)
475
-
476
- expect(decoded["user_id"]).to eq(123)
477
- expect(decoded["email"]).to eq("test@example.com")
478
- end
479
- end
480
-
481
- describe "error handling" do
482
- it "handles invalid input gracefully" do
483
- expect { serializer.decode("invalid") }.not_to raise_error
484
- end
202
+ # Test roundtrip serialization
203
+ serialized = transport.encode_message(message)
204
+ deserialized = transport.decode_message(serialized)
205
+
206
+ expect(deserialized[:order_id]).to eq("123")
207
+ expect(deserialized[:amount]).to eq(99.99)
485
208
  end
486
209
  end
487
210
  ```
488
211
 
489
- ### Mock Serializer for Testing
212
+ ### 4. Error Handling
213
+ Transports handle serialization errors internally, but you can still catch them:
490
214
 
491
215
  ```ruby
492
- class MockSerializer < SmartMessage::Serializer::Base
493
- attr_reader :encoded_messages, :decoded_payloads
494
-
495
- def initialize
496
- @encoded_messages = []
497
- @decoded_payloads = []
498
- end
499
-
500
- def encode(message_instance)
501
- @encoded_messages << message_instance
502
- "mock_encoded_#{message_instance.object_id}"
503
- end
504
-
505
- def decode(payload)
506
- @decoded_payloads << payload
507
- { "mock" => "decoded", "payload" => payload }
508
- end
509
-
510
- def clear
511
- @encoded_messages.clear
512
- @decoded_payloads.clear
513
- end
216
+ begin
217
+ message.publish
218
+ rescue SmartMessage::Errors::SerializationError => e
219
+ logger.error "Failed to serialize message: #{e.message}"
514
220
  end
515
221
  ```
516
222
 
517
- ## Common Serialization Issues
223
+ ## Performance Considerations
518
224
 
519
- ### Handling Special Values
225
+ ### Format Efficiency
226
+ - **MessagePack**: 20-30% more compact than JSON
227
+ - **JSON**: Human-readable but larger payload
228
+ - **Memory**: No serialization overhead
520
229
 
521
- ```ruby
522
- class RobustJSONSerializer < SmartMessage::Serializer::Base
523
- def encode(message_instance)
524
- data = sanitize_for_json(message_instance.to_h)
525
- JSON.generate(data)
526
- end
527
-
528
- private
529
-
530
- def sanitize_for_json(obj)
531
- case obj
532
- when Hash
533
- obj.transform_values { |v| sanitize_for_json(v) }
534
- when Array
535
- obj.map { |v| sanitize_for_json(v) }
536
- when Float
537
- return nil if obj.nan? || obj.infinite?
538
- obj
539
- when BigDecimal
540
- obj.to_f
541
- when Symbol
542
- obj.to_s
543
- when Complex, Rational
544
- obj.to_f
545
- else
546
- obj
547
- end
548
- end
549
- end
550
- ```
551
-
552
- ### Character Encoding
230
+ ### Network Optimization
231
+ - Redis transport automatically uses MessagePack when available
232
+ - Falls back to JSON if MessagePack gem is not installed
233
+ - STDOUT uses JSON for debugging clarity
553
234
 
554
- ```ruby
555
- class EncodingAwareSerializer < SmartMessage::Serializer::Base
556
- def encode(message_instance)
557
- data = message_instance.to_h
558
- json = JSON.generate(data)
559
- json.force_encoding('UTF-8')
560
- end
561
-
562
- def decode(payload)
563
- # Ensure proper encoding
564
- payload = payload.force_encoding('UTF-8')
565
- JSON.parse(payload)
566
- end
567
- end
235
+ ### Monitoring
236
+ Each transport logs its serializer choice:
237
+ ```
238
+ [SmartMessage::Transport::RedisTransport] Using serializer: SmartMessage::Serializer::MessagePack
568
239
  ```
569
240
 
570
241
  ## Next Steps
571
242
 
572
- - [Transports](transports.md) - How serializers work with transports
573
- - [Examples](../getting-started/examples.md) - Real-world serialization patterns
243
+ - [Transports](transports.md) - Available transport implementations
244
+ - [Configuration](../getting-started/quick-start.md) - Setting up transports
245
+ - [Examples](../getting-started/examples.md) - Real-world usage patterns