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
data/examples/README.md
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# BunnyFarm Examples
|
|
2
|
+
|
|
3
|
+
This directory contains practical examples demonstrating how to use the BunnyFarm library for background job processing with RabbitMQ.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
1. **Install RabbitMQ**: Make sure RabbitMQ server is running on your system
|
|
10
|
+
```bash
|
|
11
|
+
# macOS with Homebrew
|
|
12
|
+
brew install rabbitmq
|
|
13
|
+
brew services start rabbitmq
|
|
14
|
+
|
|
15
|
+
# Ubuntu/Debian
|
|
16
|
+
sudo apt-get install rabbitmq-server
|
|
17
|
+
sudo systemctl start rabbitmq-server
|
|
18
|
+
|
|
19
|
+
# Or use Docker
|
|
20
|
+
docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
2. **Install dependencies**: From the gem root directory:
|
|
24
|
+
```bash
|
|
25
|
+
bundle install
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Examples Overview
|
|
29
|
+
|
|
30
|
+
### 1. Simple Producer/Consumer Pattern
|
|
31
|
+
|
|
32
|
+

|
|
33
|
+
|
|
34
|
+
**Files**: `simple_message.rb`, `producer.rb`, `consumer.rb`
|
|
35
|
+
|
|
36
|
+
The simplest example showing basic message production and consumption.
|
|
37
|
+
|
|
38
|
+
**Run the example**:
|
|
39
|
+
```bash
|
|
40
|
+
# Terminal 1 - Start the consumer
|
|
41
|
+
cd examples
|
|
42
|
+
ruby consumer.rb
|
|
43
|
+
|
|
44
|
+
# Terminal 2 - Run the producer
|
|
45
|
+
ruby producer.rb
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**What it demonstrates**:
|
|
49
|
+
- Basic message class definition with `fields` and `actions`
|
|
50
|
+
- Simple message publishing
|
|
51
|
+
- Consumer setup and message processing
|
|
52
|
+
- Success/failure handling
|
|
53
|
+
|
|
54
|
+
### 2. Order Processing Workflow
|
|
55
|
+
|
|
56
|
+

|
|
57
|
+
|
|
58
|
+
**File**: `order_processor.rb`
|
|
59
|
+
|
|
60
|
+
A more complex example showing a multi-step order processing workflow with error handling.
|
|
61
|
+
|
|
62
|
+
**Run the example**:
|
|
63
|
+
```bash
|
|
64
|
+
# Terminal 1 - Start the consumer
|
|
65
|
+
ruby order_processor.rb --consumer
|
|
66
|
+
|
|
67
|
+
# Terminal 2 - Send orders for processing
|
|
68
|
+
ruby order_processor.rb --producer
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**What it demonstrates**:
|
|
72
|
+
- Complex message fields with nested data structures
|
|
73
|
+
- Multi-action workflows (validate → process_payment → ship)
|
|
74
|
+
- Error handling and workflow branching
|
|
75
|
+
- Message chaining (publishing follow-up messages)
|
|
76
|
+
- Random failure simulation for testing
|
|
77
|
+
|
|
78
|
+
### 3. Task Scheduler with Retries
|
|
79
|
+
|
|
80
|
+

|
|
81
|
+
|
|
82
|
+
**File**: `task_scheduler.rb`
|
|
83
|
+
|
|
84
|
+
Demonstrates scheduled task execution with retry logic and failure handling.
|
|
85
|
+
|
|
86
|
+
**Run the example**:
|
|
87
|
+
```bash
|
|
88
|
+
# Terminal 1 - Start the worker
|
|
89
|
+
ruby task_scheduler.rb --worker
|
|
90
|
+
|
|
91
|
+
# Terminal 2 - Schedule tasks
|
|
92
|
+
ruby task_scheduler.rb --scheduler
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**What it demonstrates**:
|
|
96
|
+
- Time-based task scheduling
|
|
97
|
+
- Retry mechanisms with exponential backoff
|
|
98
|
+
- Multiple task types in one message class
|
|
99
|
+
- Error recovery and failure reporting
|
|
100
|
+
- Different execution paths based on task type
|
|
101
|
+
|
|
102
|
+
## Understanding the Code Structure
|
|
103
|
+
|
|
104
|
+
### Message Class Pattern
|
|
105
|
+
|
|
106
|
+
All examples follow the same basic pattern for message classes:
|
|
107
|
+
|
|
108
|
+
```ruby
|
|
109
|
+
class MyMessage < BunnyFarm::Message
|
|
110
|
+
# Define expected fields (can include nested structures)
|
|
111
|
+
fields :field1, :field2, { nested: [:sub1, :sub2] }
|
|
112
|
+
|
|
113
|
+
# Define available actions
|
|
114
|
+
actions :action1, :action2
|
|
115
|
+
|
|
116
|
+
# Implement action methods
|
|
117
|
+
def action1(*args)
|
|
118
|
+
# Process the message
|
|
119
|
+
# Use @items[:field_name] to access data
|
|
120
|
+
|
|
121
|
+
# Mark as successful
|
|
122
|
+
success!
|
|
123
|
+
|
|
124
|
+
# Or mark as failed
|
|
125
|
+
# failure("Error message")
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Configuration
|
|
131
|
+
|
|
132
|
+
All examples use the default configuration from `config/bunny.yml.erb`. You can customize by:
|
|
133
|
+
|
|
134
|
+
1. **Environment variables**:
|
|
135
|
+
```bash
|
|
136
|
+
export AMQP_HOST=localhost
|
|
137
|
+
export AMQP_VHOST=/
|
|
138
|
+
export AMQP_QUEUE=my_queue
|
|
139
|
+
# ... etc
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
2. **Programmatic configuration**:
|
|
143
|
+
```ruby
|
|
144
|
+
BunnyFarm.config do
|
|
145
|
+
env 'production'
|
|
146
|
+
app_id 'my_worker'
|
|
147
|
+
# Custom routing key for consumers
|
|
148
|
+
bunny CONFIG.bunny.merge('routing_key' => 'MyMessage.*')
|
|
149
|
+
end
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Running with Custom RabbitMQ Settings
|
|
153
|
+
|
|
154
|
+
If your RabbitMQ is running on a different host or with different credentials:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
export AMQP_HOST=192.168.1.100
|
|
158
|
+
export AMQP_USER=myuser
|
|
159
|
+
export AMQP_PASS=mypassword
|
|
160
|
+
export AMQP_VHOST=myvhost
|
|
161
|
+
|
|
162
|
+
ruby consumer.rb
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Message Flow
|
|
166
|
+
|
|
167
|
+
Here's how messages flow through the system:
|
|
168
|
+
|
|
169
|
+
1. **Producer** creates a message instance
|
|
170
|
+
2. **Producer** populates message fields with `msg[:field] = value`
|
|
171
|
+
3. **Producer** calls `msg.publish('action_name')`
|
|
172
|
+
4. **RabbitMQ** receives the message with routing key `MessageClassName.action_name`
|
|
173
|
+
5. **Consumer** receives the message based on its routing key configuration
|
|
174
|
+
6. **Consumer** instantiates the message class with the JSON payload
|
|
175
|
+
7. **Consumer** automatically calls the appropriate action method
|
|
176
|
+
8. **Action method** processes the message and marks success/failure
|
|
177
|
+
9. **RabbitMQ** acknowledges or rejects the message based on the result
|
|
178
|
+
|
|
179
|
+
## Troubleshooting
|
|
180
|
+
|
|
181
|
+
### Connection Issues
|
|
182
|
+
- Make sure RabbitMQ is running: `sudo systemctl status rabbitmq-server`
|
|
183
|
+
- Check if the management interface is accessible: http://localhost:15672 (guest/guest)
|
|
184
|
+
- Verify network connectivity if using a remote RabbitMQ server
|
|
185
|
+
|
|
186
|
+
### No Messages Being Processed
|
|
187
|
+
- Check that producer and consumer are using compatible routing keys
|
|
188
|
+
- Verify queue and exchange names match between producer and consumer
|
|
189
|
+
- Look for error messages in the console output
|
|
190
|
+
|
|
191
|
+
### Messages Not Being Acknowledged
|
|
192
|
+
- Ensure action methods call `success!` on successful completion
|
|
193
|
+
- Check for exceptions that might prevent success marking
|
|
194
|
+
- Look for `failure(message)` calls that reject messages
|
|
195
|
+
|
|
196
|
+
## Next Steps
|
|
197
|
+
|
|
198
|
+
After running these examples:
|
|
199
|
+
|
|
200
|
+
1. **Modify the examples** to understand how changes affect behavior
|
|
201
|
+
2. **Create your own message classes** for your specific use cases
|
|
202
|
+
3. **Experiment with different routing patterns** and queue configurations
|
|
203
|
+
4. **Add monitoring and logging** for production use
|
|
204
|
+
5. **Consider scaling patterns** like multiple consumers or load balancing
|
|
205
|
+
|
|
206
|
+
## Additional Resources
|
|
207
|
+
|
|
208
|
+
- [RabbitMQ Documentation](https://www.rabbitmq.com/documentation.html)
|
|
209
|
+
- [AMQP Concepts](https://www.rabbitmq.com/tutorials/amqp-concepts.html)
|
|
210
|
+
- [Bunny Gem Documentation](https://github.com/ruby-amqp/bunny)
|
|
211
|
+
|
|
212
|
+
Happy message processing! 🐰
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# Consumer example - processes messages from RabbitMQ
|
|
3
|
+
|
|
4
|
+
require 'bundler/setup'
|
|
5
|
+
require 'bunny_farm'
|
|
6
|
+
require_relative 'simple_message'
|
|
7
|
+
|
|
8
|
+
# Configure BunnyFarm
|
|
9
|
+
BunnyFarm.config do
|
|
10
|
+
env 'development'
|
|
11
|
+
app_id 'greeting_consumer'
|
|
12
|
+
# Set routing key to match all GreetingMessage actions
|
|
13
|
+
bunny Hashie::Mash.new(
|
|
14
|
+
YAML.load(
|
|
15
|
+
ERB.new(
|
|
16
|
+
File.read(
|
|
17
|
+
File.join(BunnyFarm::CONFIG.config_dir, BunnyFarm::CONFIG.bunny_file)
|
|
18
|
+
)
|
|
19
|
+
).result, aliases: true
|
|
20
|
+
)[BunnyFarm::CONFIG.env].merge(
|
|
21
|
+
'routing_key' => 'GreetingMessage.*'
|
|
22
|
+
)
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
puts "BunnyFarm Consumer Example"
|
|
27
|
+
puts "=" * 40
|
|
28
|
+
puts "Waiting for messages from RabbitMQ..."
|
|
29
|
+
puts "Queue: #{BunnyFarm::CONFIG.bunny.queue_name}"
|
|
30
|
+
puts "Exchange: #{BunnyFarm::CONFIG.bunny.exchange_name}"
|
|
31
|
+
puts "Routing Key: #{BunnyFarm::CONFIG.bunny.routing_key}"
|
|
32
|
+
puts "=" * 40
|
|
33
|
+
puts "Press Ctrl+C to exit"
|
|
34
|
+
puts
|
|
35
|
+
|
|
36
|
+
# Start consuming messages (this will block)
|
|
37
|
+
begin
|
|
38
|
+
BunnyFarm.manage(false) # false = run in foreground (blocking)
|
|
39
|
+
rescue Interrupt
|
|
40
|
+
puts "\n\nShutting down consumer..."
|
|
41
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<svg width="800" height="400" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<!-- Background transparent -->
|
|
3
|
+
<rect width="800" height="400" fill="transparent"/>
|
|
4
|
+
|
|
5
|
+
<!-- Title -->
|
|
6
|
+
<text x="400" y="30" text-anchor="middle" font-family="Arial, sans-serif" font-size="20" font-weight="bold" fill="#e0e0e0">
|
|
7
|
+
BunnyFarm Message Flow
|
|
8
|
+
</text>
|
|
9
|
+
|
|
10
|
+
<!-- Producer -->
|
|
11
|
+
<g>
|
|
12
|
+
<rect x="50" y="80" width="120" height="80" rx="10" fill="#2d3748" stroke="#4a5568" stroke-width="2"/>
|
|
13
|
+
<text x="110" y="110" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="#e0e0e0">Producer</text>
|
|
14
|
+
<text x="110" y="130" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#cbd5e0">Ruby App</text>
|
|
15
|
+
</g>
|
|
16
|
+
|
|
17
|
+
<!-- RabbitMQ -->
|
|
18
|
+
<g>
|
|
19
|
+
<rect x="340" y="60" width="120" height="120" rx="10" fill="#1a365d" stroke="#2b6cb0" stroke-width="2"/>
|
|
20
|
+
<text x="400" y="90" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="#90cdf4">RabbitMQ</text>
|
|
21
|
+
<text x="400" y="110" text-anchor="middle" font-family="Arial, sans-serif" font-size="11" fill="#bee3f8">Exchange</text>
|
|
22
|
+
<text x="400" y="125" text-anchor="middle" font-family="Arial, sans-serif" font-size="11" fill="#bee3f8">Queue</text>
|
|
23
|
+
<!-- Rabbit icon -->
|
|
24
|
+
<ellipse cx="400" cy="145" rx="15" ry="10" fill="#90cdf4"/>
|
|
25
|
+
<ellipse cx="395" cy="140" rx="3" ry="4" fill="#90cdf4"/>
|
|
26
|
+
<ellipse cx="405" cy="140" rx="3" ry="4" fill="#90cdf4"/>
|
|
27
|
+
</g>
|
|
28
|
+
|
|
29
|
+
<!-- Consumer -->
|
|
30
|
+
<g>
|
|
31
|
+
<rect x="630" y="80" width="120" height="80" rx="10" fill="#2d3748" stroke="#4a5568" stroke-width="2"/>
|
|
32
|
+
<text x="690" y="110" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="#e0e0e0">Consumer</text>
|
|
33
|
+
<text x="690" y="130" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#cbd5e0">Worker</text>
|
|
34
|
+
</g>
|
|
35
|
+
|
|
36
|
+
<!-- Arrows -->
|
|
37
|
+
<!-- Producer to RabbitMQ -->
|
|
38
|
+
<defs>
|
|
39
|
+
<marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
40
|
+
<polygon points="0 0, 10 3.5, 0 7" fill="#68d391"/>
|
|
41
|
+
</marker>
|
|
42
|
+
</defs>
|
|
43
|
+
|
|
44
|
+
<line x1="170" y1="120" x2="340" y2="120" stroke="#68d391" stroke-width="2" marker-end="url(#arrowhead)"/>
|
|
45
|
+
<text x="255" y="115" text-anchor="middle" font-family="Arial, sans-serif" font-size="11" fill="#68d391">publish</text>
|
|
46
|
+
|
|
47
|
+
<!-- RabbitMQ to Consumer -->
|
|
48
|
+
<line x1="460" y1="120" x2="630" y2="120" stroke="#68d391" stroke-width="2" marker-end="url(#arrowhead)"/>
|
|
49
|
+
<text x="545" y="115" text-anchor="middle" font-family="Arial, sans-serif" font-size="11" fill="#68d391">deliver</text>
|
|
50
|
+
|
|
51
|
+
<!-- Message flow steps -->
|
|
52
|
+
<g>
|
|
53
|
+
<text x="50" y="220" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="#e0e0e0">Message Flow Steps:</text>
|
|
54
|
+
|
|
55
|
+
<g>
|
|
56
|
+
<circle cx="70" cy="250" r="8" fill="#68d391"/>
|
|
57
|
+
<text x="82" y="255" font-family="Arial, sans-serif" font-size="12" fill="#e0e0e0">1. Create message instance with data</text>
|
|
58
|
+
</g>
|
|
59
|
+
|
|
60
|
+
<g>
|
|
61
|
+
<circle cx="70" cy="275" r="8" fill="#68d391"/>
|
|
62
|
+
<text x="82" y="280" font-family="Arial, sans-serif" font-size="12" fill="#e0e0e0">2. Call msg.publish('action_name')</text>
|
|
63
|
+
</g>
|
|
64
|
+
|
|
65
|
+
<g>
|
|
66
|
+
<circle cx="70" cy="300" r="8" fill="#68d391"/>
|
|
67
|
+
<text x="82" y="305" font-family="Arial, sans-serif" font-size="12" fill="#e0e0e0">3. Message sent with routing key: ClassName.action</text>
|
|
68
|
+
</g>
|
|
69
|
+
|
|
70
|
+
<g>
|
|
71
|
+
<circle cx="70" cy="325" r="8" fill="#68d391"/>
|
|
72
|
+
<text x="82" y="330" font-family="Arial, sans-serif" font-size="12" fill="#e0e0e0">4. Consumer receives and instantiates message class</text>
|
|
73
|
+
</g>
|
|
74
|
+
|
|
75
|
+
<g>
|
|
76
|
+
<circle cx="70" cy="350" r="8" fill="#68d391"/>
|
|
77
|
+
<text x="82" y="355" font-family="Arial, sans-serif" font-size="12" fill="#e0e0e0">5. Action method called automatically, message ACK/NACK sent</text>
|
|
78
|
+
</g>
|
|
79
|
+
</g>
|
|
80
|
+
|
|
81
|
+
<!-- Routing key example -->
|
|
82
|
+
<g>
|
|
83
|
+
<rect x="200" y="200" width="400" height="40" rx="5" fill="#2d3748" stroke="#4a5568" stroke-width="1"/>
|
|
84
|
+
<text x="400" y="215" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#9ca3af">Routing Key Format:</text>
|
|
85
|
+
<text x="400" y="230" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="#f59e0b">MessageClassName.action_name</text>
|
|
86
|
+
</g>
|
|
87
|
+
</svg>
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
<svg width="800" height="500" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<!-- Background transparent -->
|
|
3
|
+
<rect width="800" height="500" fill="transparent"/>
|
|
4
|
+
|
|
5
|
+
<!-- Title -->
|
|
6
|
+
<text x="400" y="30" text-anchor="middle" font-family="Arial, sans-serif" font-size="18" font-weight="bold" fill="#e0e0e0">
|
|
7
|
+
Order Processing Workflow
|
|
8
|
+
</text>
|
|
9
|
+
|
|
10
|
+
<!-- Workflow Steps -->
|
|
11
|
+
|
|
12
|
+
<!-- Step 1: Validate -->
|
|
13
|
+
<g>
|
|
14
|
+
<rect x="50" y="70" width="120" height="80" rx="10" fill="#2d3748" stroke="#68d391" stroke-width="2"/>
|
|
15
|
+
<text x="110" y="95" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="#68d391">VALIDATE</text>
|
|
16
|
+
<text x="110" y="115" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="#e0e0e0">• Check email</text>
|
|
17
|
+
<text x="110" y="130" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="#e0e0e0">• Check amount</text>
|
|
18
|
+
<text x="110" y="145" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="#e0e0e0">• Update status</text>
|
|
19
|
+
</g>
|
|
20
|
+
|
|
21
|
+
<!-- Step 2: Process Payment -->
|
|
22
|
+
<g>
|
|
23
|
+
<rect x="250" y="70" width="120" height="80" rx="10" fill="#2d3748" stroke="#4299e1" stroke-width="2"/>
|
|
24
|
+
<text x="310" y="95" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="#4299e1">PAYMENT</text>
|
|
25
|
+
<text x="310" y="115" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="#e0e0e0">💳 Process</text>
|
|
26
|
+
<text x="310" y="130" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="#e0e0e0">payment</text>
|
|
27
|
+
<text x="310" y="145" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="#e0e0e0">80% success</text>
|
|
28
|
+
</g>
|
|
29
|
+
|
|
30
|
+
<!-- Step 3: Ship -->
|
|
31
|
+
<g>
|
|
32
|
+
<rect x="450" y="70" width="120" height="80" rx="10" fill="#2d3748" stroke="#ed8936" stroke-width="2"/>
|
|
33
|
+
<text x="510" y="95" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="#ed8936">SHIP</text>
|
|
34
|
+
<text x="510" y="115" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="#e0e0e0">📦 Generate</text>
|
|
35
|
+
<text x="510" y="130" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="#e0e0e0">tracking #</text>
|
|
36
|
+
<text x="510" y="145" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="#e0e0e0">Send email</text>
|
|
37
|
+
</g>
|
|
38
|
+
|
|
39
|
+
<!-- Step 4: Cancel (failure path) -->
|
|
40
|
+
<g>
|
|
41
|
+
<rect x="250" y="200" width="120" height="80" rx="10" fill="#2d3748" stroke="#e53e3e" stroke-width="2"/>
|
|
42
|
+
<text x="310" y="225" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="#e53e3e">CANCEL</text>
|
|
43
|
+
<text x="310" y="245" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="#e0e0e0">❌ Handle</text>
|
|
44
|
+
<text x="310" y="260" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="#e0e0e0">failure</text>
|
|
45
|
+
<text x="310" y="275" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="#e0e0e0">Notify customer</text>
|
|
46
|
+
</g>
|
|
47
|
+
|
|
48
|
+
<!-- Success Flow Arrows -->
|
|
49
|
+
<defs>
|
|
50
|
+
<marker id="arrow-success" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
51
|
+
<polygon points="0 0, 10 3.5, 0 7" fill="#68d391"/>
|
|
52
|
+
</marker>
|
|
53
|
+
<marker id="arrow-failure" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
54
|
+
<polygon points="0 0, 10 3.5, 0 7" fill="#e53e3e"/>
|
|
55
|
+
</marker>
|
|
56
|
+
</defs>
|
|
57
|
+
|
|
58
|
+
<!-- Validate to Payment -->
|
|
59
|
+
<line x1="170" y1="110" x2="250" y2="110" stroke="#68d391" stroke-width="2" marker-end="url(#arrow-success)"/>
|
|
60
|
+
<text x="210" y="105" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="#68d391">success</text>
|
|
61
|
+
|
|
62
|
+
<!-- Payment to Ship -->
|
|
63
|
+
<line x1="370" y1="110" x2="450" y2="110" stroke="#68d391" stroke-width="2" marker-end="url(#arrow-success)"/>
|
|
64
|
+
<text x="410" y="105" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="#68d391">paid</text>
|
|
65
|
+
|
|
66
|
+
<!-- Payment to Cancel (failure path) -->
|
|
67
|
+
<line x1="310" y1="150" x2="310" y2="200" stroke="#e53e3e" stroke-width="2" marker-end="url(#arrow-failure)"/>
|
|
68
|
+
<text x="325" y="175" font-family="Arial, sans-serif" font-size="10" fill="#e53e3e">failed</text>
|
|
69
|
+
|
|
70
|
+
<!-- Message Chaining -->
|
|
71
|
+
<g>
|
|
72
|
+
<rect x="50" y="320" width="700" height="100" rx="10" fill="#2d3748" stroke="#9f7aea" stroke-width="2"/>
|
|
73
|
+
<text x="400" y="345" text-anchor="middle" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="#9f7aea">Message Chaining</text>
|
|
74
|
+
<text x="400" y="365" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#e0e0e0">Each step publishes the next action automatically</text>
|
|
75
|
+
|
|
76
|
+
<g>
|
|
77
|
+
<text x="70" y="385" font-family="monospace" font-size="11" fill="#68d391">validate()</text>
|
|
78
|
+
<text x="130" y="385" font-family="monospace" font-size="11" fill="#e0e0e0">→ publish('process_payment')</text>
|
|
79
|
+
|
|
80
|
+
<text x="300" y="385" font-family="monospace" font-size="11" fill="#4299e1">process_payment()</text>
|
|
81
|
+
<text x="410" y="385" font-family="monospace" font-size="11" fill="#e0e0e0">→ publish('ship')</text>
|
|
82
|
+
|
|
83
|
+
<text x="70" y="405" font-family="monospace" font-size="11" fill="#e53e3e">process_payment()</text>
|
|
84
|
+
<text x="180" y="405" font-family="monospace" font-size="11" fill="#e0e0e0">(on failure) → publish('cancel')</text>
|
|
85
|
+
</g>
|
|
86
|
+
</g>
|
|
87
|
+
|
|
88
|
+
<!-- Order Data Structure -->
|
|
89
|
+
<g>
|
|
90
|
+
<rect x="600" y="70" width="150" height="200" rx="10" fill="#1a202c" stroke="#4a5568" stroke-width="1"/>
|
|
91
|
+
<text x="675" y="90" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="#f6e05e">Order Data</text>
|
|
92
|
+
|
|
93
|
+
<text x="610" y="110" font-family="monospace" font-size="9" fill="#e0e0e0">{</text>
|
|
94
|
+
<text x="615" y="125" font-family="monospace" font-size="9" fill="#68d391">order_id:</text>
|
|
95
|
+
<text x="665" y="125" font-family="monospace" font-size="9" fill="#e0e0e0">"ORD-1234",</text>
|
|
96
|
+
<text x="615" y="140" font-family="monospace" font-size="9" fill="#68d391">total_amount:</text>
|
|
97
|
+
<text x="685" y="140" font-family="monospace" font-size="9" fill="#f6e05e">99.99,</text>
|
|
98
|
+
<text x="615" y="155" font-family="monospace" font-size="9" fill="#68d391">status:</text>
|
|
99
|
+
<text x="650" y="155" font-family="monospace" font-size="9" fill="#e0e0e0">"new",</text>
|
|
100
|
+
<text x="615" y="170" font-family="monospace" font-size="9" fill="#68d391">customer:</text>
|
|
101
|
+
<text x="665" y="170" font-family="monospace" font-size="9" fill="#e0e0e0">{</text>
|
|
102
|
+
<text x="625" y="185" font-family="monospace" font-size="9" fill="#4299e1">name:</text>
|
|
103
|
+
<text x="655" y="185" font-family="monospace" font-size="9" fill="#e0e0e0">"John",</text>
|
|
104
|
+
<text x="625" y="200" font-family="monospace" font-size="9" fill="#4299e1">email:</text>
|
|
105
|
+
<text x="655" y="200" font-family="monospace" font-size="9" fill="#e0e0e0">"john@...",</text>
|
|
106
|
+
<text x="625" y="215" font-family="monospace" font-size="9" fill="#4299e1">phone:</text>
|
|
107
|
+
<text x="655" y="215" font-family="monospace" font-size="9" fill="#e0e0e0">"555-..."</text>
|
|
108
|
+
<text x="615" y="230" font-family="monospace" font-size="9" fill="#e0e0e0">},</text>
|
|
109
|
+
<text x="615" y="245" font-family="monospace" font-size="9" fill="#68d391">items:</text>
|
|
110
|
+
<text x="645" y="245" font-family="monospace" font-size="9" fill="#e0e0e0">[...]</text>
|
|
111
|
+
<text x="610" y="260" font-family="monospace" font-size="9" fill="#e0e0e0">}</text>
|
|
112
|
+
</g>
|
|
113
|
+
|
|
114
|
+
<!-- Status indicators -->
|
|
115
|
+
<g>
|
|
116
|
+
<circle cx="625" cy="450" r="8" fill="#68d391"/>
|
|
117
|
+
<text x="640" y="455" font-family="Arial, sans-serif" font-size="12" fill="#e0e0e0">Success Path</text>
|
|
118
|
+
|
|
119
|
+
<circle cx="625" cy="470" r="8" fill="#e53e3e"/>
|
|
120
|
+
<text x="640" y="475" font-family="Arial, sans-serif" font-size="12" fill="#e0e0e0">Failure Path</text>
|
|
121
|
+
</g>
|
|
122
|
+
</svg>
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
<svg width="700" height="450" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<!-- Background transparent -->
|
|
3
|
+
<rect width="700" height="450" fill="transparent"/>
|
|
4
|
+
|
|
5
|
+
<!-- Title -->
|
|
6
|
+
<text x="350" y="30" text-anchor="middle" font-family="Arial, sans-serif" font-size="18" font-weight="bold" fill="#e0e0e0">
|
|
7
|
+
Simple Producer-Consumer Pattern
|
|
8
|
+
</text>
|
|
9
|
+
|
|
10
|
+
<!-- Producer Section -->
|
|
11
|
+
<g>
|
|
12
|
+
<rect x="50" y="70" width="200" height="150" rx="10" fill="#2d3748" stroke="#68d391" stroke-width="2"/>
|
|
13
|
+
<text x="150" y="95" text-anchor="middle" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="#68d391">PRODUCER</text>
|
|
14
|
+
<text x="150" y="115" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#e0e0e0">producer.rb</text>
|
|
15
|
+
|
|
16
|
+
<!-- Code snippet -->
|
|
17
|
+
<rect x="60" y="130" width="180" height="80" fill="#1a202c" stroke="#4a5568" stroke-width="1"/>
|
|
18
|
+
<text x="65" y="145" font-family="monospace" font-size="10" fill="#68d391">msg = GreetingMessage.new</text>
|
|
19
|
+
<text x="65" y="160" font-family="monospace" font-size="10" fill="#e0e0e0">msg[:name] = "User 1"</text>
|
|
20
|
+
<text x="65" y="175" font-family="monospace" font-size="10" fill="#e0e0e0">msg[:timestamp] = Time.now</text>
|
|
21
|
+
<text x="65" y="190" font-family="monospace" font-size="10" fill="#f6e05e">msg.publish('say_hello')</text>
|
|
22
|
+
<text x="65" y="205" font-family="monospace" font-size="10" fill="#9ca3af"># Routing: GreetingMessage.say_hello</text>
|
|
23
|
+
</g>
|
|
24
|
+
|
|
25
|
+
<!-- RabbitMQ Queue -->
|
|
26
|
+
<g>
|
|
27
|
+
<rect x="300" y="100" width="100" height="90" rx="10" fill="#1a365d" stroke="#2b6cb0" stroke-width="2"/>
|
|
28
|
+
<text x="350" y="125" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="#90cdf4">Queue</text>
|
|
29
|
+
|
|
30
|
+
<!-- Message icons in queue -->
|
|
31
|
+
<rect x="315" y="135" width="70" height="12" rx="2" fill="#4299e1"/>
|
|
32
|
+
<rect x="315" y="150" width="70" height="12" rx="2" fill="#4299e1"/>
|
|
33
|
+
<rect x="315" y="165" width="70" height="12" rx="2" fill="#4299e1"/>
|
|
34
|
+
|
|
35
|
+
<text x="350" y="180" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="#bee3f8">Messages</text>
|
|
36
|
+
</g>
|
|
37
|
+
|
|
38
|
+
<!-- Consumer Section -->
|
|
39
|
+
<g>
|
|
40
|
+
<rect x="450" y="70" width="200" height="150" rx="10" fill="#2d3748" stroke="#ed8936" stroke-width="2"/>
|
|
41
|
+
<text x="550" y="95" text-anchor="middle" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="#ed8936">CONSUMER</text>
|
|
42
|
+
<text x="550" y="115" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#e0e0e0">consumer.rb</text>
|
|
43
|
+
|
|
44
|
+
<!-- Code snippet -->
|
|
45
|
+
<rect x="460" y="130" width="180" height="80" fill="#1a202c" stroke="#4a5568" stroke-width="1"/>
|
|
46
|
+
<text x="465" y="145" font-family="monospace" font-size="10" fill="#ed8936">def say_hello(*args)</text>
|
|
47
|
+
<text x="465" y="160" font-family="monospace" font-size="10" fill="#e0e0e0"> puts "Hello #{@items[:name]}"</text>
|
|
48
|
+
<text x="465" y="175" font-family="monospace" font-size="10" fill="#e0e0e0"> sleep 0.5</text>
|
|
49
|
+
<text x="465" y="190" font-family="monospace" font-size="10" fill="#68d391"> success!</text>
|
|
50
|
+
<text x="465" y="205" font-family="monospace" font-size="10" fill="#ed8936">end</text>
|
|
51
|
+
</g>
|
|
52
|
+
|
|
53
|
+
<!-- Arrows -->
|
|
54
|
+
<defs>
|
|
55
|
+
<marker id="arrow-green" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
56
|
+
<polygon points="0 0, 10 3.5, 0 7" fill="#68d391"/>
|
|
57
|
+
</marker>
|
|
58
|
+
<marker id="arrow-orange" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
59
|
+
<polygon points="0 0, 10 3.5, 0 7" fill="#ed8936"/>
|
|
60
|
+
</marker>
|
|
61
|
+
</defs>
|
|
62
|
+
|
|
63
|
+
<!-- Producer to Queue -->
|
|
64
|
+
<line x1="250" y1="145" x2="300" y2="145" stroke="#68d391" stroke-width="2" marker-end="url(#arrow-green)"/>
|
|
65
|
+
<text x="275" y="140" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="#68d391">publish</text>
|
|
66
|
+
|
|
67
|
+
<!-- Queue to Consumer -->
|
|
68
|
+
<line x1="400" y1="145" x2="450" y2="145" stroke="#ed8936" stroke-width="2" marker-end="url(#arrow-orange)"/>
|
|
69
|
+
<text x="425" y="140" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="#ed8936">consume</text>
|
|
70
|
+
|
|
71
|
+
<!-- Message Class Definition -->
|
|
72
|
+
<g>
|
|
73
|
+
<rect x="50" y="260" width="600" height="160" rx="10" fill="#2d3748" stroke="#9f7aea" stroke-width="2"/>
|
|
74
|
+
<text x="350" y="285" text-anchor="middle" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="#9f7aea">GreetingMessage Class</text>
|
|
75
|
+
<text x="350" y="305" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#e0e0e0">simple_message.rb</text>
|
|
76
|
+
|
|
77
|
+
<!-- Code -->
|
|
78
|
+
<rect x="70" y="320" width="560" height="90" fill="#1a202c" stroke="#4a5568" stroke-width="1"/>
|
|
79
|
+
<text x="80" y="340" font-family="monospace" font-size="11" fill="#9f7aea">class GreetingMessage < BunnyFarm::Message</text>
|
|
80
|
+
<text x="90" y="355" font-family="monospace" font-size="11" fill="#68d391">fields</text>
|
|
81
|
+
<text x="130" y="355" font-family="monospace" font-size="11" fill="#e0e0e0">:name, :greeting_type, :timestamp</text>
|
|
82
|
+
<text x="90" y="370" font-family="monospace" font-size="11" fill="#f6e05e">actions</text>
|
|
83
|
+
<text x="130" y="370" font-family="monospace" font-size="11" fill="#e0e0e0">:say_hello, :say_goodbye</text>
|
|
84
|
+
<text x="90" y="385" font-family="monospace" font-size="11" fill="#9ca3af"># Action methods defined here...</text>
|
|
85
|
+
<text x="80" y="400" font-family="monospace" font-size="11" fill="#9f7aea">end</text>
|
|
86
|
+
</g>
|
|
87
|
+
|
|
88
|
+
<!-- Terminal outputs -->
|
|
89
|
+
<g>
|
|
90
|
+
<text x="50" y="445" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="#68d391">Producer Output:</text>
|
|
91
|
+
<text x="180" y="445" font-family="monospace" font-size="10" fill="#9ca3af">✅ Sent hello message for User 1</text>
|
|
92
|
+
|
|
93
|
+
<text x="350" y="445" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="#ed8936">Consumer Output:</text>
|
|
94
|
+
<text x="480" y="445" font-family="monospace" font-size="10" fill="#9ca3af">👋 Hello, User 1!</text>
|
|
95
|
+
</g>
|
|
96
|
+
</svg>
|