bunny_farm 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. checksums.yaml +7 -0
  2. data/.envrc +1 -0
  3. data/.github/workflows/docs.yml +38 -0
  4. data/.gitignore +11 -0
  5. data/.travis.yml +3 -0
  6. data/CHANGELOG.md +61 -0
  7. data/COMMITS.md +196 -0
  8. data/Gemfile +4 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +330 -0
  11. data/Rakefile +9 -0
  12. data/bunny_farm.gemspec +30 -0
  13. data/config/bunny.yml.erb +29 -0
  14. data/config/bunny_test.yml.erb +29 -0
  15. data/config/hipchat.yml.erb +12 -0
  16. data/docs/api/configuration.md +9 -0
  17. data/docs/api/consumer.md +8 -0
  18. data/docs/api/message-class.md +419 -0
  19. data/docs/api/publisher.md +9 -0
  20. data/docs/architecture/integration.md +8 -0
  21. data/docs/architecture/message-flow.md +11 -0
  22. data/docs/architecture/overview.md +448 -0
  23. data/docs/architecture/scaling.md +8 -0
  24. data/docs/assets/actions_dsl_flow.svg +109 -0
  25. data/docs/assets/architecture_overview.svg +152 -0
  26. data/docs/assets/best_practices_patterns.svg +203 -0
  27. data/docs/assets/bunny_farm_logo.png +0 -0
  28. data/docs/assets/configuration_api_methods.svg +104 -0
  29. data/docs/assets/configuration_flow.svg +130 -0
  30. data/docs/assets/configuration_hierarchy.svg +70 -0
  31. data/docs/assets/data_processing_pipeline.svg +131 -0
  32. data/docs/assets/debugging_monitoring.svg +165 -0
  33. data/docs/assets/ecommerce_example_flow.svg +145 -0
  34. data/docs/assets/email_campaign_example.svg +127 -0
  35. data/docs/assets/environment_variables_map.svg +78 -0
  36. data/docs/assets/error_handling_flow.svg +114 -0
  37. data/docs/assets/favicon.ico +1 -0
  38. data/docs/assets/fields_dsl_structure.svg +89 -0
  39. data/docs/assets/instance_methods_lifecycle.svg +137 -0
  40. data/docs/assets/integration_patterns.svg +207 -0
  41. data/docs/assets/json_serialization_flow.svg +153 -0
  42. data/docs/assets/logo.svg +4 -0
  43. data/docs/assets/message_api_overview.svg +126 -0
  44. data/docs/assets/message_encapsulation.svg +113 -0
  45. data/docs/assets/message_lifecycle.svg +110 -0
  46. data/docs/assets/message_structure.svg +138 -0
  47. data/docs/assets/publisher_consumer_api.svg +120 -0
  48. data/docs/assets/scaling_deployment_patterns.svg +195 -0
  49. data/docs/assets/smart_routing_diagram.svg +131 -0
  50. data/docs/assets/system_architecture_overview.svg +155 -0
  51. data/docs/assets/task_scheduling_flow.svg +139 -0
  52. data/docs/assets/testing_strategies.svg +146 -0
  53. data/docs/assets/workflow_patterns.svg +183 -0
  54. data/docs/assets/yaml_config_structure.svg +72 -0
  55. data/docs/configuration/environment-variables.md +14 -0
  56. data/docs/configuration/overview.md +373 -0
  57. data/docs/configuration/programmatic-setup.md +10 -0
  58. data/docs/configuration/yaml-configuration.md +12 -0
  59. data/docs/core-features/configuration.md +528 -0
  60. data/docs/core-features/error-handling.md +82 -0
  61. data/docs/core-features/json-serialization.md +545 -0
  62. data/docs/core-features/message-design.md +406 -0
  63. data/docs/core-features/smart-routing.md +467 -0
  64. data/docs/core-features/task-scheduling.md +67 -0
  65. data/docs/core-features/workflow-support.md +112 -0
  66. data/docs/development/contributing.md +345 -0
  67. data/docs/development/roadmap.md +9 -0
  68. data/docs/development/testing.md +14 -0
  69. data/docs/examples/order-processing.md +10 -0
  70. data/docs/examples/overview.md +269 -0
  71. data/docs/examples/real-world.md +8 -0
  72. data/docs/examples/simple-producer-consumer.md +15 -0
  73. data/docs/examples/task-scheduler.md +9 -0
  74. data/docs/getting-started/basic-concepts.md +274 -0
  75. data/docs/getting-started/installation.md +122 -0
  76. data/docs/getting-started/quick-start.md +158 -0
  77. data/docs/index.md +106 -0
  78. data/docs/message-structure/actions-dsl.md +163 -0
  79. data/docs/message-structure/fields-dsl.md +146 -0
  80. data/docs/message-structure/instance-methods.md +115 -0
  81. data/docs/message-structure/overview.md +211 -0
  82. data/examples/README.md +212 -0
  83. data/examples/consumer.rb +41 -0
  84. data/examples/images/message_flow.svg +87 -0
  85. data/examples/images/order_workflow.svg +122 -0
  86. data/examples/images/producer_consumer.svg +96 -0
  87. data/examples/images/task_scheduler.svg +140 -0
  88. data/examples/order_processor.rb +238 -0
  89. data/examples/producer.rb +60 -0
  90. data/examples/simple_message.rb +43 -0
  91. data/examples/task_scheduler.rb +263 -0
  92. data/images/architecture_overview.svg +152 -0
  93. data/images/bunny_farm_logo.png +0 -0
  94. data/images/configuration_flow.svg +130 -0
  95. data/images/message_structure.svg +138 -0
  96. data/lib/bunny_farm/.irbrc +7 -0
  97. data/lib/bunny_farm/generic_consumer.rb +12 -0
  98. data/lib/bunny_farm/hash_ext.rb +37 -0
  99. data/lib/bunny_farm/init_bunny.rb +137 -0
  100. data/lib/bunny_farm/init_hipchat.rb +49 -0
  101. data/lib/bunny_farm/message.rb +218 -0
  102. data/lib/bunny_farm/message_elements.rb +25 -0
  103. data/lib/bunny_farm/version.rb +3 -0
  104. data/lib/bunny_farm.rb +9 -0
  105. data/mkdocs.yml +148 -0
  106. metadata +244 -0
@@ -0,0 +1,448 @@
1
+ # Architecture Overview
2
+
3
+ BunnyFarm provides a clean, layered architecture that separates concerns and enables scalable message processing. This section covers the overall system design and how components interact.
4
+
5
+ <img src="../assets/architecture_overview.svg" alt="Architecture Overview" width="100%">
6
+
7
+ ## Architectural Layers
8
+
9
+ ### 1. Ruby Application Layer
10
+
11
+ The top layer consists of your Ruby applications that produce and consume messages:
12
+
13
+ **Producers:**
14
+ - Web applications handling user requests
15
+ - API servers processing external requests
16
+ - Scheduled jobs and cron tasks
17
+ - Other microservices
18
+
19
+ **Consumers:**
20
+ - Background worker processes
21
+ - Microservices handling specific domains
22
+ - Event processors
23
+ - Data pipeline components
24
+
25
+ ### 2. BunnyFarm Library Layer
26
+
27
+ The BunnyFarm library provides the core abstractions and functionality:
28
+
29
+ **Core Components:**
30
+
31
+ #### Message Classes
32
+ - Base class for all message types
33
+ - DSL for defining data structure (fields)
34
+ - DSL for defining operations (actions)
35
+ - Built-in serialization and validation
36
+
37
+ #### Publisher
38
+ - Message publishing functionality
39
+ - Connection management
40
+ - Routing key generation
41
+ - Error handling
42
+
43
+ #### Consumer
44
+ - Message consumption and processing
45
+ - Automatic deserialization
46
+ - Action method routing
47
+ - ACK/NACK management
48
+
49
+ #### Configuration
50
+ - Environment-based configuration
51
+ - YAML configuration file support
52
+ - Programmatic configuration
53
+ - Connection parameter management
54
+
55
+ #### Router
56
+ - Routing key parsing and generation
57
+ - Action method dispatching
58
+ - Message type resolution
59
+
60
+ ### 3. RabbitMQ Message Broker
61
+
62
+ RabbitMQ serves as the message broker layer:
63
+
64
+ **Key Components:**
65
+
66
+ #### Exchange
67
+ - Routes messages based on routing keys
68
+ - Typically uses topic exchange for flexible routing
69
+ - Handles message durability and persistence
70
+
71
+ #### Queues
72
+ - Store messages until consumed
73
+ - Support various configurations (durable, auto-delete, etc.)
74
+ - Handle message ordering and priority
75
+
76
+ #### Management Interface
77
+ - Web-based administration
78
+ - Queue and exchange monitoring
79
+ - Performance metrics and alerts
80
+
81
+ ### 4. Persistence & External Services
82
+
83
+ The bottom layer includes external dependencies:
84
+
85
+ - **Databases** - For persistent data storage
86
+ - **Email Services** - For notification sending
87
+ - **File Storage** - For document and media handling
88
+ - **External APIs** - For third-party integrations
89
+ - **Caching** - Redis/Memcached for performance
90
+
91
+ ## Message Flow Architecture
92
+
93
+ <img src="../assets/message_flow.svg" alt="Message Flow" width="100%">
94
+
95
+ The message processing follows a predictable flow:
96
+
97
+ ### 1. Message Creation
98
+ ```ruby
99
+ message = OrderMessage.new
100
+ message[:order_id] = 12345
101
+ message[:customer] = customer_data
102
+ ```
103
+
104
+ ### 2. Publishing
105
+ ```ruby
106
+ message.publish('process') # Creates routing key: OrderMessage.process
107
+ ```
108
+
109
+ ### 3. RabbitMQ Routing
110
+ - Exchange receives message with routing key
111
+ - Routes to appropriate queue(s) based on bindings
112
+ - Message persisted until consumed
113
+
114
+ ### 4. Consumption
115
+ ```ruby
116
+ BunnyFarm.manage # Consumer polls for messages
117
+ ```
118
+
119
+ ### 5. Processing
120
+ - Message deserialized from JSON
121
+ - Appropriate action method called
122
+ - Business logic executed
123
+
124
+ ### 6. Acknowledgment
125
+ - Success returns `true` → ACK sent to RabbitMQ
126
+ - Failure returns `false` → NACK sent (message requeued or dead-lettered)
127
+
128
+ ## Design Principles
129
+
130
+ ### Message-Centric Design
131
+
132
+ Messages are first-class objects that encapsulate both data and behavior:
133
+
134
+ ```ruby
135
+ class OrderMessage < BunnyFarm::Message
136
+ # Data structure
137
+ fields :order_id, :customer, :items
138
+
139
+ # Behavior
140
+ actions :validate, :process, :ship
141
+
142
+ def validate
143
+ # Validation logic
144
+ end
145
+ end
146
+ ```
147
+
148
+ This approach provides:
149
+ - **Encapsulation** - Data and behavior stay together
150
+ - **Discoverability** - Easy to understand what a message can do
151
+ - **Testability** - Individual message types can be unit tested
152
+
153
+ ### Predictable Routing
154
+
155
+ Routing keys follow a consistent pattern:
156
+
157
+ ```
158
+ MessageClassName.action
159
+ ```
160
+
161
+ Examples:
162
+ - `OrderMessage.process`
163
+ - `EmailMessage.send`
164
+ - `ReportMessage.generate`
165
+
166
+ Benefits:
167
+ - **Transparency** - Easy to understand message flow
168
+ - **Debugging** - Clear routing paths
169
+ - **Monitoring** - Trackable message types
170
+
171
+ ### JSON Serialization
172
+
173
+ All message data uses JSON serialization:
174
+
175
+ ```json
176
+ {
177
+ "order_id": 12345,
178
+ "customer": {
179
+ "name": "John Doe",
180
+ "email": "john@example.com"
181
+ },
182
+ "items": [
183
+ {"product_id": 1, "quantity": 2}
184
+ ]
185
+ }
186
+ ```
187
+
188
+ Advantages:
189
+ - **Human readable** - Easy debugging and monitoring
190
+ - **Language agnostic** - Other systems can integrate
191
+ - **Tooling support** - JSON tools widely available
192
+
193
+ ## Scalability Patterns
194
+
195
+ ### Horizontal Scaling
196
+
197
+ Add more consumers to handle increased load:
198
+
199
+ ```ruby
200
+ # Worker 1
201
+ BunnyFarm.config { app_id 'worker_1' }
202
+ BunnyFarm.manage
203
+
204
+ # Worker 2
205
+ BunnyFarm.config { app_id 'worker_2' }
206
+ BunnyFarm.manage
207
+
208
+ # Worker N...
209
+ ```
210
+
211
+ Multiple consumers can process messages from the same queue concurrently.
212
+
213
+ ### Queue Partitioning
214
+
215
+ Use different queues for different message types or priorities:
216
+
217
+ ```ruby
218
+ # High priority queue
219
+ BunnyFarm.config do
220
+ queue_name 'high_priority_orders'
221
+ routing_key 'OrderMessage.urgent'
222
+ end
223
+
224
+ # Normal priority queue
225
+ BunnyFarm.config do
226
+ queue_name 'normal_orders'
227
+ routing_key 'OrderMessage.process'
228
+ end
229
+ ```
230
+
231
+ ### Load Balancing
232
+
233
+ RabbitMQ automatically load balances messages across multiple consumers using round-robin distribution.
234
+
235
+ ## Fault Tolerance
236
+
237
+ ### Message Persistence
238
+
239
+ Messages can be persisted to disk:
240
+
241
+ ```ruby
242
+ BunnyFarm.config do
243
+ exchange_options durable: true
244
+ queue_options durable: true
245
+ message_options persistent: true
246
+ end
247
+ ```
248
+
249
+ ### Error Handling
250
+
251
+ Failed messages can be:
252
+ - **Retried** - Requeued automatically
253
+ - **Dead lettered** - Sent to error queue
254
+ - **Logged** - For manual inspection
255
+
256
+ ```ruby
257
+ def risky_operation
258
+ begin
259
+ perform_work
260
+ success!
261
+ rescue => e
262
+ failure("Operation failed: #{e.message}")
263
+ end
264
+
265
+ successful?
266
+ end
267
+ ```
268
+
269
+ ### Circuit Breaker Pattern
270
+
271
+ Prevent cascading failures:
272
+
273
+ ```ruby
274
+ def external_service_call
275
+ if circuit_breaker.open?
276
+ failure("Circuit breaker open - service unavailable")
277
+ return
278
+ end
279
+
280
+ begin
281
+ result = external_service.call
282
+ circuit_breaker.record_success
283
+ success!
284
+ rescue => e
285
+ circuit_breaker.record_failure
286
+ failure("External service failed: #{e.message}")
287
+ end
288
+
289
+ successful?
290
+ end
291
+ ```
292
+
293
+ ## Monitoring and Observability
294
+
295
+ ### RabbitMQ Management
296
+
297
+ Built-in monitoring via RabbitMQ management interface:
298
+ - Queue depths and rates
299
+ - Consumer activity
300
+ - Message flow metrics
301
+ - Connection status
302
+
303
+ ### Application Metrics
304
+
305
+ Track application-level metrics:
306
+
307
+ ```ruby
308
+ def process_order
309
+ StatsD.increment 'orders.processing.started'
310
+
311
+ result = perform_processing
312
+
313
+ if successful?
314
+ StatsD.increment 'orders.processing.success'
315
+ else
316
+ StatsD.increment 'orders.processing.failed'
317
+ end
318
+
319
+ result
320
+ end
321
+ ```
322
+
323
+ ### Logging
324
+
325
+ Structured logging for message processing:
326
+
327
+ ```ruby
328
+ def process_order
329
+ logger.info "Processing order", order_id: @items[:order_id]
330
+
331
+ # ... processing
332
+
333
+ if successful?
334
+ logger.info "Order processed successfully", order_id: @items[:order_id]
335
+ else
336
+ logger.error "Order processing failed",
337
+ order_id: @items[:order_id],
338
+ errors: errors
339
+ end
340
+ end
341
+ ```
342
+
343
+ ## Integration Patterns
344
+
345
+ ### Event-Driven Architecture
346
+
347
+ Use BunnyFarm for event-driven communication between services:
348
+
349
+ ```ruby
350
+ # Service A publishes events
351
+ order_created = OrderCreatedEvent.new
352
+ order_created[:order_id] = order.id
353
+ order_created.publish('notify_services')
354
+
355
+ # Service B subscribes to events
356
+ class OrderCreatedEvent < BunnyFarm::Message
357
+ actions :update_inventory, :send_confirmation
358
+
359
+ def update_inventory
360
+ # Update inventory service
361
+ end
362
+
363
+ def send_confirmation
364
+ # Send customer confirmation
365
+ end
366
+ end
367
+ ```
368
+
369
+ ### Saga Pattern
370
+
371
+ Implement distributed transactions:
372
+
373
+ ```ruby
374
+ class OrderSaga < BunnyFarm::Message
375
+ actions :start, :process_payment, :reserve_inventory,
376
+ :ship_order, :complete, :compensate
377
+
378
+ def start
379
+ # Begin saga
380
+ next_step('process_payment')
381
+ end
382
+
383
+ def process_payment
384
+ if payment_successful?
385
+ next_step('reserve_inventory')
386
+ else
387
+ compensate('payment_failed')
388
+ end
389
+ end
390
+
391
+ private
392
+
393
+ def next_step(action)
394
+ self.class.new(@items).publish(action)
395
+ end
396
+ end
397
+ ```
398
+
399
+ ## Performance Considerations
400
+
401
+ ### Connection Pooling
402
+
403
+ For high-throughput scenarios:
404
+
405
+ ```ruby
406
+ BunnyFarm.config do
407
+ connection_pool_size 10
408
+ channel_pool_size 20
409
+ end
410
+ ```
411
+
412
+ ### Batch Processing
413
+
414
+ Process multiple messages together:
415
+
416
+ ```ruby
417
+ def process_batch
418
+ messages = consume_batch(size: 100)
419
+
420
+ ActiveRecord::Base.transaction do
421
+ messages.each(&:process)
422
+ end
423
+ end
424
+ ```
425
+
426
+ ### Memory Management
427
+
428
+ For long-running consumers:
429
+
430
+ ```ruby
431
+ def process_with_memory_management
432
+ GC.start if processed_count % 1000 == 0
433
+
434
+ # Process message
435
+
436
+ ensure
437
+ # Cleanup resources
438
+ end
439
+ ```
440
+
441
+ ## Next Steps
442
+
443
+ Explore specific architectural topics:
444
+
445
+ - **[Message Flow](message-flow.md)** - Detailed message processing flow
446
+ - **[Scaling Patterns](scaling.md)** - Horizontal and vertical scaling strategies
447
+ - **[Integration Patterns](integration.md)** - Common integration scenarios
448
+ - **[Configuration](../configuration/overview.md)** - Architecture configuration options
@@ -0,0 +1,8 @@
1
+ # Scaling Patterns
2
+
3
+ Horizontal and vertical scaling strategies.
4
+
5
+ ## Horizontal Scaling
6
+ - Multiple consumer instances
7
+ - Queue partitioning
8
+ - Load balancing
@@ -0,0 +1,109 @@
1
+ <svg width="900" height="600" xmlns="http://www.w3.org/2000/svg">
2
+ <rect width="900" height="600" fill="transparent"/>
3
+
4
+ <!-- Title -->
5
+ <text x="450" y="30" text-anchor="middle" font-family="Arial, sans-serif" font-size="18" font-weight="bold" fill="#e0e0e0">
6
+ Actions DSL: Defining Message Behaviors
7
+ </text>
8
+
9
+ <!-- Action Declaration -->
10
+ <g>
11
+ <text x="450" y="70" text-anchor="middle" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="#f6e05e">
12
+ Action Declaration and Implementation
13
+ </text>
14
+
15
+ <rect x="50" y="90" width="800" height="140" rx="8" fill="#2d3748" stroke="#f6e05e" stroke-width="2"/>
16
+ <text x="450" y="115" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="#f6e05e">Complete Action Definition</text>
17
+
18
+ <text x="70" y="140" font-family="monospace" font-size="12" fill="#4299e1">class OrderMessage extends BunnyFarm::Message</text>
19
+ <text x="80" y="160" font-family="monospace" font-size="12" fill="#68d391">fields</text>
20
+ <text x="140" y="160" font-family="monospace" font-size="12" fill="#e0e0e0">:order_id, :customer_id, :items, :total</text>
21
+ <text x="80" y="180" font-family="monospace" font-size="12" fill="#f6e05e">actions</text>
22
+ <text x="150" y="180" font-family="monospace" font-size="12" fill="#e0e0e0">:validate, :process, :ship, :cancel</text>
23
+ <text x="80" y="200" font-family="monospace" font-size="12" fill="#9f7aea">def validate</text>
24
+ <text x="90" y="220" font-family="monospace" font-size="12" fill="#e0e0e0">check_inventory and validate_payment</text>
25
+ <text x="80" y="240" font-family="monospace" font-size="12" fill="#9f7aea">end</text>
26
+ <text x="70" y="260" font-family="monospace" font-size="12" fill="#4299e1">end</text>
27
+ </g>
28
+
29
+ <!-- Action Types -->
30
+ <g>
31
+ <text x="450" y="300" text-anchor="middle" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="#e0e0e0">
32
+ Action Types and Patterns
33
+ </text>
34
+
35
+ <!-- Simple Actions -->
36
+ <rect x="50" y="320" width="200" height="100" rx="6" fill="#2d3748" stroke="#68d391" stroke-width="2"/>
37
+ <text x="150" y="345" text-anchor="middle" font-family="Arial, sans-serif" font-size="13" font-weight="bold" fill="#68d391">Simple Actions</text>
38
+ <text x="60" y="365" font-family="monospace" font-size="10" fill="#e0e0e0">def send_email</text>
39
+ <text x="70" y="380" font-family="monospace" font-size="10" fill="#e0e0e0">EmailService.send(</text>
40
+ <text x="80" y="395" font-family="monospace" font-size="10" fill="#e0e0e0">self[:recipient],</text>
41
+ <text x="80" y="410" font-family="monospace" font-size="10" fill="#e0e0e0">self[:message])</text>
42
+ <text x="60" y="425" font-family="monospace" font-size="10" fill="#e0e0e0">end</text>
43
+
44
+ <!-- Workflow Actions -->
45
+ <rect x="270" y="320" width="200" height="100" rx="6" fill="#2d3748" stroke="#4299e1" stroke-width="2"/>
46
+ <text x="370" y="345" text-anchor="middle" font-family="Arial, sans-serif" font-size="13" font-weight="bold" fill="#4299e1">Workflow Actions</text>
47
+ <text x="280" y="365" font-family="monospace" font-size="10" fill="#e0e0e0">def process_order</text>
48
+ <text x="290" y="380" font-family="monospace" font-size="10" fill="#e0e0e0">publish('validate')</text>
49
+ <text x="290" y="395" font-family="monospace" font-size="10" fill="#e0e0e0">publish('charge')</text>
50
+ <text x="290" y="410" font-family="monospace" font-size="10" fill="#e0e0e0">publish('fulfill')</text>
51
+ <text x="280" y="425" font-family="monospace" font-size="10" fill="#e0e0e0">end</text>
52
+
53
+ <!-- Conditional Actions -->
54
+ <rect x="490" y="320" width="200" height="100" rx="6" fill="#2d3748" stroke="#9f7aea" stroke-width="2"/>
55
+ <text x="590" y="345" text-anchor="middle" font-family="Arial, sans-serif" font-size="13" font-weight="bold" fill="#9f7aea">Conditional Actions</text>
56
+ <text x="500" y="365" font-family="monospace" font-size="10" fill="#e0e0e0">def handle_payment</text>
57
+ <text x="510" y="380" font-family="monospace" font-size="10" fill="#e0e0e0">if premium_customer?</text>
58
+ <text x="520" y="395" font-family="monospace" font-size="10" fill="#e0e0e0">fast_checkout</text>
59
+ <text x="510" y="410" font-family="monospace" font-size="10" fill="#e0e0e0">else standard_flow</text>
60
+ <text x="500" y="425" font-family="monospace" font-size="10" fill="#e0e0e0">end</text>
61
+
62
+ <!-- Error Handling Actions -->
63
+ <rect x="710" y="320" width="180" height="100" rx="6" fill="#2d3748" stroke="#e53e3e" stroke-width="2"/>
64
+ <text x="800" y="345" text-anchor="middle" font-family="Arial, sans-serif" font-size="13" font-weight="bold" fill="#e53e3e">Error Actions</text>
65
+ <text x="720" y="365" font-family="monospace" font-size="10" fill="#e0e0e0">def retry_payment</text>
66
+ <text x="730" y="380" font-family="monospace" font-size="10" fill="#e0e0e0">retry_count += 1</text>
67
+ <text x="730" y="395" font-family="monospace" font-size="10" fill="#e0e0e0">if retry_count > 3</text>
68
+ <text x="740" y="410" font-family="monospace" font-size="10" fill="#e0e0e0">publish('failed')</text>
69
+ <text x="720" y="425" font-family="monospace" font-size="10" fill="#e0e0e0">end</text>
70
+ </g>
71
+
72
+ <!-- Action Execution Flow -->
73
+ <g>
74
+ <text x="450" y="470" text-anchor="middle" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="#e0e0e0">
75
+ Action Execution and Routing
76
+ </text>
77
+
78
+ <!-- Publishing -->
79
+ <rect x="50" y="490" width="160" height="60" rx="6" fill="#1a202c" stroke="#ff9800" stroke-width="1"/>
80
+ <text x="130" y="515" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="#ff9800">1. Publish</text>
81
+ <text x="60" y="535" font-family="monospace" font-size="10" fill="#e0e0e0">message.publish('validate')</text>
82
+
83
+ <!-- Routing -->
84
+ <rect x="240" y="490" width="160" height="60" rx="6" fill="#1a202c" stroke="#f6e05e" stroke-width="1"/>
85
+ <text x="320" y="515" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="#f6e05e">2. Route</text>
86
+ <text x="250" y="535" font-family="monospace" font-size="10" fill="#e0e0e0">OrderMessage.validate</text>
87
+
88
+ <!-- Consume -->
89
+ <rect x="430" y="490" width="160" height="60" rx="6" fill="#1a202c" stroke="#4299e1" stroke-width="1"/>
90
+ <text x="510" y="515" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="#4299e1">3. Consume</text>
91
+ <text x="440" y="535" font-family="monospace" font-size="10" fill="#e0e0e0">Worker picks up message</text>
92
+
93
+ <!-- Execute -->
94
+ <rect x="620" y="490" width="160" height="60" rx="6" fill="#1a202c" stroke="#68d391" stroke-width="1"/>
95
+ <text x="700" y="515" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="#68d391">4. Execute</text>
96
+ <text x="630" y="535" font-family="monospace" font-size="10" fill="#e0e0e0">message.validate()</text>
97
+ </g>
98
+
99
+ <!-- Flow arrows -->
100
+ <defs>
101
+ <marker id="arrow-action" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
102
+ <polygon points="0 0, 8 3, 0 6" fill="#ff9800"/>
103
+ </marker>
104
+ </defs>
105
+
106
+ <line x1="210" y1="520" x2="240" y2="520" stroke="#ff9800" stroke-width="2" marker-end="url(#arrow-action)"/>
107
+ <line x1="400" y1="520" x2="430" y2="520" stroke="#ff9800" stroke-width="2" marker-end="url(#arrow-action)"/>
108
+ <line x1="590" y1="520" x2="620" y2="520" stroke="#ff9800" stroke-width="2" marker-end="url(#arrow-action)"/>
109
+ </svg>