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.
- checksums.yaml +7 -0
- data/.envrc +1 -0
- data/.github/workflows/docs.yml +38 -0
- data/.gitignore +11 -0
- data/.travis.yml +3 -0
- data/CHANGELOG.md +61 -0
- data/COMMITS.md +196 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +330 -0
- data/Rakefile +9 -0
- data/bunny_farm.gemspec +30 -0
- data/config/bunny.yml.erb +29 -0
- data/config/bunny_test.yml.erb +29 -0
- data/config/hipchat.yml.erb +12 -0
- data/docs/api/configuration.md +9 -0
- data/docs/api/consumer.md +8 -0
- data/docs/api/message-class.md +419 -0
- data/docs/api/publisher.md +9 -0
- data/docs/architecture/integration.md +8 -0
- data/docs/architecture/message-flow.md +11 -0
- data/docs/architecture/overview.md +448 -0
- data/docs/architecture/scaling.md +8 -0
- data/docs/assets/actions_dsl_flow.svg +109 -0
- data/docs/assets/architecture_overview.svg +152 -0
- data/docs/assets/best_practices_patterns.svg +203 -0
- data/docs/assets/bunny_farm_logo.png +0 -0
- data/docs/assets/configuration_api_methods.svg +104 -0
- data/docs/assets/configuration_flow.svg +130 -0
- data/docs/assets/configuration_hierarchy.svg +70 -0
- data/docs/assets/data_processing_pipeline.svg +131 -0
- data/docs/assets/debugging_monitoring.svg +165 -0
- data/docs/assets/ecommerce_example_flow.svg +145 -0
- data/docs/assets/email_campaign_example.svg +127 -0
- data/docs/assets/environment_variables_map.svg +78 -0
- data/docs/assets/error_handling_flow.svg +114 -0
- data/docs/assets/favicon.ico +1 -0
- data/docs/assets/fields_dsl_structure.svg +89 -0
- data/docs/assets/instance_methods_lifecycle.svg +137 -0
- data/docs/assets/integration_patterns.svg +207 -0
- data/docs/assets/json_serialization_flow.svg +153 -0
- data/docs/assets/logo.svg +4 -0
- data/docs/assets/message_api_overview.svg +126 -0
- data/docs/assets/message_encapsulation.svg +113 -0
- data/docs/assets/message_lifecycle.svg +110 -0
- data/docs/assets/message_structure.svg +138 -0
- data/docs/assets/publisher_consumer_api.svg +120 -0
- data/docs/assets/scaling_deployment_patterns.svg +195 -0
- data/docs/assets/smart_routing_diagram.svg +131 -0
- data/docs/assets/system_architecture_overview.svg +155 -0
- data/docs/assets/task_scheduling_flow.svg +139 -0
- data/docs/assets/testing_strategies.svg +146 -0
- data/docs/assets/workflow_patterns.svg +183 -0
- data/docs/assets/yaml_config_structure.svg +72 -0
- data/docs/configuration/environment-variables.md +14 -0
- data/docs/configuration/overview.md +373 -0
- data/docs/configuration/programmatic-setup.md +10 -0
- data/docs/configuration/yaml-configuration.md +12 -0
- data/docs/core-features/configuration.md +528 -0
- data/docs/core-features/error-handling.md +82 -0
- data/docs/core-features/json-serialization.md +545 -0
- data/docs/core-features/message-design.md +406 -0
- data/docs/core-features/smart-routing.md +467 -0
- data/docs/core-features/task-scheduling.md +67 -0
- data/docs/core-features/workflow-support.md +112 -0
- data/docs/development/contributing.md +345 -0
- data/docs/development/roadmap.md +9 -0
- data/docs/development/testing.md +14 -0
- data/docs/examples/order-processing.md +10 -0
- data/docs/examples/overview.md +269 -0
- data/docs/examples/real-world.md +8 -0
- data/docs/examples/simple-producer-consumer.md +15 -0
- data/docs/examples/task-scheduler.md +9 -0
- data/docs/getting-started/basic-concepts.md +274 -0
- data/docs/getting-started/installation.md +122 -0
- data/docs/getting-started/quick-start.md +158 -0
- data/docs/index.md +106 -0
- data/docs/message-structure/actions-dsl.md +163 -0
- data/docs/message-structure/fields-dsl.md +146 -0
- data/docs/message-structure/instance-methods.md +115 -0
- data/docs/message-structure/overview.md +211 -0
- data/examples/README.md +212 -0
- data/examples/consumer.rb +41 -0
- data/examples/images/message_flow.svg +87 -0
- data/examples/images/order_workflow.svg +122 -0
- data/examples/images/producer_consumer.svg +96 -0
- data/examples/images/task_scheduler.svg +140 -0
- data/examples/order_processor.rb +238 -0
- data/examples/producer.rb +60 -0
- data/examples/simple_message.rb +43 -0
- data/examples/task_scheduler.rb +263 -0
- data/images/architecture_overview.svg +152 -0
- data/images/bunny_farm_logo.png +0 -0
- data/images/configuration_flow.svg +130 -0
- data/images/message_structure.svg +138 -0
- data/lib/bunny_farm/.irbrc +7 -0
- data/lib/bunny_farm/generic_consumer.rb +12 -0
- data/lib/bunny_farm/hash_ext.rb +37 -0
- data/lib/bunny_farm/init_bunny.rb +137 -0
- data/lib/bunny_farm/init_hipchat.rb +49 -0
- data/lib/bunny_farm/message.rb +218 -0
- data/lib/bunny_farm/message_elements.rb +25 -0
- data/lib/bunny_farm/version.rb +3 -0
- data/lib/bunny_farm.rb +9 -0
- data/mkdocs.yml +148 -0
- 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,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>
|