smart_message 0.0.5 → 0.0.6
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 +67 -0
- data/Gemfile.lock +1 -1
- data/README.md +58 -4
- data/docs/README.md +1 -0
- data/docs/addressing.md +364 -0
- data/docs/getting-started.md +38 -0
- data/examples/08_entity_addressing_basic.rb +366 -0
- data/examples/08_entity_addressing_with_filtering.rb +418 -0
- data/examples/README.md +68 -0
- data/lib/smart_message/base.rb +201 -12
- data/lib/smart_message/dispatcher.rb +53 -5
- data/lib/smart_message/header.rb +14 -0
- data/lib/smart_message/transport/base.rb +3 -2
- data/lib/smart_message/transport/redis_transport.rb +2 -2
- data/lib/smart_message/version.rb +1 -1
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eac068dc19706e57d2c66a1dfe36981fbac33e6d7b180fe0429f81d874727cd4
|
4
|
+
data.tar.gz: 91585bc79637c4feab1256716519c0c3c7aa36c2b313ed09ebee7788b11d3f1a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a0c0ead05e3cb104873e5cfa53cfc182ee06c6fd2f2e56fe02c0d64a4313dc4356b84d3b5be251e5438e6e381812848f6f587b005a315282204d8160f785f87b
|
7
|
+
data.tar.gz: 3a84537cca151b3b8f3efa16b9ad8591811be19ab5547013fe9f33d7df58474e5db2a74e85e669fb95c17e5b375dd2d889b3a3051b6ded765120dd208246c26a
|
data/CHANGELOG.md
CHANGED
@@ -7,6 +7,73 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## [0.0.6] 2025-08-19
|
11
|
+
|
12
|
+
### Added
|
13
|
+
- **Entity-Aware Message Filtering**: Advanced subscription filtering system enabling precise message routing
|
14
|
+
- New subscription filter parameters: `broadcast:`, `to:`, `from:` for `subscribe` method
|
15
|
+
- Filter by broadcast messages only: `MyMessage.subscribe(broadcast: true)`
|
16
|
+
- Filter by destination entity: `MyMessage.subscribe(to: 'service-name')`
|
17
|
+
- Filter by sender entity: `MyMessage.subscribe(from: 'sender-service')`
|
18
|
+
- Support for array-based filters: `subscribe(from: ['admin', 'system'])`
|
19
|
+
- Combined filters with OR logic: `subscribe(broadcast: true, to: 'my-service')`
|
20
|
+
- String-to-array automatic conversion for convenience: `subscribe(to: 'service')` becomes `['service']`
|
21
|
+
- Full backward compatibility - existing subscriptions work unchanged
|
22
|
+
- **Real-Time Header Synchronization**: Message headers now update automatically when addressing fields change
|
23
|
+
- Instance-level `from()`, `to()`, `reply_to()` methods now update both instance variables and message headers
|
24
|
+
- Enables filtering to work correctly when addressing is changed after message creation
|
25
|
+
- Reset methods (`reset_from`, `reset_to`, `reset_reply_to`) also update headers
|
26
|
+
- Critical for entity-aware filtering functionality
|
27
|
+
- **Enhanced Example Programs**
|
28
|
+
- New comprehensive filtering example: `examples/08_entity_addressing_with_filtering.rb`
|
29
|
+
- Demonstrates all filtering capabilities with real-world microservice scenarios
|
30
|
+
- Improved timing with sleep statements for better output visualization
|
31
|
+
- Updated basic addressing example: `examples/08_entity_addressing_basic.rb`
|
32
|
+
- Both examples now show clear interleaved publish/receive output flow
|
33
|
+
|
34
|
+
### Changed
|
35
|
+
- **Message Subscription Architecture**: Subscription storage updated to support filtering
|
36
|
+
- Dispatcher now stores subscription objects with filter criteria instead of simple method strings
|
37
|
+
- Subscription objects contain `{process_method: string, filters: hash}` structure
|
38
|
+
- All transport implementations updated to pass filter options through subscription chain
|
39
|
+
- RedisTransport updated to accept new filter_options parameter
|
40
|
+
- **Header Addressing Behavior**: Message headers now reflect real-time addressing changes
|
41
|
+
- **BREAKING**: Headers are no longer immutable after creation - they update when addressing methods are called
|
42
|
+
- This change enables entity-aware filtering to work correctly with dynamic addressing
|
43
|
+
- Previous behavior kept original addressing in headers while instance methods showed new values
|
44
|
+
|
45
|
+
### Fixed
|
46
|
+
- **Message Filtering Logic**: Resolved critical filtering implementation issues
|
47
|
+
- Fixed message_matches_filters? method to properly evaluate filter criteria
|
48
|
+
- Corrected AND/OR logic for combined broadcast and entity-specific filters
|
49
|
+
- Ensured filtering works with both class-level and instance-level addressing
|
50
|
+
- **Test Suite Compatibility**: Updated all tests to work with new subscription structure
|
51
|
+
- Fixed ProcHandlerTest to expect subscription objects instead of string arrays
|
52
|
+
- Updated TransportTest to handle new subscription object format
|
53
|
+
- Fixed AddressingTest to reflect new real-time header update behavior
|
54
|
+
- All existing functionality preserved with full backward compatibility
|
55
|
+
|
56
|
+
### Enhanced
|
57
|
+
- **Message Processing Performance**: Filtering happens at subscription level, reducing processing overhead
|
58
|
+
- Messages not matching filter criteria are ignored by handlers, improving efficiency
|
59
|
+
- Enables microservices to process only relevant messages
|
60
|
+
- Reduces unnecessary handler invocations and processing cycles
|
61
|
+
- **Developer Experience**: Clear examples demonstrate filtering benefits and usage patterns
|
62
|
+
- Examples show both what DOES and DOESN'T get processed
|
63
|
+
- Demonstrates gateway patterns, admin message handling, and microservice communication
|
64
|
+
- Educational value enhanced with comprehensive console output and timing
|
65
|
+
|
66
|
+
### Documentation
|
67
|
+
- **Entity-Aware Filtering Guide**: Comprehensive examples showing all filtering capabilities
|
68
|
+
- Broadcast vs directed message handling patterns
|
69
|
+
- Admin/monitoring system integration examples
|
70
|
+
- Request-reply routing with filters
|
71
|
+
- Gateway pattern implementations with dynamic routing
|
72
|
+
- Best practices for microservice message filtering
|
73
|
+
- **Breaking Change Documentation**: Clear explanation of header behavior changes
|
74
|
+
- Migration guide for applications depending on immutable headers
|
75
|
+
- Benefits of real-time header updates for filtering functionality
|
76
|
+
|
10
77
|
## [0.0.5] 2025-08-18
|
11
78
|
|
12
79
|
### Added
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -9,6 +9,7 @@ SmartMessage is a message abstraction framework that decouples business logic fr
|
|
9
9
|
|
10
10
|
- **Transport Abstraction**: Plugin architecture supporting multiple message transports (Redis, RabbitMQ, Kafka, etc.)
|
11
11
|
- **Serialization Flexibility**: Pluggable serialization formats (JSON, MessagePack, etc.)
|
12
|
+
- **Entity-to-Entity Addressing**: Built-in FROM/TO/REPLY_TO addressing for point-to-point and broadcast messaging patterns
|
12
13
|
- **Schema Versioning**: Built-in version management with automatic compatibility validation
|
13
14
|
- **Comprehensive Validation**: Property validation with custom error messages and automatic validation before publishing
|
14
15
|
- **Message Documentation**: Built-in documentation support for message classes and properties with automatic defaults
|
@@ -47,6 +48,11 @@ class OrderMessage < SmartMessage::Base
|
|
47
48
|
# Add a description for the message class
|
48
49
|
description "Represents customer order data for processing and fulfillment"
|
49
50
|
|
51
|
+
# Configure entity addressing
|
52
|
+
from 'order-service'
|
53
|
+
to 'fulfillment-service' # Point-to-point message
|
54
|
+
reply_to 'order-service' # Responses come back here
|
55
|
+
|
50
56
|
# Required properties with validation
|
51
57
|
property :order_id,
|
52
58
|
required: true,
|
@@ -153,6 +159,50 @@ end
|
|
153
159
|
OrderMessage.subscribe(audit_handler)
|
154
160
|
```
|
155
161
|
|
162
|
+
### 4. Entity Addressing
|
163
|
+
|
164
|
+
SmartMessage supports entity-to-entity addressing with FROM/TO/REPLY_TO fields for advanced message routing:
|
165
|
+
|
166
|
+
```ruby
|
167
|
+
# Point-to-point messaging
|
168
|
+
class PaymentMessage < SmartMessage::Base
|
169
|
+
version 1
|
170
|
+
from 'payment-service' # Required: sender identity
|
171
|
+
to 'bank-gateway' # Optional: specific recipient
|
172
|
+
reply_to 'payment-service' # Optional: where responses go
|
173
|
+
|
174
|
+
property :amount, required: true
|
175
|
+
property :account_id, required: true
|
176
|
+
end
|
177
|
+
|
178
|
+
# Broadcast messaging (no 'to' specified)
|
179
|
+
class SystemAnnouncementMessage < SmartMessage::Base
|
180
|
+
version 1
|
181
|
+
from 'admin-service' # Required: sender identity
|
182
|
+
# No 'to' field = broadcast to all subscribers
|
183
|
+
|
184
|
+
property :message, required: true
|
185
|
+
property :priority, default: 'normal'
|
186
|
+
end
|
187
|
+
|
188
|
+
# Instance-level addressing override
|
189
|
+
payment = PaymentMessage.new(amount: 100.00, account_id: "ACCT-123")
|
190
|
+
payment.to('backup-gateway') # Override destination for this instance
|
191
|
+
payment.publish
|
192
|
+
|
193
|
+
# Access addressing information
|
194
|
+
puts payment._sm_header.from # => 'payment-service'
|
195
|
+
puts payment._sm_header.to # => 'backup-gateway'
|
196
|
+
puts payment._sm_header.reply_to # => 'payment-service'
|
197
|
+
```
|
198
|
+
|
199
|
+
#### Messaging Patterns Supported
|
200
|
+
|
201
|
+
- **Point-to-Point**: Set `to` field for direct entity targeting
|
202
|
+
- **Broadcast**: Omit `to` field (nil) for message broadcast to all subscribers
|
203
|
+
- **Request-Reply**: Use `reply_to` field to specify response routing
|
204
|
+
- **Gateway Patterns**: Override addressing at instance level for message forwarding
|
205
|
+
|
156
206
|
## Architecture
|
157
207
|
|
158
208
|
### Core Components
|
@@ -323,15 +373,16 @@ end
|
|
323
373
|
## Message Lifecycle
|
324
374
|
|
325
375
|
1. **Definition**: Create message class inheriting from `SmartMessage::Base`
|
326
|
-
2. **Configuration**: Set transport, serializer, and
|
327
|
-
3. **Validation**: Messages are automatically validated before publishing (properties, header, version compatibility)
|
328
|
-
4. **Publishing**: Message instance is encoded and sent through transport
|
376
|
+
2. **Configuration**: Set transport, serializer, logger plugins, and entity addressing (from/to/reply_to)
|
377
|
+
3. **Validation**: Messages are automatically validated before publishing (properties, header, addressing, version compatibility)
|
378
|
+
4. **Publishing**: Message instance is encoded with addressing metadata and sent through transport
|
329
379
|
5. **Subscription**: Message classes register handlers with dispatcher for processing
|
330
380
|
- Default handlers (`self.process` method)
|
331
381
|
- Custom method handlers (`"ClassName.method_name"`)
|
332
382
|
- Block handlers (`subscribe do |h,p|...end`)
|
333
383
|
- Proc/Lambda handlers (`subscribe(proc {...})`)
|
334
|
-
6. **
|
384
|
+
6. **Routing**: Dispatcher uses addressing metadata to route messages (point-to-point vs broadcast)
|
385
|
+
7. **Processing**: Received messages are decoded and routed to registered handlers
|
335
386
|
|
336
387
|
## Schema Versioning and Validation
|
337
388
|
|
@@ -588,6 +639,9 @@ puts message._sm_header.uuid
|
|
588
639
|
puts message._sm_header.message_class
|
589
640
|
puts message._sm_header.published_at
|
590
641
|
puts message._sm_header.publisher_pid
|
642
|
+
puts message._sm_header.from
|
643
|
+
puts message._sm_header.to
|
644
|
+
puts message._sm_header.reply_to
|
591
645
|
```
|
592
646
|
|
593
647
|
## Development
|
data/docs/README.md
CHANGED
@@ -16,6 +16,7 @@ Welcome to the comprehensive documentation for SmartMessage, a Ruby gem that abs
|
|
16
16
|
### Components
|
17
17
|
- [SmartMessage::Base](base.md)
|
18
18
|
- [Property System](properties.md)
|
19
|
+
- [Entity Addressing](addressing.md)
|
19
20
|
- [Transport Layer](transports.md)
|
20
21
|
- [Serializers](serializers.md)
|
21
22
|
- [Logging System](logging.md)
|
data/docs/addressing.md
ADDED
@@ -0,0 +1,364 @@
|
|
1
|
+
# Entity Addressing
|
2
|
+
|
3
|
+
SmartMessage supports entity-to-entity addressing through built-in FROM/TO/REPLY_TO fields in message headers. This enables sophisticated messaging patterns including point-to-point communication, broadcast messaging, and request-reply workflows.
|
4
|
+
|
5
|
+
## Overview
|
6
|
+
|
7
|
+
Entity addressing in SmartMessage provides:
|
8
|
+
|
9
|
+
- **Sender Identification**: Required `from` field identifies the sending entity
|
10
|
+
- **Recipient Targeting**: Optional `to` field for point-to-point messaging
|
11
|
+
- **Response Routing**: Optional `reply_to` field for request-reply patterns
|
12
|
+
- **Broadcast Support**: Omitting `to` field enables broadcast to all subscribers
|
13
|
+
- **Dual-Level Configuration**: Class and instance-level addressing configuration
|
14
|
+
|
15
|
+
## Address Fields
|
16
|
+
|
17
|
+
### FROM (Required)
|
18
|
+
The `from` field identifies the entity sending the message. This is required for all messages.
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
class MyMessage < SmartMessage::Base
|
22
|
+
from 'order-service' # Required sender identity
|
23
|
+
|
24
|
+
property :data
|
25
|
+
end
|
26
|
+
```
|
27
|
+
|
28
|
+
### TO (Optional)
|
29
|
+
The `to` field specifies the intended recipient entity. When present, creates point-to-point messaging. When `nil`, the message is broadcast to all subscribers.
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
# Point-to-point messaging
|
33
|
+
class DirectMessage < SmartMessage::Base
|
34
|
+
from 'sender-service'
|
35
|
+
to 'recipient-service' # Specific target
|
36
|
+
|
37
|
+
property :content
|
38
|
+
end
|
39
|
+
|
40
|
+
# Broadcast messaging
|
41
|
+
class AnnouncementMessage < SmartMessage::Base
|
42
|
+
from 'admin-service'
|
43
|
+
# No 'to' field = broadcast to all subscribers
|
44
|
+
|
45
|
+
property :announcement
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
### REPLY_TO (Optional)
|
50
|
+
The `reply_to` field specifies where responses should be sent. Defaults to the `from` entity if not specified.
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
class RequestMessage < SmartMessage::Base
|
54
|
+
from 'client-service'
|
55
|
+
to 'api-service'
|
56
|
+
reply_to 'client-callback-service' # Responses go here
|
57
|
+
|
58
|
+
property :request_data
|
59
|
+
end
|
60
|
+
```
|
61
|
+
|
62
|
+
## Configuration Patterns
|
63
|
+
|
64
|
+
### Class-Level Configuration
|
65
|
+
|
66
|
+
Set default addressing for all instances of a message class:
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
class PaymentMessage < SmartMessage::Base
|
70
|
+
version 1
|
71
|
+
|
72
|
+
# Class-level addressing
|
73
|
+
from 'payment-service'
|
74
|
+
to 'bank-gateway'
|
75
|
+
reply_to 'payment-service'
|
76
|
+
|
77
|
+
property :amount, required: true
|
78
|
+
property :account_id, required: true
|
79
|
+
end
|
80
|
+
|
81
|
+
# All instances inherit class addressing
|
82
|
+
payment = PaymentMessage.new(amount: 100.00, account_id: "ACCT-123")
|
83
|
+
puts payment._sm_header.from # => 'payment-service'
|
84
|
+
puts payment._sm_header.to # => 'bank-gateway'
|
85
|
+
puts payment._sm_header.reply_to # => 'payment-service'
|
86
|
+
```
|
87
|
+
|
88
|
+
### Instance-Level Overrides
|
89
|
+
|
90
|
+
Override addressing for specific message instances:
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
class FlexibleMessage < SmartMessage::Base
|
94
|
+
from 'service-a'
|
95
|
+
to 'service-b'
|
96
|
+
|
97
|
+
property :data
|
98
|
+
end
|
99
|
+
|
100
|
+
# Override addressing for this instance
|
101
|
+
message = FlexibleMessage.new(data: "test")
|
102
|
+
message.from('different-sender')
|
103
|
+
message.to('different-recipient')
|
104
|
+
message.reply_to('different-reply-service')
|
105
|
+
|
106
|
+
puts message.from # => 'different-sender'
|
107
|
+
puts message.to # => 'different-recipient'
|
108
|
+
puts message.reply_to # => 'different-reply-service'
|
109
|
+
|
110
|
+
# Class defaults remain unchanged
|
111
|
+
puts FlexibleMessage.from # => 'service-a'
|
112
|
+
puts FlexibleMessage.to # => 'service-b'
|
113
|
+
```
|
114
|
+
|
115
|
+
## Messaging Patterns
|
116
|
+
|
117
|
+
### Point-to-Point Messaging
|
118
|
+
|
119
|
+
Direct communication between two specific entities:
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
class OrderProcessingMessage < SmartMessage::Base
|
123
|
+
from 'order-service'
|
124
|
+
to 'inventory-service' # Direct target
|
125
|
+
reply_to 'order-service'
|
126
|
+
|
127
|
+
property :order_id, required: true
|
128
|
+
property :items, required: true
|
129
|
+
end
|
130
|
+
|
131
|
+
# Message goes directly to inventory-service
|
132
|
+
order = OrderProcessingMessage.new(
|
133
|
+
order_id: "ORD-123",
|
134
|
+
items: ["widget-1", "widget-2"]
|
135
|
+
)
|
136
|
+
order.publish # Only inventory-service receives this
|
137
|
+
```
|
138
|
+
|
139
|
+
### Broadcast Messaging
|
140
|
+
|
141
|
+
Send message to all subscribers by omitting the `to` field:
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
class SystemMaintenanceMessage < SmartMessage::Base
|
145
|
+
from 'admin-service'
|
146
|
+
# No 'to' field = broadcast
|
147
|
+
|
148
|
+
property :message, required: true
|
149
|
+
property :scheduled_time, required: true
|
150
|
+
end
|
151
|
+
|
152
|
+
# Message goes to all subscribers
|
153
|
+
maintenance = SystemMaintenanceMessage.new(
|
154
|
+
message: "System maintenance tonight at 2 AM",
|
155
|
+
scheduled_time: Time.parse("2024-01-15 02:00:00")
|
156
|
+
)
|
157
|
+
maintenance.publish # All subscribers receive this
|
158
|
+
```
|
159
|
+
|
160
|
+
### Request-Reply Pattern
|
161
|
+
|
162
|
+
Structured request-response communication:
|
163
|
+
|
164
|
+
```ruby
|
165
|
+
# Request message
|
166
|
+
class UserLookupRequest < SmartMessage::Base
|
167
|
+
from 'web-service'
|
168
|
+
to 'user-service'
|
169
|
+
reply_to 'web-service' # Responses come back here
|
170
|
+
|
171
|
+
property :user_id, required: true
|
172
|
+
property :request_id, required: true # For correlation
|
173
|
+
end
|
174
|
+
|
175
|
+
# Response message
|
176
|
+
class UserLookupResponse < SmartMessage::Base
|
177
|
+
from 'user-service'
|
178
|
+
# 'to' will be set to the original 'reply_to' value
|
179
|
+
|
180
|
+
property :user_id, required: true
|
181
|
+
property :request_id, required: true # Correlation ID
|
182
|
+
property :user_data
|
183
|
+
property :success, default: true
|
184
|
+
end
|
185
|
+
|
186
|
+
# Send request
|
187
|
+
request = UserLookupRequest.new(
|
188
|
+
user_id: "USER-123",
|
189
|
+
request_id: SecureRandom.uuid
|
190
|
+
)
|
191
|
+
request.publish
|
192
|
+
|
193
|
+
# In user-service handler:
|
194
|
+
class UserLookupRequest
|
195
|
+
def self.process(header, payload)
|
196
|
+
request_data = JSON.parse(payload)
|
197
|
+
|
198
|
+
# Process lookup...
|
199
|
+
user_data = UserService.find(request_data['user_id'])
|
200
|
+
|
201
|
+
# Send response back to reply_to address
|
202
|
+
response = UserLookupResponse.new(
|
203
|
+
user_id: request_data['user_id'],
|
204
|
+
request_id: request_data['request_id'],
|
205
|
+
user_data: user_data
|
206
|
+
)
|
207
|
+
response.to(header.reply_to) # Send to original reply_to
|
208
|
+
response.publish
|
209
|
+
end
|
210
|
+
end
|
211
|
+
```
|
212
|
+
|
213
|
+
### Gateway Pattern
|
214
|
+
|
215
|
+
Forward messages between different transports/formats:
|
216
|
+
|
217
|
+
```ruby
|
218
|
+
class GatewayMessage < SmartMessage::Base
|
219
|
+
from 'gateway-service'
|
220
|
+
|
221
|
+
property :original_message
|
222
|
+
property :source_format
|
223
|
+
property :target_format
|
224
|
+
end
|
225
|
+
|
226
|
+
# Receive from one transport/format
|
227
|
+
incoming = SomeMessage.new(data: "from system A")
|
228
|
+
|
229
|
+
# Forward to different system with different addressing
|
230
|
+
gateway_msg = GatewayMessage.new(
|
231
|
+
original_message: incoming.to_h,
|
232
|
+
source_format: 'json',
|
233
|
+
target_format: 'xml'
|
234
|
+
)
|
235
|
+
|
236
|
+
# Override transport and addressing for forwarding
|
237
|
+
gateway_msg.config do
|
238
|
+
transport DifferentTransport.new
|
239
|
+
serializer DifferentSerializer.new
|
240
|
+
end
|
241
|
+
gateway_msg.to('system-b')
|
242
|
+
gateway_msg.publish
|
243
|
+
```
|
244
|
+
|
245
|
+
## Address Validation
|
246
|
+
|
247
|
+
The `from` field is required and validated automatically:
|
248
|
+
|
249
|
+
```ruby
|
250
|
+
class InvalidMessage < SmartMessage::Base
|
251
|
+
# No 'from' specified - will fail validation
|
252
|
+
property :data
|
253
|
+
end
|
254
|
+
|
255
|
+
message = InvalidMessage.new(data: "test")
|
256
|
+
message.publish # Raises SmartMessage::Errors::ValidationError
|
257
|
+
# => "The property 'from' From entity ID is required for message routing and replies"
|
258
|
+
```
|
259
|
+
|
260
|
+
## Header Access
|
261
|
+
|
262
|
+
Access addressing information from message headers:
|
263
|
+
|
264
|
+
```ruby
|
265
|
+
class SampleMessage < SmartMessage::Base
|
266
|
+
from 'sample-service'
|
267
|
+
to 'target-service'
|
268
|
+
reply_to 'callback-service'
|
269
|
+
|
270
|
+
property :content
|
271
|
+
end
|
272
|
+
|
273
|
+
message = SampleMessage.new(content: "Hello")
|
274
|
+
header = message._sm_header
|
275
|
+
|
276
|
+
puts header.from # => 'sample-service'
|
277
|
+
puts header.to # => 'target-service'
|
278
|
+
puts header.reply_to # => 'callback-service'
|
279
|
+
puts header.uuid # => Generated UUID
|
280
|
+
puts header.message_class # => 'SampleMessage'
|
281
|
+
```
|
282
|
+
|
283
|
+
## Integration with Dispatcher
|
284
|
+
|
285
|
+
The dispatcher can use addressing metadata for advanced routing logic:
|
286
|
+
|
287
|
+
```ruby
|
288
|
+
# Future enhancement: Dispatcher filtering by recipient
|
289
|
+
# dispatcher.route(message_header, payload) do |header|
|
290
|
+
# if header.to.nil?
|
291
|
+
# # Broadcast to all subscribers
|
292
|
+
# route_to_all_subscribers(header.message_class)
|
293
|
+
# else
|
294
|
+
# # Route only to specific recipient
|
295
|
+
# route_to_entity(header.to, header.message_class)
|
296
|
+
# end
|
297
|
+
# end
|
298
|
+
```
|
299
|
+
|
300
|
+
## Best Practices
|
301
|
+
|
302
|
+
### Entity Naming
|
303
|
+
Use consistent, descriptive entity identifiers:
|
304
|
+
|
305
|
+
```ruby
|
306
|
+
# Good: Descriptive service names
|
307
|
+
from 'order-management-service'
|
308
|
+
to 'inventory-tracking-service'
|
309
|
+
reply_to 'order-status-service'
|
310
|
+
|
311
|
+
# Avoid: Generic or unclear names
|
312
|
+
from 'service1'
|
313
|
+
to 'app'
|
314
|
+
```
|
315
|
+
|
316
|
+
### Address Consistency
|
317
|
+
Maintain consistent addressing patterns across your application:
|
318
|
+
|
319
|
+
```ruby
|
320
|
+
# Consistent pattern for microservices
|
321
|
+
class OrderMessage < SmartMessage::Base
|
322
|
+
from 'order-service'
|
323
|
+
to 'fulfillment-service'
|
324
|
+
reply_to 'order-service'
|
325
|
+
end
|
326
|
+
|
327
|
+
class PaymentMessage < SmartMessage::Base
|
328
|
+
from 'payment-service'
|
329
|
+
to 'billing-service'
|
330
|
+
reply_to 'payment-service'
|
331
|
+
end
|
332
|
+
```
|
333
|
+
|
334
|
+
### Gateway Configuration
|
335
|
+
For gateway patterns, use instance-level overrides:
|
336
|
+
|
337
|
+
```ruby
|
338
|
+
# Class defines default routing
|
339
|
+
class APIMessage < SmartMessage::Base
|
340
|
+
from 'api-gateway'
|
341
|
+
to 'internal-service'
|
342
|
+
end
|
343
|
+
|
344
|
+
# Override for external routing
|
345
|
+
message = APIMessage.new(data: "external request")
|
346
|
+
message.to('external-partner-service')
|
347
|
+
message.config do
|
348
|
+
transport ExternalTransport.new
|
349
|
+
serializer SecureSerializer.new
|
350
|
+
end
|
351
|
+
message.publish
|
352
|
+
```
|
353
|
+
|
354
|
+
## Future Enhancements
|
355
|
+
|
356
|
+
The addressing system provides the foundation for advanced features:
|
357
|
+
|
358
|
+
- **Dispatcher Filtering**: Route messages based on recipient targeting
|
359
|
+
- **Security Integration**: Entity-based authentication and authorization
|
360
|
+
- **Audit Trails**: Track message flow between entities
|
361
|
+
- **Load Balancing**: Distribute messages across entity instances
|
362
|
+
- **Circuit Breakers**: Per-entity failure handling
|
363
|
+
|
364
|
+
Entity addressing enables sophisticated messaging architectures while maintaining the simplicity and flexibility that makes SmartMessage powerful.
|
data/docs/getting-started.md
CHANGED
@@ -40,6 +40,11 @@ class WelcomeMessage < SmartMessage::Base
|
|
40
40
|
# Add a description for the message class
|
41
41
|
description "Welcomes new users after successful signup"
|
42
42
|
|
43
|
+
# Configure entity addressing
|
44
|
+
from 'user-service' # Required: identifies sender
|
45
|
+
to 'notification-service' # Optional: specific recipient
|
46
|
+
reply_to 'user-service' # Optional: where responses go
|
47
|
+
|
43
48
|
# Define message properties
|
44
49
|
property :user_name
|
45
50
|
property :email
|
@@ -153,6 +158,9 @@ puts message._sm_header.uuid # Unique identifier
|
|
153
158
|
puts message._sm_header.message_class # "WelcomeMessage"
|
154
159
|
puts message._sm_header.published_at # Timestamp when published
|
155
160
|
puts message._sm_header.publisher_pid # Process ID of publisher
|
161
|
+
puts message._sm_header.from # 'user-service'
|
162
|
+
puts message._sm_header.to # 'notification-service'
|
163
|
+
puts message._sm_header.reply_to # 'user-service'
|
156
164
|
```
|
157
165
|
|
158
166
|
### Transports
|
@@ -222,6 +230,36 @@ OrderMessage.subscribe("OrderService.process_order")
|
|
222
230
|
- **Proc**: Reusable handlers that work across multiple message types
|
223
231
|
- **Method**: Complex business logic organized in service classes
|
224
232
|
|
233
|
+
### Entity Addressing
|
234
|
+
|
235
|
+
SmartMessage supports entity-to-entity addressing for sophisticated messaging patterns:
|
236
|
+
|
237
|
+
```ruby
|
238
|
+
# Point-to-point messaging
|
239
|
+
class PaymentMessage < SmartMessage::Base
|
240
|
+
from 'payment-service' # Required: sender identity
|
241
|
+
to 'bank-gateway' # Optional: specific recipient
|
242
|
+
reply_to 'payment-service' # Optional: where responses go
|
243
|
+
|
244
|
+
property :amount, required: true
|
245
|
+
end
|
246
|
+
|
247
|
+
# Broadcast messaging (no 'to' field)
|
248
|
+
class AnnouncementMessage < SmartMessage::Base
|
249
|
+
from 'admin-service' # Required sender
|
250
|
+
# No 'to' = broadcast to all subscribers
|
251
|
+
|
252
|
+
property :message, required: true
|
253
|
+
end
|
254
|
+
|
255
|
+
# Instance-level addressing override
|
256
|
+
payment = PaymentMessage.new(amount: 100.00)
|
257
|
+
payment.to('backup-gateway') # Override destination
|
258
|
+
payment.publish
|
259
|
+
```
|
260
|
+
|
261
|
+
For more details, see [Entity Addressing](addressing.md).
|
262
|
+
|
225
263
|
## Next Steps
|
226
264
|
|
227
265
|
Now that you have the basics working, explore:
|