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,486 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# examples/redis_queue/04_load_balancing.rb
|
3
|
+
# Load balancing and consumer groups with Redis Queue Transport
|
4
|
+
|
5
|
+
require_relative '../../lib/smart_message'
|
6
|
+
|
7
|
+
puts "⚖️ Redis Queue Transport - Load Balancing Demo"
|
8
|
+
puts "=" * 50
|
9
|
+
|
10
|
+
#==============================================================================
|
11
|
+
# Transport Configuration
|
12
|
+
#==============================================================================
|
13
|
+
|
14
|
+
# Create shared transport for load balancing examples
|
15
|
+
shared_transport = SmartMessage::Transport::RedisQueueTransport.new(
|
16
|
+
url: 'redis://localhost:6379',
|
17
|
+
db: 4, # Use database 4 for load balancing examples
|
18
|
+
queue_prefix: 'load_balance_demo',
|
19
|
+
consumer_group: 'demo_workers',
|
20
|
+
block_time: 500 # Fast response for demo
|
21
|
+
)
|
22
|
+
|
23
|
+
#==============================================================================
|
24
|
+
# Work Message Classes
|
25
|
+
#==============================================================================
|
26
|
+
|
27
|
+
class ProcessingTask < SmartMessage::Base
|
28
|
+
transport :redis_queue, {
|
29
|
+
url: 'redis://localhost:6379',
|
30
|
+
db: 4,
|
31
|
+
queue_prefix: 'load_balance_demo'
|
32
|
+
}
|
33
|
+
|
34
|
+
property :task_id, required: true
|
35
|
+
property :task_type, required: true
|
36
|
+
property :complexity, default: 'medium' # low, medium, high
|
37
|
+
property :estimated_seconds, default: 1
|
38
|
+
property :payload, default: {}
|
39
|
+
|
40
|
+
def process
|
41
|
+
complexity_icon = case complexity
|
42
|
+
when 'high' then '🔥'
|
43
|
+
when 'medium' then '⚡'
|
44
|
+
when 'low' then '🍃'
|
45
|
+
else '⚙️'
|
46
|
+
end
|
47
|
+
|
48
|
+
puts "#{complexity_icon} Processing #{task_id} [#{task_type}] - #{complexity} complexity (#{estimated_seconds}s)"
|
49
|
+
|
50
|
+
# Simulate work
|
51
|
+
sleep(estimated_seconds * 0.1) # Scale down for demo
|
52
|
+
|
53
|
+
puts "✅ Completed #{task_id} by worker #{Thread.current.object_id.to_s[-4..-1]}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class EmailTask < SmartMessage::Base
|
58
|
+
transport :redis_queue, {
|
59
|
+
url: 'redis://localhost:6379',
|
60
|
+
db: 4,
|
61
|
+
queue_prefix: 'load_balance_demo'
|
62
|
+
}
|
63
|
+
|
64
|
+
property :email_id, required: true
|
65
|
+
property :recipient, required: true
|
66
|
+
property :subject, required: true
|
67
|
+
property :template, default: 'default'
|
68
|
+
property :priority, default: 'normal'
|
69
|
+
|
70
|
+
def process
|
71
|
+
priority_icon = case priority
|
72
|
+
when 'urgent' then '🚨'
|
73
|
+
when 'high' then '❗'
|
74
|
+
when 'normal' then '📧'
|
75
|
+
when 'low' then '📮'
|
76
|
+
else '📬'
|
77
|
+
end
|
78
|
+
|
79
|
+
worker_id = Thread.current.object_id.to_s[-4..-1]
|
80
|
+
puts "#{priority_icon} Worker-#{worker_id}: Email #{email_id} → #{recipient}"
|
81
|
+
puts " Subject: #{subject} [#{priority}]"
|
82
|
+
|
83
|
+
# Simulate email sending
|
84
|
+
sleep(rand(0.5..1.5))
|
85
|
+
|
86
|
+
puts "📤 Email #{email_id} sent by worker-#{worker_id}"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class DataAnalysisTask < SmartMessage::Base
|
91
|
+
transport :redis_queue, {
|
92
|
+
url: 'redis://localhost:6379',
|
93
|
+
db: 4,
|
94
|
+
queue_prefix: 'load_balance_demo'
|
95
|
+
}
|
96
|
+
|
97
|
+
property :analysis_id, required: true
|
98
|
+
property :dataset, required: true
|
99
|
+
property :analysis_type, required: true
|
100
|
+
property :rows, default: 1000
|
101
|
+
property :columns, default: 10
|
102
|
+
|
103
|
+
def process
|
104
|
+
worker_id = Thread.current.object_id.to_s[-4..-1]
|
105
|
+
puts "📊 Worker-#{worker_id}: Analyzing #{dataset} [#{analysis_type}]"
|
106
|
+
puts " Dataset: #{rows} rows × #{columns} columns"
|
107
|
+
|
108
|
+
# Simulate analysis work
|
109
|
+
sleep(rand(0.8..2.0))
|
110
|
+
|
111
|
+
puts "🎯 Analysis #{analysis_id} completed by worker-#{worker_id}"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
#==============================================================================
|
116
|
+
# Consumer Group Setup
|
117
|
+
#==============================================================================
|
118
|
+
|
119
|
+
puts "\n👥 Setting up consumer groups for load balancing:"
|
120
|
+
|
121
|
+
# Group 1: General processing workers
|
122
|
+
puts "1️⃣ Setting up 'processing_workers' group (3 workers)"
|
123
|
+
processing_workers = []
|
124
|
+
3.times do |i|
|
125
|
+
worker_thread = Thread.new do
|
126
|
+
worker_transport = SmartMessage::Transport::RedisQueueTransport.new(
|
127
|
+
url: 'redis://localhost:6379',
|
128
|
+
db: 4,
|
129
|
+
queue_prefix: 'load_balance_demo',
|
130
|
+
consumer_group: 'processing_workers',
|
131
|
+
block_time: 1000
|
132
|
+
)
|
133
|
+
|
134
|
+
# Subscribe to processing tasks directed to worker pool
|
135
|
+
worker_transport.where
|
136
|
+
.to('worker_pool')
|
137
|
+
.consumer_group('processing_workers')
|
138
|
+
.subscribe do |message_class, message_data|
|
139
|
+
data = JSON.parse(message_data)
|
140
|
+
worker_id = Thread.current.object_id.to_s[-4..-1]
|
141
|
+
puts "⚙️ Worker-#{i+1}-#{worker_id} received: #{data['task_id'] || data['email_id'] || data['analysis_id']}"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
processing_workers << worker_thread
|
145
|
+
end
|
146
|
+
|
147
|
+
# Group 2: Email workers
|
148
|
+
puts "2️⃣ Setting up 'email_workers' group (2 workers)"
|
149
|
+
email_workers = []
|
150
|
+
2.times do |i|
|
151
|
+
worker_thread = Thread.new do
|
152
|
+
worker_transport = SmartMessage::Transport::RedisQueueTransport.new(
|
153
|
+
url: 'redis://localhost:6379',
|
154
|
+
db: 4,
|
155
|
+
queue_prefix: 'load_balance_demo',
|
156
|
+
consumer_group: 'email_workers',
|
157
|
+
block_time: 1000
|
158
|
+
)
|
159
|
+
|
160
|
+
# Subscribe to email tasks
|
161
|
+
worker_transport.where
|
162
|
+
.type('EmailTask')
|
163
|
+
.consumer_group('email_workers')
|
164
|
+
.subscribe do |message_class, message_data|
|
165
|
+
data = JSON.parse(message_data)
|
166
|
+
worker_id = Thread.current.object_id.to_s[-4..-1]
|
167
|
+
puts "📧 EmailWorker-#{i+1}-#{worker_id} received: #{data['email_id']}"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
email_workers << worker_thread
|
171
|
+
end
|
172
|
+
|
173
|
+
# Group 3: Analytics workers
|
174
|
+
puts "3️⃣ Setting up 'analytics_workers' group (4 workers)"
|
175
|
+
analytics_workers = []
|
176
|
+
4.times do |i|
|
177
|
+
worker_thread = Thread.new do
|
178
|
+
worker_transport = SmartMessage::Transport::RedisQueueTransport.new(
|
179
|
+
url: 'redis://localhost:6379',
|
180
|
+
db: 4,
|
181
|
+
queue_prefix: 'load_balance_demo',
|
182
|
+
consumer_group: 'analytics_workers',
|
183
|
+
block_time: 1000
|
184
|
+
)
|
185
|
+
|
186
|
+
# Subscribe to analytics tasks
|
187
|
+
worker_transport.where
|
188
|
+
.type('DataAnalysisTask')
|
189
|
+
.consumer_group('analytics_workers')
|
190
|
+
.subscribe do |message_class, message_data|
|
191
|
+
data = JSON.parse(message_data)
|
192
|
+
worker_id = Thread.current.object_id.to_s[-4..-1]
|
193
|
+
puts "📊 AnalyticsWorker-#{i+1}-#{worker_id} received: #{data['analysis_id']}"
|
194
|
+
end
|
195
|
+
end
|
196
|
+
analytics_workers << worker_thread
|
197
|
+
end
|
198
|
+
|
199
|
+
# Give workers time to start
|
200
|
+
sleep 2
|
201
|
+
|
202
|
+
#==============================================================================
|
203
|
+
# Load Balancing Demonstration
|
204
|
+
#==============================================================================
|
205
|
+
|
206
|
+
puts "\n📤 Demonstrating load balancing with multiple workers:"
|
207
|
+
|
208
|
+
# Test 1: Processing tasks distributed among 3 workers
|
209
|
+
puts "\n🔸 Test 1: General processing tasks (distributed among 3 workers)"
|
210
|
+
5.times do |i|
|
211
|
+
ProcessingTask.new(
|
212
|
+
task_id: "PROC-#{sprintf('%03d', i + 1)}",
|
213
|
+
task_type: ['data_import', 'file_conversion', 'image_resize', 'pdf_generation', 'backup'][i],
|
214
|
+
complexity: ['low', 'medium', 'high', 'medium', 'low'][i],
|
215
|
+
estimated_seconds: [1, 2, 3, 2, 1][i],
|
216
|
+
payload: { batch_size: rand(100..1000) },
|
217
|
+
_sm_header: {
|
218
|
+
from: 'task_scheduler',
|
219
|
+
to: 'worker_pool'
|
220
|
+
}
|
221
|
+
).publish
|
222
|
+
end
|
223
|
+
|
224
|
+
sleep 3
|
225
|
+
|
226
|
+
# Test 2: Email tasks distributed among 2 workers
|
227
|
+
puts "\n🔸 Test 2: Email tasks (distributed among 2 workers)"
|
228
|
+
6.times do |i|
|
229
|
+
EmailTask.new(
|
230
|
+
email_id: "EMAIL-#{sprintf('%03d', i + 1)}",
|
231
|
+
recipient: "user#{i + 1}@example.com",
|
232
|
+
subject: [
|
233
|
+
'Welcome to our service!',
|
234
|
+
'Your order confirmation',
|
235
|
+
'Password reset request',
|
236
|
+
'Monthly newsletter',
|
237
|
+
'Account verification required',
|
238
|
+
'Special offer inside!'
|
239
|
+
][i],
|
240
|
+
template: ['welcome', 'order', 'password_reset', 'newsletter', 'verification', 'promotion'][i],
|
241
|
+
priority: ['normal', 'high', 'urgent', 'low', 'normal', 'high'][i],
|
242
|
+
_sm_header: {
|
243
|
+
from: 'email_service',
|
244
|
+
to: 'email_queue'
|
245
|
+
}
|
246
|
+
).publish
|
247
|
+
end
|
248
|
+
|
249
|
+
sleep 4
|
250
|
+
|
251
|
+
# Test 3: Analytics tasks distributed among 4 workers
|
252
|
+
puts "\n🔸 Test 3: Analytics tasks (distributed among 4 workers)"
|
253
|
+
8.times do |i|
|
254
|
+
DataAnalysisTask.new(
|
255
|
+
analysis_id: "ANALYSIS-#{sprintf('%03d', i + 1)}",
|
256
|
+
dataset: "dataset_#{i + 1}",
|
257
|
+
analysis_type: ['regression', 'classification', 'clustering', 'time_series', 'correlation', 'anomaly_detection', 'forecasting', 'segmentation'][i],
|
258
|
+
rows: rand(1000..10000),
|
259
|
+
columns: rand(5..50),
|
260
|
+
_sm_header: {
|
261
|
+
from: 'analytics_service',
|
262
|
+
to: 'analytics_queue'
|
263
|
+
}
|
264
|
+
).publish
|
265
|
+
end
|
266
|
+
|
267
|
+
sleep 5
|
268
|
+
|
269
|
+
#==============================================================================
|
270
|
+
# High-Volume Load Test
|
271
|
+
#==============================================================================
|
272
|
+
|
273
|
+
puts "\n🚀 High-volume load balancing test:"
|
274
|
+
|
275
|
+
# Publish many tasks rapidly to see load distribution
|
276
|
+
puts "Publishing 20 processing tasks rapidly..."
|
277
|
+
start_time = Time.now
|
278
|
+
|
279
|
+
20.times do |i|
|
280
|
+
ProcessingTask.new(
|
281
|
+
task_id: "LOAD-#{sprintf('%03d', i + 1)}",
|
282
|
+
task_type: 'load_test',
|
283
|
+
complexity: ['low', 'medium', 'high'].sample,
|
284
|
+
estimated_seconds: rand(1..3),
|
285
|
+
_sm_header: {
|
286
|
+
from: 'load_tester',
|
287
|
+
to: 'worker_pool'
|
288
|
+
}
|
289
|
+
).publish
|
290
|
+
end
|
291
|
+
|
292
|
+
end_time = Time.now
|
293
|
+
puts "✅ Published 20 tasks in #{(end_time - start_time).round(3)} seconds"
|
294
|
+
|
295
|
+
# Wait for processing
|
296
|
+
puts "\n⏳ Waiting for load test completion..."
|
297
|
+
sleep 8
|
298
|
+
|
299
|
+
#==============================================================================
|
300
|
+
# Priority-Based Load Balancing
|
301
|
+
#==============================================================================
|
302
|
+
|
303
|
+
puts "\n⭐ Priority-based load balancing:"
|
304
|
+
|
305
|
+
# Set up priority workers
|
306
|
+
puts "Setting up high-priority worker group..."
|
307
|
+
priority_transport = SmartMessage::Transport::RedisQueueTransport.new(
|
308
|
+
url: 'redis://localhost:6379',
|
309
|
+
db: 4,
|
310
|
+
queue_prefix: 'load_balance_demo',
|
311
|
+
consumer_group: 'priority_workers',
|
312
|
+
block_time: 500
|
313
|
+
)
|
314
|
+
|
315
|
+
# Priority worker subscription
|
316
|
+
priority_worker = Thread.new do
|
317
|
+
priority_transport.where
|
318
|
+
.to('priority_queue')
|
319
|
+
.consumer_group('priority_workers')
|
320
|
+
.subscribe do |message_class, message_data|
|
321
|
+
data = JSON.parse(message_data)
|
322
|
+
puts "🌟 PRIORITY Worker handling: #{data['task_id'] || data['email_id']}"
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
sleep 1
|
327
|
+
|
328
|
+
# Publish priority tasks
|
329
|
+
puts "Publishing high-priority tasks..."
|
330
|
+
3.times do |i|
|
331
|
+
ProcessingTask.new(
|
332
|
+
task_id: "PRIORITY-#{sprintf('%03d', i + 1)}",
|
333
|
+
task_type: 'critical_task',
|
334
|
+
complexity: 'high',
|
335
|
+
estimated_seconds: 1,
|
336
|
+
_sm_header: {
|
337
|
+
from: 'urgent_scheduler',
|
338
|
+
to: 'priority_queue'
|
339
|
+
}
|
340
|
+
).publish
|
341
|
+
end
|
342
|
+
|
343
|
+
# Publish priority emails
|
344
|
+
2.times do |i|
|
345
|
+
EmailTask.new(
|
346
|
+
email_id: "URGENT-EMAIL-#{sprintf('%03d', i + 1)}",
|
347
|
+
recipient: "admin#{i + 1}@company.com",
|
348
|
+
subject: 'URGENT: System Alert',
|
349
|
+
priority: 'urgent',
|
350
|
+
_sm_header: {
|
351
|
+
from: 'alert_system',
|
352
|
+
to: 'priority_queue'
|
353
|
+
}
|
354
|
+
).publish
|
355
|
+
end
|
356
|
+
|
357
|
+
sleep 3
|
358
|
+
|
359
|
+
#==============================================================================
|
360
|
+
# Load Balancing Statistics
|
361
|
+
#==============================================================================
|
362
|
+
|
363
|
+
puts "\n📊 Load Balancing Statistics:"
|
364
|
+
|
365
|
+
# Show queue statistics
|
366
|
+
stats = shared_transport.queue_stats
|
367
|
+
puts "\nQueue lengths after load balancing:"
|
368
|
+
total_queued = 0
|
369
|
+
stats.each do |queue_name, info|
|
370
|
+
total_queued += info[:length]
|
371
|
+
puts " #{queue_name}: #{info[:length]} messages (#{info[:consumers]} consumers)"
|
372
|
+
end
|
373
|
+
|
374
|
+
puts "\nTotal messages remaining in queues: #{total_queued}"
|
375
|
+
|
376
|
+
# Show routing table for consumer groups
|
377
|
+
routing_table = shared_transport.routing_table
|
378
|
+
puts "\nActive consumer group patterns:"
|
379
|
+
routing_table.each do |pattern, queues|
|
380
|
+
puts " Pattern: '#{pattern}'"
|
381
|
+
puts " Queues: #{queues.join(', ')}"
|
382
|
+
end
|
383
|
+
|
384
|
+
#==============================================================================
|
385
|
+
# Worker Performance Comparison
|
386
|
+
#==============================================================================
|
387
|
+
|
388
|
+
puts "\n⚡ Worker Performance Demonstration:"
|
389
|
+
|
390
|
+
# Create workers with different processing speeds
|
391
|
+
puts "Creating workers with different performance characteristics..."
|
392
|
+
|
393
|
+
# Fast worker
|
394
|
+
fast_worker_transport = SmartMessage::Transport::RedisQueueTransport.new(
|
395
|
+
url: 'redis://localhost:6379',
|
396
|
+
db: 4,
|
397
|
+
queue_prefix: 'load_balance_demo',
|
398
|
+
consumer_group: 'performance_test_workers'
|
399
|
+
)
|
400
|
+
|
401
|
+
fast_worker = Thread.new do
|
402
|
+
fast_worker_transport.where
|
403
|
+
.to('performance_test')
|
404
|
+
.consumer_group('performance_test_workers')
|
405
|
+
.subscribe do |message_class, message_data|
|
406
|
+
data = JSON.parse(message_data)
|
407
|
+
puts "🚀 FAST Worker: #{data['task_id']} (processed quickly)"
|
408
|
+
sleep(0.1) # Fast processing
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
# Slow worker
|
413
|
+
slow_worker_transport = SmartMessage::Transport::RedisQueueTransport.new(
|
414
|
+
url: 'redis://localhost:6379',
|
415
|
+
db: 4,
|
416
|
+
queue_prefix: 'load_balance_demo',
|
417
|
+
consumer_group: 'performance_test_workers'
|
418
|
+
)
|
419
|
+
|
420
|
+
slow_worker = Thread.new do
|
421
|
+
slow_worker_transport.where
|
422
|
+
.to('performance_test')
|
423
|
+
.consumer_group('performance_test_workers')
|
424
|
+
.subscribe do |message_class, message_data|
|
425
|
+
data = JSON.parse(message_data)
|
426
|
+
puts "🐌 SLOW Worker: #{data['task_id']} (processing slowly...)"
|
427
|
+
sleep(2.0) # Slow processing
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
sleep 1
|
432
|
+
|
433
|
+
# Send tasks to both workers
|
434
|
+
puts "Sending 10 tasks to mixed-speed worker group..."
|
435
|
+
10.times do |i|
|
436
|
+
ProcessingTask.new(
|
437
|
+
task_id: "PERF-#{sprintf('%03d', i + 1)}",
|
438
|
+
task_type: 'performance_test',
|
439
|
+
complexity: 'medium',
|
440
|
+
_sm_header: {
|
441
|
+
from: 'performance_tester',
|
442
|
+
to: 'performance_test'
|
443
|
+
}
|
444
|
+
).publish
|
445
|
+
end
|
446
|
+
|
447
|
+
puts "⏳ Observing how Redis Queue balances load between fast and slow workers..."
|
448
|
+
sleep 8
|
449
|
+
|
450
|
+
#==============================================================================
|
451
|
+
# Cleanup
|
452
|
+
#==============================================================================
|
453
|
+
|
454
|
+
puts "\n🧹 Cleaning up workers and connections..."
|
455
|
+
|
456
|
+
# Stop all worker threads
|
457
|
+
[processing_workers, email_workers, analytics_workers, priority_worker, fast_worker, slow_worker].flatten.each do |thread|
|
458
|
+
thread.kill if thread.alive?
|
459
|
+
end
|
460
|
+
|
461
|
+
# Disconnect transports
|
462
|
+
shared_transport.disconnect
|
463
|
+
priority_transport.disconnect
|
464
|
+
fast_worker_transport.disconnect
|
465
|
+
slow_worker_transport.disconnect
|
466
|
+
|
467
|
+
puts "\n⚖️ Load balancing demonstration completed!"
|
468
|
+
|
469
|
+
puts "\n💡 Load Balancing Features Demonstrated:"
|
470
|
+
puts " ✓ Consumer groups for work distribution"
|
471
|
+
puts " ✓ Multiple workers sharing same queue"
|
472
|
+
puts " ✓ Round-robin task distribution"
|
473
|
+
puts " ✓ Different worker group configurations"
|
474
|
+
puts " ✓ High-volume load testing"
|
475
|
+
puts " ✓ Priority-based routing"
|
476
|
+
puts " ✓ Mixed-performance worker handling"
|
477
|
+
puts " ✓ Real-time queue monitoring"
|
478
|
+
|
479
|
+
puts "\n🚀 Key Benefits:"
|
480
|
+
puts " • Automatic load distribution via Redis BRPOP"
|
481
|
+
puts " • Scalable worker pool management"
|
482
|
+
puts " • Fair work distribution among workers"
|
483
|
+
puts " • Consumer group isolation"
|
484
|
+
puts " • High-throughput task processing"
|
485
|
+
puts " • Fault-tolerant worker coordination"
|
486
|
+
puts " • Zero-configuration load balancing"
|