smart_message 0.0.10 → 0.0.12
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/.github/workflows/deploy-github-pages.yml +38 -0
- data/.gitignore +5 -0
- data/CHANGELOG.md +30 -0
- data/Gemfile.lock +35 -4
- data/README.md +169 -71
- data/Rakefile +29 -4
- data/docs/assets/images/ddq_architecture.svg +130 -0
- data/docs/assets/images/dlq_architecture.svg +115 -0
- data/docs/assets/images/enhanced-dual-publishing.svg +136 -0
- data/docs/assets/images/enhanced-fluent-api.svg +149 -0
- data/docs/assets/images/enhanced-microservices-routing.svg +115 -0
- data/docs/assets/images/enhanced-pattern-matching.svg +107 -0
- data/docs/assets/images/fluent-api-demo.svg +59 -0
- data/docs/assets/images/performance-comparison.svg +161 -0
- data/docs/assets/images/redis-basic-architecture.svg +53 -0
- data/docs/assets/images/redis-enhanced-architecture.svg +88 -0
- data/docs/assets/images/redis-queue-architecture.svg +101 -0
- data/docs/assets/images/smart_message.jpg +0 -0
- data/docs/assets/images/smart_message_walking.jpg +0 -0
- data/docs/assets/images/smartmessage_architecture_overview.svg +173 -0
- data/docs/assets/images/transport-comparison-matrix.svg +171 -0
- data/docs/assets/javascripts/mathjax.js +17 -0
- data/docs/assets/stylesheets/extra.css +51 -0
- data/docs/{addressing.md → core-concepts/addressing.md} +5 -7
- data/docs/{architecture.md → core-concepts/architecture.md} +78 -138
- data/docs/{dispatcher.md → core-concepts/dispatcher.md} +21 -21
- data/docs/{message_filtering.md → core-concepts/message-filtering.md} +2 -3
- data/docs/{message_processing.md → core-concepts/message-processing.md} +17 -17
- data/docs/{troubleshooting.md → development/troubleshooting.md} +7 -7
- data/docs/{examples.md → getting-started/examples.md} +115 -89
- data/docs/{getting-started.md → getting-started/quick-start.md} +47 -18
- data/docs/guides/redis-queue-getting-started.md +697 -0
- data/docs/guides/redis-queue-patterns.md +889 -0
- data/docs/guides/redis-queue-production.md +1091 -0
- data/docs/index.md +64 -0
- data/docs/{dead_letter_queue.md → reference/dead-letter-queue.md} +2 -3
- data/docs/{logging.md → reference/logging.md} +1 -1
- data/docs/{message_deduplication.md → reference/message-deduplication.md} +1 -0
- data/docs/{proc_handlers_summary.md → reference/proc-handlers.md} +7 -6
- data/docs/{serializers.md → reference/serializers.md} +3 -5
- data/docs/{transports.md → reference/transports.md} +133 -11
- data/docs/transports/memory-transport.md +374 -0
- data/docs/transports/redis-enhanced-transport.md +524 -0
- data/docs/transports/redis-queue-transport.md +1304 -0
- data/docs/transports/redis-transport-comparison.md +496 -0
- data/docs/transports/redis-transport.md +509 -0
- data/examples/README.md +98 -5
- data/examples/city_scenario/911_emergency_call_flow.svg +99 -0
- data/examples/city_scenario/README.md +515 -0
- data/examples/city_scenario/ai_visitor_intelligence_flow.svg +108 -0
- data/examples/city_scenario/citizen.rb +195 -0
- data/examples/city_scenario/city_diagram.svg +125 -0
- data/examples/city_scenario/common/health_monitor.rb +80 -0
- data/examples/city_scenario/common/logger.rb +30 -0
- data/examples/city_scenario/emergency_dispatch_center.rb +270 -0
- data/examples/city_scenario/fire_department.rb +446 -0
- data/examples/city_scenario/fire_emergency_flow.svg +95 -0
- data/examples/city_scenario/health_department.rb +100 -0
- data/examples/city_scenario/health_monitoring_system.svg +130 -0
- data/examples/city_scenario/house.rb +244 -0
- data/examples/city_scenario/local_bank.rb +217 -0
- data/examples/city_scenario/messages/emergency_911_message.rb +81 -0
- data/examples/city_scenario/messages/emergency_resolved_message.rb +43 -0
- data/examples/city_scenario/messages/fire_dispatch_message.rb +43 -0
- data/examples/city_scenario/messages/fire_emergency_message.rb +45 -0
- data/examples/city_scenario/messages/health_check_message.rb +22 -0
- data/examples/city_scenario/messages/health_status_message.rb +35 -0
- data/examples/city_scenario/messages/police_dispatch_message.rb +46 -0
- data/examples/city_scenario/messages/silent_alarm_message.rb +38 -0
- data/examples/city_scenario/police_department.rb +316 -0
- data/examples/city_scenario/redis_monitor.rb +129 -0
- data/examples/city_scenario/redis_stats.rb +743 -0
- data/examples/city_scenario/room_for_improvement.md +240 -0
- data/examples/city_scenario/security_emergency_flow.svg +95 -0
- data/examples/city_scenario/service_internal_architecture.svg +154 -0
- data/examples/city_scenario/smart_message_ai_agent.rb +364 -0
- data/examples/city_scenario/start_demo.sh +236 -0
- data/examples/city_scenario/stop_demo.sh +106 -0
- data/examples/city_scenario/visitor.rb +631 -0
- data/examples/{10_message_deduplication.rb → memory/01_message_deduplication_demo.rb} +1 -1
- data/examples/{09_dead_letter_queue_demo.rb → memory/02_dead_letter_queue_demo.rb} +13 -40
- data/examples/{01_point_to_point_orders.rb → memory/03_point_to_point_orders.rb} +1 -1
- data/examples/{02_publish_subscribe_events.rb → memory/04_publish_subscribe_events.rb} +2 -2
- data/examples/{03_many_to_many_chat.rb → memory/05_many_to_many_chat.rb} +4 -4
- data/examples/{show_me.rb → memory/06_pretty_print_demo.rb} +1 -1
- data/examples/{05_proc_handlers.rb → memory/07_proc_handlers_demo.rb} +2 -2
- data/examples/{06_custom_logger_example.rb → memory/08_custom_logger_demo.rb} +17 -14
- data/examples/{07_error_handling_scenarios.rb → memory/09_error_handling_demo.rb} +4 -4
- data/examples/{08_entity_addressing_basic.rb → memory/10_entity_addressing_basic.rb} +8 -8
- data/examples/{08_entity_addressing_with_filtering.rb → memory/11_entity_addressing_with_filtering.rb} +6 -6
- data/examples/{09_regex_filtering_microservices.rb → memory/12_regex_filtering_microservices.rb} +2 -2
- data/examples/{10_header_block_configuration.rb → memory/13_header_block_configuration.rb} +6 -6
- data/examples/{11_global_configuration_example.rb → memory/14_global_configuration_demo.rb} +19 -8
- data/examples/{show_logger.rb → memory/15_logger_demo.rb} +1 -1
- data/examples/memory/README.md +163 -0
- data/examples/memory/memory_transport_architecture.svg +90 -0
- data/examples/memory/point_to_point_pattern.svg +94 -0
- data/examples/memory/publish_subscribe_pattern.svg +125 -0
- data/examples/{04_redis_smart_home_iot.rb → redis/01_smart_home_iot_demo.rb} +5 -5
- data/examples/redis/README.md +230 -0
- data/examples/redis/alert_system_flow.svg +127 -0
- data/examples/redis/dashboard_status_flow.svg +107 -0
- data/examples/redis/device_command_flow.svg +113 -0
- data/examples/redis/redis_transport_architecture.svg +115 -0
- data/examples/{smart_home_iot_dataflow.md → redis/smart_home_iot_dataflow.md} +4 -116
- data/examples/redis/smart_home_system_architecture.svg +133 -0
- data/examples/redis_enhanced/README.md +319 -0
- data/examples/redis_enhanced/enhanced_01_basic_patterns.rb +233 -0
- data/examples/redis_enhanced/enhanced_02_fluent_api.rb +331 -0
- data/examples/redis_enhanced/enhanced_03_dual_publishing.rb +281 -0
- data/examples/redis_enhanced/enhanced_04_advanced_routing.rb +419 -0
- data/examples/redis_queue/01_basic_messaging.rb +221 -0
- data/examples/redis_queue/01_comprehensive_examples.rb +508 -0
- data/examples/redis_queue/02_pattern_routing.rb +405 -0
- data/examples/redis_queue/03_fluent_api.rb +422 -0
- data/examples/redis_queue/04_load_balancing.rb +486 -0
- data/examples/redis_queue/05_microservices.rb +735 -0
- data/examples/redis_queue/06_emergency_alerts.rb +777 -0
- data/examples/redis_queue/07_queue_management.rb +587 -0
- data/examples/redis_queue/README.md +366 -0
- data/examples/redis_queue/enhanced_01_basic_patterns.rb +233 -0
- data/examples/redis_queue/enhanced_02_fluent_api.rb +331 -0
- data/examples/redis_queue/enhanced_03_dual_publishing.rb +281 -0
- data/examples/redis_queue/enhanced_04_advanced_routing.rb +419 -0
- data/examples/redis_queue/redis_queue_architecture.svg +148 -0
- data/ideas/README.md +41 -0
- data/ideas/agents.md +1001 -0
- data/ideas/database_transport.md +980 -0
- data/ideas/improvement.md +359 -0
- data/ideas/meshage.md +1788 -0
- data/ideas/message_discovery.md +178 -0
- data/ideas/message_schema.md +1381 -0
- data/lib/smart_message/.idea/.gitignore +8 -0
- data/lib/smart_message/.idea/markdown.xml +6 -0
- data/lib/smart_message/.idea/misc.xml +4 -0
- data/lib/smart_message/.idea/modules.xml +8 -0
- data/lib/smart_message/.idea/smart_message.iml +16 -0
- data/lib/smart_message/.idea/vcs.xml +6 -0
- data/lib/smart_message/addressing.rb +15 -0
- data/lib/smart_message/base.rb +0 -2
- data/lib/smart_message/configuration.rb +1 -1
- data/lib/smart_message/logger.rb +15 -4
- data/lib/smart_message/plugins.rb +5 -2
- data/lib/smart_message/serializer.rb +14 -0
- data/lib/smart_message/transport/redis_enhanced_transport.rb +399 -0
- data/lib/smart_message/transport/redis_queue_transport.rb +555 -0
- data/lib/smart_message/transport/registry.rb +1 -0
- data/lib/smart_message/transport.rb +34 -1
- data/lib/smart_message/version.rb +1 -1
- data/lib/smart_message.rb +5 -52
- data/mkdocs.yml +184 -0
- data/p2p_plan.md +326 -0
- data/p2p_roadmap.md +287 -0
- data/smart_message.gemspec +2 -0
- data/smart_message.svg +51 -0
- metadata +170 -44
- data/docs/README.md +0 -57
- data/examples/dead_letters.jsonl +0 -12
- data/examples/temp.txt +0 -94
- data/examples/tmux_chat/README.md +0 -283
- data/examples/tmux_chat/bot_agent.rb +0 -278
- data/examples/tmux_chat/human_agent.rb +0 -199
- data/examples/tmux_chat/room_monitor.rb +0 -160
- data/examples/tmux_chat/shared_chat_system.rb +0 -328
- data/examples/tmux_chat/start_chat_demo.sh +0 -190
- data/examples/tmux_chat/stop_chat_demo.sh +0 -22
- /data/docs/{properties.md → core-concepts/properties.md} +0 -0
- /data/docs/{ideas_to_think_about.md → development/ideas.md} +0 -0
@@ -0,0 +1,331 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# examples/redis_queue/enhanced_02_fluent_api.rb
|
3
|
+
# Redis Enhanced Transport - Fluent API Demonstration
|
4
|
+
|
5
|
+
require_relative '../../lib/smart_message'
|
6
|
+
require 'smart_message/transport/redis_enhanced_transport'
|
7
|
+
|
8
|
+
puts "🚀 Redis Enhanced Transport - Fluent API Demo"
|
9
|
+
puts "=" * 50
|
10
|
+
|
11
|
+
# Create enhanced Redis transport instance
|
12
|
+
transport = SmartMessage::Transport::RedisEnhancedTransport.new(
|
13
|
+
url: 'redis://localhost:6379',
|
14
|
+
db: 3, # Use database 3 for fluent API examples
|
15
|
+
auto_subscribe: true
|
16
|
+
)
|
17
|
+
|
18
|
+
#==============================================================================
|
19
|
+
# Define Message Classes for Microservices Architecture
|
20
|
+
#==============================================================================
|
21
|
+
|
22
|
+
class UserRegistrationMessage < SmartMessage::Base
|
23
|
+
from 'web-app'
|
24
|
+
to 'user-service'
|
25
|
+
|
26
|
+
transport transport
|
27
|
+
serializer SmartMessage::Serializer::Json.new
|
28
|
+
|
29
|
+
property :user_id, required: true
|
30
|
+
property :email, required: true
|
31
|
+
property :name, required: true
|
32
|
+
|
33
|
+
def self.process(wrapper)
|
34
|
+
header, payload = wrapper.split
|
35
|
+
data = JSON.parse(payload)
|
36
|
+
|
37
|
+
puts "👤 [USER SERVICE] New user registration: #{data['name']} (#{data['email']})"
|
38
|
+
puts " User ID: #{data['user_id']}"
|
39
|
+
puts
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class EmailNotificationMessage < SmartMessage::Base
|
44
|
+
from 'user-service'
|
45
|
+
to 'notification-service'
|
46
|
+
|
47
|
+
transport transport
|
48
|
+
serializer SmartMessage::Serializer::Json.new
|
49
|
+
|
50
|
+
property :recipient, required: true
|
51
|
+
property :subject, required: true
|
52
|
+
property :body, required: true
|
53
|
+
property :template, default: 'default'
|
54
|
+
|
55
|
+
def self.process(wrapper)
|
56
|
+
header, payload = wrapper.split
|
57
|
+
data = JSON.parse(payload)
|
58
|
+
|
59
|
+
puts "📧 [NOTIFICATION SERVICE] Sending email to #{data['recipient']}"
|
60
|
+
puts " Subject: #{data['subject']}"
|
61
|
+
puts " Template: #{data['template']}"
|
62
|
+
puts
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class AnalyticsEventMessage < SmartMessage::Base
|
67
|
+
from 'various-services'
|
68
|
+
to 'analytics-service'
|
69
|
+
|
70
|
+
transport transport
|
71
|
+
serializer SmartMessage::Serializer::Json.new
|
72
|
+
|
73
|
+
property :event_type, required: true
|
74
|
+
property :user_id
|
75
|
+
property :metadata, default: {}
|
76
|
+
property :timestamp, default: -> { Time.now.iso8601 }
|
77
|
+
|
78
|
+
def self.process(wrapper)
|
79
|
+
header, payload = wrapper.split
|
80
|
+
data = JSON.parse(payload)
|
81
|
+
|
82
|
+
puts "📊 [ANALYTICS] Event: #{data['event_type']}"
|
83
|
+
puts " User: #{data['user_id'] || 'anonymous'}"
|
84
|
+
puts " Timestamp: #{data['timestamp']}"
|
85
|
+
puts " Metadata: #{data['metadata']}"
|
86
|
+
puts
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class AdminAlertMessage < SmartMessage::Base
|
91
|
+
from 'monitoring'
|
92
|
+
to 'admin-panel'
|
93
|
+
|
94
|
+
transport transport
|
95
|
+
serializer SmartMessage::Serializer::Json.new
|
96
|
+
|
97
|
+
property :severity, required: true
|
98
|
+
property :message, required: true
|
99
|
+
property :service, required: true
|
100
|
+
|
101
|
+
def self.process(wrapper)
|
102
|
+
header, payload = wrapper.split
|
103
|
+
data = JSON.parse(payload)
|
104
|
+
|
105
|
+
puts "⚠️ [ADMIN PANEL] #{data['severity'].upcase} from #{data['service']}"
|
106
|
+
puts " #{data['message']}"
|
107
|
+
puts
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
#==============================================================================
|
112
|
+
# Fluent API Demonstration Functions
|
113
|
+
#==============================================================================
|
114
|
+
|
115
|
+
def demo_basic_fluent_subscriptions(transport)
|
116
|
+
puts "🔗 Setting up fluent API subscriptions..."
|
117
|
+
puts
|
118
|
+
|
119
|
+
# Basic fluent subscriptions
|
120
|
+
transport.where.from('web-app').subscribe
|
121
|
+
puts "✅ Subscribed to all messages FROM 'web-app'"
|
122
|
+
|
123
|
+
transport.where.to('user-service').subscribe
|
124
|
+
puts "✅ Subscribed to all messages TO 'user-service'"
|
125
|
+
|
126
|
+
transport.where.type('EmailNotificationMessage').subscribe
|
127
|
+
puts "✅ Subscribed to all 'EmailNotificationMessage' messages"
|
128
|
+
puts
|
129
|
+
end
|
130
|
+
|
131
|
+
def demo_combined_fluent_subscriptions(transport)
|
132
|
+
puts "🎯 Setting up combined fluent API subscriptions..."
|
133
|
+
puts
|
134
|
+
|
135
|
+
# Combined conditions
|
136
|
+
transport.where
|
137
|
+
.from('user-service')
|
138
|
+
.to('notification-service')
|
139
|
+
.subscribe
|
140
|
+
puts "✅ Subscribed to messages FROM 'user-service' TO 'notification-service'"
|
141
|
+
|
142
|
+
transport.where
|
143
|
+
.type('AnalyticsEventMessage')
|
144
|
+
.from('web-app')
|
145
|
+
.subscribe
|
146
|
+
puts "✅ Subscribed to 'AnalyticsEventMessage' FROM 'web-app'"
|
147
|
+
|
148
|
+
# Three-way combination
|
149
|
+
transport.where
|
150
|
+
.type('AdminAlertMessage')
|
151
|
+
.from('monitoring')
|
152
|
+
.to('admin-panel')
|
153
|
+
.subscribe
|
154
|
+
puts "✅ Subscribed to 'AdminAlertMessage' FROM 'monitoring' TO 'admin-panel'"
|
155
|
+
puts
|
156
|
+
end
|
157
|
+
|
158
|
+
def demo_wildcard_subscriptions(transport)
|
159
|
+
puts "🌟 Setting up wildcard pattern subscriptions..."
|
160
|
+
puts
|
161
|
+
|
162
|
+
# Service-specific patterns
|
163
|
+
transport.where.from('analytics-service').subscribe
|
164
|
+
puts "✅ Subscribed to all messages from analytics service"
|
165
|
+
|
166
|
+
transport.where.to('notification-service').subscribe
|
167
|
+
puts "✅ Subscribed to all messages to notification service"
|
168
|
+
|
169
|
+
# Catch-all analytics events
|
170
|
+
transport.where.type('AnalyticsEventMessage').subscribe
|
171
|
+
puts "✅ Subscribed to all analytics events regardless of source/destination"
|
172
|
+
puts
|
173
|
+
end
|
174
|
+
|
175
|
+
def publish_sample_workflow
|
176
|
+
puts "📤 Publishing sample microservices workflow..."
|
177
|
+
puts
|
178
|
+
|
179
|
+
# 1. User registration from web app
|
180
|
+
registration = UserRegistrationMessage.new(
|
181
|
+
user_id: 'user_12345',
|
182
|
+
email: 'john.doe@example.com',
|
183
|
+
name: 'John Doe'
|
184
|
+
)
|
185
|
+
registration.publish
|
186
|
+
|
187
|
+
sleep 0.1 # Small delay to see message processing order
|
188
|
+
|
189
|
+
# 2. Welcome email notification
|
190
|
+
welcome_email = EmailNotificationMessage.new(
|
191
|
+
recipient: 'john.doe@example.com',
|
192
|
+
subject: 'Welcome to Our Platform!',
|
193
|
+
body: 'Thank you for joining us, John!',
|
194
|
+
template: 'welcome'
|
195
|
+
)
|
196
|
+
welcome_email.publish
|
197
|
+
|
198
|
+
sleep 0.1
|
199
|
+
|
200
|
+
# 3. Analytics event from user service
|
201
|
+
analytics = AnalyticsEventMessage.new(
|
202
|
+
event_type: 'user_registered',
|
203
|
+
user_id: 'user_12345',
|
204
|
+
metadata: {
|
205
|
+
source: 'web_signup',
|
206
|
+
referrer: 'google_ads',
|
207
|
+
campaign: 'spring_2024'
|
208
|
+
}
|
209
|
+
)
|
210
|
+
analytics.from('user-service') # Override default 'from'
|
211
|
+
analytics.publish
|
212
|
+
|
213
|
+
sleep 0.1
|
214
|
+
|
215
|
+
# 4. Another analytics event from web-app
|
216
|
+
web_analytics = AnalyticsEventMessage.new(
|
217
|
+
event_type: 'signup_completed',
|
218
|
+
user_id: 'user_12345',
|
219
|
+
metadata: {
|
220
|
+
page: '/signup/complete',
|
221
|
+
time_spent: 45
|
222
|
+
}
|
223
|
+
)
|
224
|
+
web_analytics.from('web-app')
|
225
|
+
web_analytics.publish
|
226
|
+
|
227
|
+
sleep 0.1
|
228
|
+
|
229
|
+
# 5. Admin alert from monitoring
|
230
|
+
admin_alert = AdminAlertMessage.new(
|
231
|
+
severity: 'info',
|
232
|
+
message: 'New user registration completed successfully',
|
233
|
+
service: 'user-service'
|
234
|
+
)
|
235
|
+
admin_alert.publish
|
236
|
+
|
237
|
+
puts "✅ Published complete user registration workflow (5 messages)"
|
238
|
+
puts
|
239
|
+
end
|
240
|
+
|
241
|
+
def demonstrate_pattern_building(transport)
|
242
|
+
puts "🔨 Demonstrating pattern building..."
|
243
|
+
puts
|
244
|
+
|
245
|
+
# Show how patterns are built
|
246
|
+
builder = transport.where.from('web-app').to('user-service').type('UserRegistrationMessage')
|
247
|
+
pattern = builder.build
|
248
|
+
puts "Pattern for web-app → user-service UserRegistrationMessage:"
|
249
|
+
puts " #{pattern}"
|
250
|
+
puts
|
251
|
+
|
252
|
+
builder2 = transport.where.type('AnalyticsEventMessage')
|
253
|
+
pattern2 = builder2.build
|
254
|
+
puts "Pattern for any AnalyticsEventMessage:"
|
255
|
+
puts " #{pattern2}"
|
256
|
+
puts
|
257
|
+
|
258
|
+
builder3 = transport.where.from('monitoring')
|
259
|
+
pattern3 = builder3.build
|
260
|
+
puts "Pattern for any message from monitoring:"
|
261
|
+
puts " #{pattern3}"
|
262
|
+
puts
|
263
|
+
end
|
264
|
+
|
265
|
+
#==============================================================================
|
266
|
+
# Main Demonstration
|
267
|
+
#==============================================================================
|
268
|
+
|
269
|
+
begin
|
270
|
+
puts "🔧 Checking Redis connection..."
|
271
|
+
unless transport.connected?
|
272
|
+
puts "❌ Redis not available. Please start Redis server:"
|
273
|
+
puts " brew services start redis # macOS"
|
274
|
+
puts " sudo service redis start # Linux"
|
275
|
+
exit 1
|
276
|
+
end
|
277
|
+
puts "✅ Connected to Redis"
|
278
|
+
puts
|
279
|
+
|
280
|
+
# Demonstrate pattern building first
|
281
|
+
demonstrate_pattern_building(transport)
|
282
|
+
|
283
|
+
# Set up various fluent API subscriptions
|
284
|
+
demo_basic_fluent_subscriptions(transport)
|
285
|
+
demo_combined_fluent_subscriptions(transport)
|
286
|
+
demo_wildcard_subscriptions(transport)
|
287
|
+
|
288
|
+
# Subscribe message classes to their handlers
|
289
|
+
UserRegistrationMessage.subscribe
|
290
|
+
EmailNotificationMessage.subscribe
|
291
|
+
AnalyticsEventMessage.subscribe
|
292
|
+
AdminAlertMessage.subscribe
|
293
|
+
|
294
|
+
puts "⏳ Waiting for subscriptions to be established..."
|
295
|
+
sleep 1
|
296
|
+
|
297
|
+
# Publish sample workflow
|
298
|
+
publish_sample_workflow
|
299
|
+
|
300
|
+
puts "⏳ Processing messages (waiting 3 seconds)..."
|
301
|
+
sleep 3
|
302
|
+
|
303
|
+
# Show active patterns
|
304
|
+
puts "📋 Active Pattern Subscriptions:"
|
305
|
+
pattern_subscriptions = transport.instance_variable_get(:@pattern_subscriptions)
|
306
|
+
if pattern_subscriptions && pattern_subscriptions.any?
|
307
|
+
pattern_subscriptions.each_with_index do |pattern, i|
|
308
|
+
puts " #{i + 1}. #{pattern}"
|
309
|
+
end
|
310
|
+
else
|
311
|
+
puts " No pattern subscriptions found"
|
312
|
+
end
|
313
|
+
puts
|
314
|
+
|
315
|
+
puts "🎉 Fluent API Demo completed!"
|
316
|
+
puts "💡 Key takeaways:"
|
317
|
+
puts " • Fluent API makes complex subscriptions readable"
|
318
|
+
puts " • Combine .from(), .to(), and .type() for precise routing"
|
319
|
+
puts " • Patterns are built as: type.from.to with wildcards (*)"
|
320
|
+
puts " • Each .subscribe() call adds a new pattern to the transport"
|
321
|
+
|
322
|
+
rescue Interrupt
|
323
|
+
puts "\n👋 Demo interrupted by user"
|
324
|
+
rescue => e
|
325
|
+
puts "💥 Error: #{e.message}"
|
326
|
+
puts e.backtrace[0..3]
|
327
|
+
ensure
|
328
|
+
puts "\n🧹 Cleaning up..."
|
329
|
+
transport&.disconnect
|
330
|
+
puts "✅ Disconnected from Redis"
|
331
|
+
end
|
@@ -0,0 +1,281 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# examples/redis_queue/enhanced_03_dual_publishing.rb
|
3
|
+
# Redis Enhanced Transport - Dual Channel Publishing Demo
|
4
|
+
|
5
|
+
require_relative '../../lib/smart_message'
|
6
|
+
require 'smart_message/transport/redis_enhanced_transport'
|
7
|
+
|
8
|
+
puts "🚀 Redis Enhanced Transport - Dual Channel Publishing Demo"
|
9
|
+
puts "=" * 58
|
10
|
+
|
11
|
+
# Create both enhanced and basic Redis transports to demonstrate compatibility
|
12
|
+
enhanced_transport = SmartMessage::Transport::RedisEnhancedTransport.new(
|
13
|
+
url: 'redis://localhost:6379',
|
14
|
+
db: 4, # Use database 4 for dual publishing examples
|
15
|
+
auto_subscribe: true
|
16
|
+
)
|
17
|
+
|
18
|
+
basic_transport = SmartMessage::Transport::RedisTransport.new(
|
19
|
+
url: 'redis://localhost:6379',
|
20
|
+
db: 4, # Same database to show cross-transport communication
|
21
|
+
auto_subscribe: true
|
22
|
+
)
|
23
|
+
|
24
|
+
#==============================================================================
|
25
|
+
# Define Message Classes for Both Transports
|
26
|
+
#==============================================================================
|
27
|
+
|
28
|
+
class OrderStatusMessage < SmartMessage::Base
|
29
|
+
from 'order-service'
|
30
|
+
to 'customer-notification'
|
31
|
+
|
32
|
+
transport enhanced_transport
|
33
|
+
serializer SmartMessage::Serializer::Json.new
|
34
|
+
|
35
|
+
property :order_id, required: true
|
36
|
+
property :status, required: true
|
37
|
+
property :customer_email, required: true
|
38
|
+
property :updated_at, default: -> { Time.now.iso8601 }
|
39
|
+
|
40
|
+
def self.process(wrapper)
|
41
|
+
header, payload = wrapper.split
|
42
|
+
data = JSON.parse(payload)
|
43
|
+
|
44
|
+
puts "📋 [ENHANCED] Order #{data['order_id']} status: #{data['status']}"
|
45
|
+
puts " Customer: #{data['customer_email']}"
|
46
|
+
puts " Channel: Enhanced (dual publishing)"
|
47
|
+
puts " From: #{header.from} → To: #{header.to}"
|
48
|
+
puts
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Same message class but using basic transport
|
53
|
+
class LegacyOrderMessage < SmartMessage::Base
|
54
|
+
from 'legacy-system'
|
55
|
+
|
56
|
+
transport basic_transport
|
57
|
+
serializer SmartMessage::Serializer::Json.new
|
58
|
+
|
59
|
+
property :order_id, required: true
|
60
|
+
property :action, required: true
|
61
|
+
property :details, default: {}
|
62
|
+
|
63
|
+
def self.process(wrapper)
|
64
|
+
header, payload = wrapper.split
|
65
|
+
data = JSON.parse(payload)
|
66
|
+
|
67
|
+
puts "🔄 [BASIC] Legacy order #{data['order_id']} - #{data['action']}"
|
68
|
+
puts " Channel: Basic (single channel)"
|
69
|
+
puts " From: #{header.from}"
|
70
|
+
puts
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Message that demonstrates backwards compatibility
|
75
|
+
class CompatibilityTestMessage < SmartMessage::Base
|
76
|
+
from 'test-service'
|
77
|
+
to 'compatibility-test'
|
78
|
+
|
79
|
+
# Will be configured dynamically to test both transports
|
80
|
+
serializer SmartMessage::Serializer::Json.new
|
81
|
+
|
82
|
+
property :test_id, required: true
|
83
|
+
property :transport_type, required: true
|
84
|
+
property :message_content, required: true
|
85
|
+
|
86
|
+
def self.process(wrapper)
|
87
|
+
header, payload = wrapper.split
|
88
|
+
data = JSON.parse(payload)
|
89
|
+
|
90
|
+
puts "🧪 [#{data['transport_type'].upcase}] Test #{data['test_id']}"
|
91
|
+
puts " Content: #{data['message_content']}"
|
92
|
+
puts " From: #{header.from} → To: #{header.to}"
|
93
|
+
puts
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
#==============================================================================
|
98
|
+
# Demonstration Functions
|
99
|
+
#==============================================================================
|
100
|
+
|
101
|
+
def demonstrate_dual_publishing
|
102
|
+
puts "🔄 Demonstrating dual channel publishing..."
|
103
|
+
puts "Enhanced transport publishes to BOTH channels:"
|
104
|
+
puts " 1. Original channel: 'OrderStatusMessage'"
|
105
|
+
puts " 2. Enhanced channel: 'orderstatusmessage.order_service.customer_notification'"
|
106
|
+
puts
|
107
|
+
|
108
|
+
# Publish enhanced message
|
109
|
+
order_status = OrderStatusMessage.new(
|
110
|
+
order_id: 'ORD-2024-001',
|
111
|
+
status: 'shipped',
|
112
|
+
customer_email: 'customer@example.com'
|
113
|
+
)
|
114
|
+
|
115
|
+
puts "📤 Publishing OrderStatusMessage (enhanced transport)..."
|
116
|
+
order_status.publish
|
117
|
+
puts "✅ Message published to both original and enhanced channels"
|
118
|
+
puts
|
119
|
+
end
|
120
|
+
|
121
|
+
def demonstrate_backwards_compatibility
|
122
|
+
puts "🔙 Demonstrating backwards compatibility..."
|
123
|
+
puts "Enhanced transport should receive messages from basic transport"
|
124
|
+
puts
|
125
|
+
|
126
|
+
# Publish from basic transport
|
127
|
+
legacy_message = LegacyOrderMessage.new(
|
128
|
+
order_id: 'ORD-LEGACY-001',
|
129
|
+
action: 'processed',
|
130
|
+
details: { processor: 'legacy_v1.2', timestamp: Time.now.to_i }
|
131
|
+
)
|
132
|
+
|
133
|
+
puts "📤 Publishing from basic Redis transport..."
|
134
|
+
legacy_message.publish
|
135
|
+
puts "✅ Basic transport message published"
|
136
|
+
puts
|
137
|
+
end
|
138
|
+
|
139
|
+
def demonstrate_cross_transport_subscriptions(enhanced_transport)
|
140
|
+
puts "🌉 Setting up cross-transport subscriptions..."
|
141
|
+
puts
|
142
|
+
|
143
|
+
# Enhanced transport subscribes to basic transport patterns
|
144
|
+
enhanced_transport.subscribe_pattern("LegacyOrderMessage") # Basic channel name
|
145
|
+
enhanced_transport.subscribe_pattern("*.legacy_system.*") # Enhanced pattern that won't match basic
|
146
|
+
|
147
|
+
puts "✅ Enhanced transport subscribed to:"
|
148
|
+
puts " • 'LegacyOrderMessage' (basic channel)"
|
149
|
+
puts " • '*.legacy_system.*' (enhanced pattern)"
|
150
|
+
puts
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_transport_compatibility
|
154
|
+
puts "🧪 Testing transport compatibility..."
|
155
|
+
puts
|
156
|
+
|
157
|
+
# Test 1: Enhanced message with enhanced transport
|
158
|
+
CompatibilityTestMessage.config { transport enhanced_transport }
|
159
|
+
|
160
|
+
enhanced_test = CompatibilityTestMessage.new(
|
161
|
+
test_id: 'TEST-001',
|
162
|
+
transport_type: 'enhanced',
|
163
|
+
message_content: 'Testing dual channel publishing'
|
164
|
+
)
|
165
|
+
|
166
|
+
puts "📤 Test 1: Enhanced transport with enhanced message..."
|
167
|
+
enhanced_test.publish
|
168
|
+
|
169
|
+
# Test 2: Basic message with basic transport
|
170
|
+
CompatibilityTestMessage.config { transport basic_transport }
|
171
|
+
|
172
|
+
basic_test = CompatibilityTestMessage.new(
|
173
|
+
test_id: 'TEST-002',
|
174
|
+
transport_type: 'basic',
|
175
|
+
message_content: 'Testing single channel publishing'
|
176
|
+
)
|
177
|
+
|
178
|
+
puts "📤 Test 2: Basic transport with basic message..."
|
179
|
+
basic_test.publish
|
180
|
+
puts
|
181
|
+
end
|
182
|
+
|
183
|
+
def show_channel_comparison
|
184
|
+
puts "📊 Channel Comparison:"
|
185
|
+
puts "┌─────────────────┬───────────────────────┬────────────────────────────────────┐"
|
186
|
+
puts "│ Transport Type │ Original Channel │ Enhanced Channel │"
|
187
|
+
puts "├─────────────────┼───────────────────────┼────────────────────────────────────┤"
|
188
|
+
puts "│ Basic │ MessageClassName │ (none) │"
|
189
|
+
puts "│ Enhanced │ MessageClassName │ messageclassname.from.to │"
|
190
|
+
puts "└─────────────────┴───────────────────────┴────────────────────────────────────┘"
|
191
|
+
puts
|
192
|
+
|
193
|
+
puts "📋 Pattern Matching Examples:"
|
194
|
+
puts "• Basic pattern: 'OrderStatusMessage'"
|
195
|
+
puts "• Enhanced pattern: 'orderstatusmessage.order_service.customer_notification'"
|
196
|
+
puts "• Wildcard pattern: '*.order_service.*' (matches all from order-service)"
|
197
|
+
puts "• Type pattern: 'orderstatusmessage.*.*' (matches all order status messages)"
|
198
|
+
puts
|
199
|
+
end
|
200
|
+
|
201
|
+
def monitor_redis_channels
|
202
|
+
puts "👀 Monitoring Redis channels (simulation)..."
|
203
|
+
puts "If you were monitoring Redis, you would see:"
|
204
|
+
puts
|
205
|
+
puts "BASIC TRANSPORT publishes to:"
|
206
|
+
puts " ├─ 'LegacyOrderMessage'"
|
207
|
+
puts " └─ 'CompatibilityTestMessage'"
|
208
|
+
puts
|
209
|
+
puts "ENHANCED TRANSPORT publishes to:"
|
210
|
+
puts " ├─ 'OrderStatusMessage' (backwards compatibility)"
|
211
|
+
puts " ├─ 'orderstatusmessage.order_service.customer_notification' (enhanced)"
|
212
|
+
puts " ├─ 'CompatibilityTestMessage' (backwards compatibility)"
|
213
|
+
puts " └─ 'compatibilitytestmessage.test_service.compatibility_test' (enhanced)"
|
214
|
+
puts
|
215
|
+
end
|
216
|
+
|
217
|
+
#==============================================================================
|
218
|
+
# Main Demonstration
|
219
|
+
#==============================================================================
|
220
|
+
|
221
|
+
begin
|
222
|
+
puts "🔧 Checking Redis connections..."
|
223
|
+
unless enhanced_transport.connected? && basic_transport.connected?
|
224
|
+
puts "❌ Redis not available. Please start Redis server:"
|
225
|
+
puts " brew services start redis # macOS"
|
226
|
+
puts " sudo service redis start # Linux"
|
227
|
+
exit 1
|
228
|
+
end
|
229
|
+
puts "✅ Connected to Redis (both transports)"
|
230
|
+
puts
|
231
|
+
|
232
|
+
# Show channel comparison
|
233
|
+
show_channel_comparison
|
234
|
+
|
235
|
+
# Set up cross-transport subscriptions
|
236
|
+
demonstrate_cross_transport_subscriptions(enhanced_transport)
|
237
|
+
|
238
|
+
# Subscribe message classes
|
239
|
+
OrderStatusMessage.subscribe
|
240
|
+
LegacyOrderMessage.subscribe
|
241
|
+
CompatibilityTestMessage.subscribe
|
242
|
+
|
243
|
+
puts "⏳ Waiting for subscriptions to be established..."
|
244
|
+
sleep 1
|
245
|
+
|
246
|
+
# Run demonstrations
|
247
|
+
demonstrate_dual_publishing
|
248
|
+
sleep 0.5
|
249
|
+
|
250
|
+
demonstrate_backwards_compatibility
|
251
|
+
sleep 0.5
|
252
|
+
|
253
|
+
test_transport_compatibility
|
254
|
+
sleep 1
|
255
|
+
|
256
|
+
puts "⏳ Processing messages (waiting 3 seconds)..."
|
257
|
+
sleep 3
|
258
|
+
|
259
|
+
# Show monitoring simulation
|
260
|
+
monitor_redis_channels
|
261
|
+
|
262
|
+
puts "🎉 Dual Publishing Demo completed!"
|
263
|
+
puts
|
264
|
+
puts "💡 Key Insights:"
|
265
|
+
puts " • Enhanced transport publishes to BOTH original and enhanced channels"
|
266
|
+
puts " • This provides backwards compatibility with basic Redis transport"
|
267
|
+
puts " • Enhanced patterns allow more sophisticated routing"
|
268
|
+
puts " • Basic transport only publishes to original channels"
|
269
|
+
puts " • Both transports can coexist and communicate"
|
270
|
+
|
271
|
+
rescue Interrupt
|
272
|
+
puts "\n👋 Demo interrupted by user"
|
273
|
+
rescue => e
|
274
|
+
puts "💥 Error: #{e.message}"
|
275
|
+
puts e.backtrace[0..3]
|
276
|
+
ensure
|
277
|
+
puts "\n🧹 Cleaning up..."
|
278
|
+
enhanced_transport&.disconnect
|
279
|
+
basic_transport&.disconnect
|
280
|
+
puts "✅ Disconnected from Redis (both transports)"
|
281
|
+
end
|