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,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
+ ![BunnyFarm Message Flow](images/message_flow.svg)
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
+ ![Producer Consumer Pattern](images/producer_consumer.svg)
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
+ ![Order Workflow](images/order_workflow.svg)
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
+ ![Task Scheduler](images/task_scheduler.svg)
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 &lt; 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>