smart_message 0.0.1 → 0.0.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: efdcf78330a702d97c6c59ec11495c04a42ef746fbe6ed12011711ba127a792c
4
- data.tar.gz: 395ae151a03376eab42036932e6ebbb437ddd0a42659a8ce8aca64fb80af45e7
3
+ metadata.gz: 8a7c214ec62b411d8f3bbf0925d6547fa135233684ac22483e028ffc76cc6cbe
4
+ data.tar.gz: f80ce67e2ea59172a36a8c7b675864c93573bf1f2b94e294124bdf2bbb28ae73
5
5
  SHA512:
6
- metadata.gz: d307903f836b3f1252bc8e6723c09112c4a89ace6dcb1fbf07581e1782b4ab92899ebaa4d00b74e1c615dd75b7e34a754c2adc84c9c1c894c1e5a679862742a7
7
- data.tar.gz: 966a81e21c5348b5c922f068a5edeb5709e73d6ae871eb0c653c76850b7f89ce4d1fde78ff5cd89df03e16cf8558fc6ce40c1949df179ba2f44f977ffe46b718
6
+ metadata.gz: da70af3b299ef64e94d8cefd87b3bb25b0a50dd3b835d4765a6f26231c65d0fa69b2ccf3d204d8de666aca2e241dcb37e396dcd064aaeae895881885e8c1ea21
7
+ data.tar.gz: fd2da658b323102bcb93e73f9b5d0ae843bd6afc7a8f031be7ebc206d89231f3304092d83de79524d7fd337f09a0bafad7b7bfc782e9f7a9820d32568c65e252
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ /*.log
1
2
  /.bundle/
2
3
  /.yardoc
3
4
  /_yardoc/
data/CHANGELOG.md CHANGED
@@ -7,7 +7,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
- ## [0.0.1] 2025-08-17
10
+ ## [0.0.2] - 2025-08-17
11
+
12
+ ### Added
13
+ - **Property Descriptions**: New property-level description system for message documentation
14
+ - Add descriptions to individual properties using `property :name, description: "text"`
15
+ - Access descriptions programmatically via `property_description(:name)` method
16
+ - Get all property descriptions with `property_descriptions` method
17
+ - List properties with descriptions using `described_properties` method
18
+ - Implemented via new `SmartMessage::PropertyDescriptions` module
19
+ - **Class-Level Descriptions**: New message class documentation system
20
+ - Set class descriptions using `description "text"` class method
21
+ - Retrieve descriptions with `MyMessage.description`
22
+ - Can be set within config blocks or after class definition
23
+ - Useful for API documentation and code generation tools
24
+ - **Enhanced Documentation**
25
+ - Added comprehensive property system documentation (`docs/properties.md`)
26
+ - Documents all Hashie::Dash options and SmartMessage enhancements
27
+ - Includes examples of property transformations, coercions, and translations
28
+ - Added to documentation table of contents
29
+
30
+ ### Changed
31
+ - Updated README.md with property and class description examples
32
+ - Enhanced SmartMessage::Base with property introspection capabilities
33
+
34
+ ### Tests
35
+ - Added comprehensive test suite for property descriptions (`test/property_descriptions_test.rb`)
36
+ - Added test suite for class-level descriptions (`test/description_test.rb`)
37
+ - Updated base_test.rb with class description test cases
38
+ - All tests passing with full backward compatibility
39
+
40
+ ## [0.0.1] - 2025-08-17
11
41
 
12
42
  ### Added
13
43
  - Comprehensive example applications demonstrating different messaging patterns
data/Gemfile.lock CHANGED
@@ -1,10 +1,11 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- smart_message (0.0.1)
4
+ smart_message (0.0.3)
5
5
  activesupport
6
6
  concurrent-ruby
7
7
  hashie
8
+ redis
8
9
 
9
10
  GEM
10
11
  remote: https://rubygems.org/
@@ -41,6 +42,10 @@ GEM
41
42
  mutex_m (0.3.0)
42
43
  power_assert (2.0.5)
43
44
  rake (13.3.0)
45
+ redis (5.4.1)
46
+ redis-client (>= 0.22.0)
47
+ redis-client (0.25.2)
48
+ connection_pool
44
49
  securerandom (0.4.1)
45
50
  shoulda (4.0.0)
46
51
  shoulda-context (~> 2.0)
data/README.md CHANGED
@@ -7,12 +7,14 @@ SmartMessage is a message abstraction framework that decouples business logic fr
7
7
 
8
8
  ## Features
9
9
 
10
- - **Transport Abstraction**: Plugin architecture supporting multiple message transports (RabbitMQ, Kafka, etc.)
10
+ - **Transport Abstraction**: Plugin architecture supporting multiple message transports (Redis, RabbitMQ, Kafka, etc.)
11
11
  - **Serialization Flexibility**: Pluggable serialization formats (JSON, MessagePack, etc.)
12
+ - **Flexible Message Handlers**: Multiple subscription patterns - default methods, custom methods, blocks, procs, and lambdas
12
13
  - **Dual-Level Configuration**: Class and instance-level plugin overrides for gateway patterns
13
14
  - **Concurrent Processing**: Thread-safe message routing using `Concurrent::CachedThreadPool`
14
15
  - **Built-in Statistics**: Message processing metrics and monitoring
15
16
  - **Development Tools**: STDOUT and in-memory transports for testing
17
+ - **Production Ready**: Redis transport with automatic reconnection and error handling
16
18
 
17
19
  ## Installation
18
20
 
@@ -36,10 +38,10 @@ Or install it yourself as:
36
38
 
37
39
  ```ruby
38
40
  class OrderMessage < SmartMessage::Base
39
- property :order_id
40
- property :customer_id
41
- property :amount
42
- property :items
41
+ property :order_id, description: "Unique order identifier"
42
+ property :customer_id, description: "Customer's unique ID"
43
+ property :amount, description: "Total order amount in dollars"
44
+ property :items, description: "Array of ordered items"
43
45
 
44
46
  # Configure transport and serializer at class level
45
47
  config do
@@ -85,12 +87,33 @@ order.publish
85
87
 
86
88
  ### 3. Subscribe to Messages
87
89
 
90
+ SmartMessage supports multiple ways to handle incoming messages:
91
+
88
92
  ```ruby
89
- # Subscribe to process incoming OrderMessage instances
93
+ # 1. Default handler (uses self.process method)
90
94
  OrderMessage.subscribe
91
95
 
92
- # Or specify a custom processing method
93
- OrderMessage.subscribe("OrderMessage.custom_processor")
96
+ # 2. Custom method handler
97
+ OrderMessage.subscribe("PaymentService.process_order")
98
+
99
+ # 3. Block handler (NEW!)
100
+ OrderMessage.subscribe do |header, payload|
101
+ order_data = JSON.parse(payload)
102
+ puts "Quick processing: Order #{order_data['order_id']}"
103
+ end
104
+
105
+ # 4. Proc handler (NEW!)
106
+ order_processor = proc do |header, payload|
107
+ order_data = JSON.parse(payload)
108
+ EmailService.send_confirmation(order_data['customer_id'])
109
+ end
110
+ OrderMessage.subscribe(order_processor)
111
+
112
+ # 5. Lambda handler (NEW!)
113
+ audit_handler = lambda do |header, payload|
114
+ AuditLog.record("Order processed at #{header.published_at}")
115
+ end
116
+ OrderMessage.subscribe(audit_handler)
94
117
  ```
95
118
 
96
119
  ## Architecture
@@ -109,6 +132,7 @@ Pluggable message delivery system with built-in implementations:
109
132
 
110
133
  - **StdoutTransport**: Development and testing transport
111
134
  - **MemoryTransport**: In-memory queuing for testing
135
+ - **RedisTransport**: Redis pub/sub transport for production messaging
112
136
  - **Custom Transports**: Implement `SmartMessage::Transport::Base`
113
137
 
114
138
  #### Serializer System
@@ -177,35 +201,85 @@ puts transport.all_messages
177
201
  transport.process_all # Process all pending messages
178
202
  ```
179
203
 
204
+ ### Redis Transport (Production)
205
+
206
+ ```ruby
207
+ # Basic Redis configuration
208
+ transport = SmartMessage::Transport.create(:redis,
209
+ url: 'redis://localhost:6379',
210
+ db: 0
211
+ )
212
+
213
+ # Production configuration with custom options
214
+ transport = SmartMessage::Transport.create(:redis,
215
+ url: 'redis://prod-redis:6379',
216
+ db: 1,
217
+ auto_subscribe: true,
218
+ reconnect_attempts: 5,
219
+ reconnect_delay: 2
220
+ )
221
+
222
+ # Configure message class to use Redis
223
+ MyMessage.config do
224
+ transport SmartMessage::Transport.create(:redis, url: 'redis://localhost:6379')
225
+ serializer SmartMessage::Serializer::JSON.new
226
+ end
227
+
228
+ # Subscribe to messages (uses message class name as Redis channel)
229
+ MyMessage.subscribe
230
+
231
+ # Publish messages (automatically publishes to Redis channel named "MyMessage")
232
+ message = MyMessage.new(data: "Hello Redis!")
233
+ message.publish
234
+ ```
235
+
236
+ The Redis transport uses the message class name as the Redis channel name, enabling automatic routing of messages to their appropriate handlers.
237
+
180
238
  ### Custom Transport
181
239
 
182
240
  ```ruby
183
- class RedisTransport < SmartMessage::Transport::Base
241
+ class WebhookTransport < SmartMessage::Transport::Base
184
242
  def default_options
185
- { redis_url: "redis://localhost:6379" }
243
+ {
244
+ webhook_url: "https://api.example.com/webhooks",
245
+ timeout: 30,
246
+ retries: 3
247
+ }
186
248
  end
187
249
 
188
250
  def configure
189
- @redis = Redis.new(url: @options[:redis_url])
251
+ require 'net/http'
252
+ @uri = URI(@options[:webhook_url])
190
253
  end
191
254
 
192
255
  def publish(message_header, message_payload)
193
- channel = message_header.message_class
194
- @redis.publish(channel, message_payload)
256
+ http = Net::HTTP.new(@uri.host, @uri.port)
257
+ http.use_ssl = @uri.scheme == 'https'
258
+
259
+ request = Net::HTTP::Post.new(@uri)
260
+ request['Content-Type'] = 'application/json'
261
+ request['X-Message-Class'] = message_header.message_class
262
+ request.body = message_payload
263
+
264
+ response = http.request(request)
265
+ raise "Webhook failed: #{response.code}" unless response.code.to_i < 400
195
266
  end
196
267
 
197
268
  def subscribe(message_class, process_method)
198
269
  super
199
- # Set up Redis subscription for message_class
270
+ # For webhooks, subscription would typically be configured
271
+ # externally on the webhook provider's side
200
272
  end
201
273
  end
202
274
 
203
275
  # Register the transport
204
- SmartMessage::Transport.register(:redis, RedisTransport)
276
+ SmartMessage::Transport.register(:webhook, WebhookTransport)
205
277
 
206
278
  # Use the transport
207
279
  MyMessage.config do
208
- transport SmartMessage::Transport.create(:redis, redis_url: "redis://prod:6379")
280
+ transport SmartMessage::Transport.create(:webhook,
281
+ webhook_url: "https://api.myservice.com/messages"
282
+ )
209
283
  end
210
284
  ```
211
285
 
@@ -214,8 +288,12 @@ end
214
288
  1. **Definition**: Create message class inheriting from `SmartMessage::Base`
215
289
  2. **Configuration**: Set transport, serializer, and logger plugins
216
290
  3. **Publishing**: Message instance is encoded and sent through transport
217
- 4. **Subscription**: Message classes register with dispatcher for processing
218
- 5. **Processing**: Received messages are decoded and `process` method is called
291
+ 4. **Subscription**: Message classes register handlers with dispatcher for processing
292
+ - Default handlers (`self.process` method)
293
+ - Custom method handlers (`"ClassName.method_name"`)
294
+ - Block handlers (`subscribe do |h,p|...end`)
295
+ - Proc/Lambda handlers (`subscribe(proc {...})`)
296
+ 5. **Processing**: Received messages are decoded and routed to registered handlers
219
297
 
220
298
  ## Advanced Usage
221
299
 
@@ -255,9 +333,9 @@ puts dispatcher.subscribers
255
333
 
256
334
  ```ruby
257
335
  class MyMessage < SmartMessage::Base
258
- property :user_id
259
- property :action
260
- property :timestamp, default: -> { Time.now }
336
+ property :user_id, description: "User's unique identifier"
337
+ property :action, description: "Action performed by the user"
338
+ property :timestamp, default: -> { Time.now }, description: "When the action occurred"
261
339
  end
262
340
 
263
341
  message = MyMessage.new(user_id: 123, action: "login")
@@ -266,6 +344,10 @@ message = MyMessage.new(user_id: 123, action: "login")
266
344
  puts message.user_id
267
345
  puts message.fields # Returns Set of property names (excluding internal _sm_ properties)
268
346
 
347
+ # Access property descriptions
348
+ puts MyMessage.property_description(:user_id) # => "User's unique identifier"
349
+ puts MyMessage.property_descriptions # => Hash of all descriptions
350
+
269
351
  # Access message header
270
352
  puts message._sm_header.uuid
271
353
  puts message._sm_header.message_class
data/docs/README.md CHANGED
@@ -8,14 +8,15 @@ Welcome to the comprehensive documentation for SmartMessage, a Ruby gem that abs
8
8
  - [Installation & Quick Start](getting-started.md)
9
9
  - [Basic Usage Examples](examples.md)
10
10
 
11
- ### Core Concepts
11
+ ### Core Concepts
12
12
  - [Architecture Overview](architecture.md)
13
13
  - [Message Lifecycle](message-lifecycle.md)
14
14
  - [Plugin System](plugin-system.md)
15
15
 
16
16
  ### Components
17
17
  - [SmartMessage::Base](base.md)
18
- - [Transport Layer](transports.md)
18
+ - [Property System](properties.md)
19
+ - [Transport Layer](transports.md)
19
20
  - [Serializers](serializers.md)
20
21
  - [Dispatcher & Routing](dispatcher.md)
21
22
  - [Message Headers](headers.md)
@@ -47,6 +48,6 @@ Welcome to the comprehensive documentation for SmartMessage, a Ruby gem that abs
47
48
 
48
49
  ## Version
49
50
 
50
- This documentation is for SmartMessage v0.0.1.
51
+ This documentation is for SmartMessage v0.0.2.
51
52
 
52
- For older versions, please check the git tags and corresponding documentation.
53
+ For older versions, please check the git tags and corresponding documentation.
data/docs/architecture.md CHANGED
@@ -40,10 +40,12 @@ SmartMessage is designed around the principle that **messages should be independ
40
40
 
41
41
 
42
42
  ┌─────────────────────┐
43
- Business Logic
43
+ Message Handlers
44
44
  │ │
45
- │ • process() method
46
- │ • Domain logic
45
+ │ • Default handler
46
+ │ • Block handlers
47
+ │ • Proc handlers │
48
+ │ • Method handlers │
47
49
  └─────────────────────┘
48
50
  ```
49
51
 
@@ -193,21 +195,52 @@ transport.receive(header, payload)
193
195
  # 1. Routes to dispatcher
194
196
  # 2. Dispatcher finds subscribers
195
197
  # 3. Spawns thread for processing
196
- # 4. Calls OrderMessage.process(header, payload)
198
+ # 4. Calls registered message handlers
197
199
  ```
198
200
 
199
- ### 5. Processing Phase
201
+ ### 5. Message Handler Processing
202
+
203
+ SmartMessage supports multiple handler types, routed through the dispatcher:
204
+
200
205
  ```ruby
206
+ # Default handler (self.process method)
201
207
  def self.process(message_header, message_payload)
202
- # 1. Decode payload
203
208
  data = JSON.parse(message_payload)
204
209
  order = new(data)
205
-
206
- # 2. Execute business logic
207
210
  fulfill_order(order)
208
211
  end
212
+
213
+ # Block handler (inline processing)
214
+ OrderMessage.subscribe do |header, payload|
215
+ data = JSON.parse(payload)
216
+ quick_processing(data)
217
+ end
218
+
219
+ # Proc handler (reusable across message types)
220
+ audit_proc = proc do |header, payload|
221
+ AuditService.log_message(header.message_class, payload)
222
+ end
223
+ OrderMessage.subscribe(audit_proc)
224
+
225
+ # Method handler (service class processing)
226
+ class OrderService
227
+ def self.process_order(header, payload)
228
+ data = JSON.parse(payload)
229
+ complex_business_logic(data)
230
+ end
231
+ end
232
+ OrderMessage.subscribe("OrderService.process_order")
209
233
  ```
210
234
 
235
+ **Handler Routing Process:**
236
+ 1. Dispatcher receives message and header
237
+ 2. Looks up all registered handlers for message class
238
+ 3. For each handler:
239
+ - **String handlers**: Resolves to class method via constantize
240
+ - **Proc handlers**: Calls proc directly from registry
241
+ 4. Executes handlers in parallel threads
242
+ 5. Collects statistics and handles errors
243
+
211
244
  ## Plugin System Architecture
212
245
 
213
246
  ### Dual-Level Configuration
data/docs/dispatcher.md CHANGED
@@ -28,27 +28,49 @@ Located at `lib/smart_message/dispatcher.rb:11-147`, the dispatcher is the centr
28
28
 
29
29
  ### Adding Subscriptions
30
30
 
31
+ SmartMessage supports multiple subscription patterns:
32
+
31
33
  ```ruby
32
- # Basic subscription - uses default process method
34
+ # 1. Default handler - uses self.process method
33
35
  MyMessage.subscribe
34
36
  # Registers "MyMessage.process" as the handler
35
37
 
36
- # Custom process method
37
- MyMessage.subscribe("MyMessage.custom_handler")
38
- # Registers "MyMessage.custom_handler" as the handler
38
+ # 2. Custom method handler
39
+ MyMessage.subscribe("MyService.handle_message")
40
+ # Registers "MyService.handle_message" as the handler
41
+
42
+ # 3. Block handler (NEW!)
43
+ handler_id = MyMessage.subscribe do |header, payload|
44
+ puts "Processing: #{JSON.parse(payload)}"
45
+ end
46
+ # Registers a proc handler with generated ID like "MyMessage.proc_abc123"
47
+
48
+ # 4. Proc handler (NEW!)
49
+ my_proc = proc { |header, payload| log_message(payload) }
50
+ proc_id = MyMessage.subscribe(my_proc)
51
+ # Registers the proc with generated ID
52
+
53
+ # 5. Lambda handler (NEW!)
54
+ my_lambda = lambda { |header, payload| validate_message(payload) }
55
+ lambda_id = MyMessage.subscribe(my_lambda)
39
56
 
40
57
  # Multiple handlers for the same message
41
- MyMessage.subscribe("MyMessage.handler_one")
42
- MyMessage.subscribe("MyMessage.handler_two")
43
- # Both handlers will receive the message
58
+ MyMessage.subscribe("MyMessage.audit")
59
+ MyMessage.subscribe("MyMessage.notify")
60
+ MyMessage.subscribe { |h,p| puts "Quick log" }
61
+ # All handlers will receive the message
44
62
  ```
45
63
 
46
64
  ### Removing Subscriptions
47
65
 
48
66
  ```ruby
49
- # Remove specific handler
67
+ # Remove specific method handler
50
68
  MyMessage.unsubscribe("MyMessage.custom_handler")
51
69
 
70
+ # Remove specific proc/block handler using returned ID
71
+ block_id = MyMessage.subscribe { |h,p| puts p }
72
+ MyMessage.unsubscribe(block_id) # Cleans up proc from registry too
73
+
52
74
  # Remove ALL handlers for a message class
53
75
  MyMessage.unsubscribe!
54
76
 
@@ -101,7 +123,7 @@ end
101
123
 
102
124
  ### 3. Concurrent Processing
103
125
 
104
- Each handler is processed in its own thread:
126
+ Each handler is processed in its own thread, with support for both method and proc handlers:
105
127
 
106
128
  ```ruby
107
129
  @subscribers[message_klass].each do |message_processor|
@@ -109,21 +131,35 @@ Each handler is processed in its own thread:
109
131
 
110
132
  @router_pool.post do
111
133
  # This runs in a separate thread
112
- parts = message_processor.split('.')
113
- target_klass = parts[0] # "MyMessage"
114
- class_method = parts[1] # "process"
115
-
116
134
  begin
117
- result = target_klass.constantize
118
- .method(class_method)
119
- .call(message_header, message_payload)
135
+ # Check if this is a proc handler or a regular method call
136
+ if proc_handler?(message_processor)
137
+ # Call the proc handler via SmartMessage::Base
138
+ SmartMessage::Base.call_proc_handler(message_processor, message_header, message_payload)
139
+ else
140
+ # Original method call logic
141
+ parts = message_processor.split('.')
142
+ target_klass = parts[0] # "MyMessage"
143
+ class_method = parts[1] # "process"
144
+
145
+ target_klass.constantize
146
+ .method(class_method)
147
+ .call(message_header, message_payload)
148
+ end
120
149
  rescue Exception => e
121
150
  # Error handling - doesn't crash the dispatcher
151
+ puts "Error processing message: #{e.message}" if $DEBUG
122
152
  end
123
153
  end
124
154
  end
125
155
  ```
126
156
 
157
+ **Handler Types Processed:**
158
+ - **Method handlers**: `"ClassName.method_name"` → resolved via constantize
159
+ - **Proc handlers**: `"ClassName.proc_abc123"` → looked up in proc registry
160
+ - **Block handlers**: `"ClassName.proc_def456"` → treated as proc handlers
161
+ - **Lambda handlers**: `"ClassName.proc_ghi789"` → treated as proc handlers
162
+
127
163
  ## Thread Pool Management
128
164
 
129
165
  ### Thread Pool Configuration
@@ -64,11 +64,27 @@ end
64
64
 
65
65
  ### 2. Subscribe to Messages
66
66
 
67
- Before publishing, set up a subscription to receive messages:
67
+ Before publishing, set up a subscription to receive messages. SmartMessage provides several ways to handle incoming messages:
68
68
 
69
69
  ```ruby
70
- # Subscribe to process incoming WelcomeMessage instances
70
+ # 1. Default handler (uses the self.process method defined above)
71
71
  WelcomeMessage.subscribe
72
+
73
+ # 2. Block handler (inline processing logic)
74
+ WelcomeMessage.subscribe do |header, payload|
75
+ data = JSON.parse(payload)
76
+ puts "👋 Quick welcome for #{data['user_name']}"
77
+ end
78
+
79
+ # 3. Proc handler (reusable processing logic)
80
+ welcome_processor = proc do |header, payload|
81
+ data = JSON.parse(payload)
82
+ EmailService.send_welcome_email(data['email'], data['user_name'])
83
+ end
84
+ WelcomeMessage.subscribe(welcome_processor)
85
+
86
+ # 4. Custom method handler
87
+ WelcomeMessage.subscribe("UserService.handle_welcome")
72
88
  ```
73
89
 
74
90
  ### 3. Create and Publish a Message
@@ -153,6 +169,52 @@ Serializers handle message encoding/decoding:
153
169
  serializer SmartMessage::Serializer::JSON.new
154
170
  ```
155
171
 
172
+ ### Message Handlers
173
+
174
+ SmartMessage supports four types of message handlers to give you flexibility in how you process messages:
175
+
176
+ ```ruby
177
+ class OrderMessage < SmartMessage::Base
178
+ # Define your message properties
179
+ property :order_id
180
+ property :amount
181
+
182
+ # Default handler - processed when no custom handler specified
183
+ def self.process(header, payload)
184
+ puts "Default processing for order"
185
+ end
186
+ end
187
+
188
+ # 1. Default handler (uses self.process)
189
+ OrderMessage.subscribe
190
+
191
+ # 2. Block handler - great for simple, inline logic
192
+ OrderMessage.subscribe do |header, payload|
193
+ data = JSON.parse(payload)
194
+ puts "Block handler: Processing order #{data['order_id']}"
195
+ end
196
+
197
+ # 3. Proc handler - reusable across message types
198
+ audit_logger = proc do |header, payload|
199
+ puts "Audit: #{header.message_class} at #{header.published_at}"
200
+ end
201
+ OrderMessage.subscribe(audit_logger)
202
+
203
+ # 4. Method handler - organized in service classes
204
+ class OrderService
205
+ def self.process_order(header, payload)
206
+ puts "Service processing order"
207
+ end
208
+ end
209
+ OrderMessage.subscribe("OrderService.process_order")
210
+ ```
211
+
212
+ **When to use each type:**
213
+ - **Default**: Simple built-in processing for the message type
214
+ - **Block**: Quick inline logic specific to one subscription
215
+ - **Proc**: Reusable handlers that work across multiple message types
216
+ - **Method**: Complex business logic organized in service classes
217
+
156
218
  ## Next Steps
157
219
 
158
220
  Now that you have the basics working, explore: