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,406 @@
1
+ # Message-Centric Design
2
+
3
+ BunnyFarm's core philosophy revolves around treating messages as first-class objects that encapsulate both data and behavior. This approach provides a clean, object-oriented way to handle background job processing.
4
+
5
+ ## What is Message-Centric Design?
6
+
7
+ In traditional job queue systems, jobs are simple data structures passed to generic worker processes. BunnyFarm takes a different approach where each message type is a full Ruby class that defines:
8
+
9
+ - **Data structure** - What fields the message contains
10
+ - **Business logic** - What operations can be performed
11
+ - **Error handling** - How failures are managed
12
+ - **State management** - Success/failure tracking
13
+
14
+ ## Benefits of Message Classes
15
+
16
+ ### 1. Encapsulation
17
+ Related data and behavior stay together:
18
+
19
+ ```ruby
20
+ class OrderMessage < BunnyFarm::Message
21
+ # Data structure
22
+ fields :order_id, :customer_email, :items
23
+
24
+ # Business logic
25
+ actions :validate, :process_payment, :ship
26
+
27
+ def validate
28
+ validate_order_data
29
+ validate_customer_info
30
+ success! if errors.empty?
31
+ end
32
+
33
+ def process_payment
34
+ # Payment logic here
35
+ success!
36
+ end
37
+ end
38
+ ```
39
+
40
+ ### 2. Discoverability
41
+ Easy to understand what a message can do:
42
+
43
+ ```ruby
44
+ # Clear interface
45
+ OrderMessage.new.respond_to?(:validate) # => true
46
+ OrderMessage.new.respond_to?(:ship) # => true
47
+ OrderMessage.new.respond_to?(:fly_rocket) # => false
48
+ ```
49
+
50
+ ### 3. Testability
51
+ Individual message types can be unit tested:
52
+
53
+ ```ruby
54
+ class TestOrderMessage < Minitest::Test
55
+ def test_validation
56
+ message = OrderMessage.new
57
+ message[:order_id] = nil
58
+ message.validate
59
+
60
+ assert message.failed?
61
+ assert_includes message.errors, "Order ID required"
62
+ end
63
+ end
64
+ ```
65
+
66
+ ### 4. Type Safety
67
+ Ruby's class system provides structure:
68
+
69
+ ```ruby
70
+ class OrderMessage < BunnyFarm::Message
71
+ fields :order_id, :customer_email
72
+
73
+ def validate
74
+ failure("Order ID required") if @items[:order_id].nil?
75
+ failure("Invalid email") unless valid_email?(@items[:customer_email])
76
+ end
77
+
78
+ private
79
+
80
+ def valid_email?(email)
81
+ email =~ /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
82
+ end
83
+ end
84
+ ```
85
+
86
+ ## Message Anatomy
87
+
88
+ Every BunnyFarm message has four key components:
89
+
90
+ ### 1. Class Definition
91
+ Inherit from `BunnyFarm::Message`:
92
+
93
+ ```ruby
94
+ class CustomerMessage < BunnyFarm::Message
95
+ # Message definition
96
+ end
97
+ ```
98
+
99
+ ### 2. Fields DSL
100
+ Define the data structure:
101
+
102
+ ```ruby
103
+ fields :name, :email, :phone,
104
+ { address: [:street, :city, :state, :zip] },
105
+ { preferences: [:newsletter, :marketing] }
106
+ ```
107
+
108
+ ### 3. Actions DSL
109
+ Define available operations:
110
+
111
+ ```ruby
112
+ actions :register, :update_profile, :send_welcome_email
113
+ ```
114
+
115
+ ### 4. Action Methods
116
+ Implement the business logic:
117
+
118
+ ```ruby
119
+ def register
120
+ validate_customer_data
121
+ return unless successful?
122
+
123
+ create_account
124
+ return unless successful?
125
+
126
+ send_welcome_email
127
+ end
128
+ ```
129
+
130
+ ## Design Patterns
131
+
132
+ ### Command Pattern
133
+ Each action is a command that can be executed:
134
+
135
+ ```ruby
136
+ class ReportMessage < BunnyFarm::Message
137
+ actions :generate, :email, :archive
138
+
139
+ def generate
140
+ # Generate report
141
+ @report_data = create_report
142
+ success!
143
+ end
144
+
145
+ def email
146
+ # Email the report
147
+ send_report_email(@report_data)
148
+ success!
149
+ end
150
+ end
151
+
152
+ # Usage
153
+ report = ReportMessage.new
154
+ report[:report_type] = 'monthly_sales'
155
+ report.publish('generate') # Execute generate command
156
+ ```
157
+
158
+ ### State Machine Pattern
159
+ Messages can represent state transitions:
160
+
161
+ ```ruby
162
+ class OrderMessage < BunnyFarm::Message
163
+ actions :place_order, :confirm_payment, :ship_order, :complete_order
164
+
165
+ def place_order
166
+ @items[:status] = 'pending'
167
+ validate_order
168
+ success!
169
+ end
170
+
171
+ def confirm_payment
172
+ return failure("Order not pending") unless @items[:status] == 'pending'
173
+
174
+ @items[:status] = 'confirmed'
175
+ process_payment
176
+ success!
177
+ end
178
+ end
179
+ ```
180
+
181
+ ### Template Method Pattern
182
+ Define common workflow structure:
183
+
184
+ ```ruby
185
+ class ProcessingMessage < BunnyFarm::Message
186
+ def process
187
+ validate_input
188
+ return unless successful?
189
+
190
+ perform_work
191
+ return unless successful?
192
+
193
+ finalize_result
194
+ end
195
+
196
+ private
197
+
198
+ # Subclasses override these methods
199
+ def validate_input; raise NotImplementedError; end
200
+ def perform_work; raise NotImplementedError; end
201
+ def finalize_result; success!; end
202
+ end
203
+
204
+ class OrderProcessingMessage < ProcessingMessage
205
+ def validate_input
206
+ failure("Invalid order") unless valid_order?
207
+ end
208
+
209
+ def perform_work
210
+ charge_payment
211
+ update_inventory
212
+ end
213
+ end
214
+ ```
215
+
216
+ ## Message Lifecycle
217
+
218
+ Understanding the message lifecycle helps design better message classes:
219
+
220
+ ### 1. Creation
221
+ ```ruby
222
+ message = OrderMessage.new
223
+ message[:order_id] = 12345
224
+ message[:customer_email] = 'customer@example.com'
225
+ ```
226
+
227
+ ### 2. Publishing
228
+ ```ruby
229
+ message.publish('validate') # Routing key: OrderMessage.validate
230
+ ```
231
+
232
+ ### 3. Consumption
233
+ ```ruby
234
+ # Consumer receives message and calls validate method
235
+ def validate
236
+ # Business logic
237
+ success!
238
+ successful? # Returns true for ACK
239
+ end
240
+ ```
241
+
242
+ ### 4. Acknowledgment
243
+ - `true` return → Message acknowledged (ACK)
244
+ - `false` return → Message rejected (NACK)
245
+
246
+ ## Best Practices
247
+
248
+ ### 1. Single Responsibility
249
+ Each message class should handle one domain:
250
+
251
+ ```ruby
252
+ # Good: Focused on orders
253
+ class OrderMessage < BunnyFarm::Message
254
+ actions :validate, :process, :ship
255
+ end
256
+
257
+ # Avoid: Too broad
258
+ class EverythingMessage < BunnyFarm::Message
259
+ actions :process_order, :send_email, :update_inventory, :generate_report
260
+ end
261
+ ```
262
+
263
+ ### 2. Clear Action Names
264
+ Use descriptive, verb-based action names:
265
+
266
+ ```ruby
267
+ # Good: Clear intent
268
+ actions :validate_order, :process_payment, :ship_order, :send_confirmation
269
+
270
+ # Avoid: Vague names
271
+ actions :do_stuff, :handle, :process
272
+ ```
273
+
274
+ ### 3. Proper Error Handling
275
+ Always handle errors gracefully:
276
+
277
+ ```ruby
278
+ def process_payment
279
+ return failure("No payment info") unless payment_present?
280
+
281
+ begin
282
+ result = payment_gateway.charge(@items[:amount])
283
+
284
+ if result.success?
285
+ success!
286
+ else
287
+ failure("Payment failed: #{result.error_message}")
288
+ end
289
+ rescue PaymentGatewayError => e
290
+ failure("Gateway error: #{e.message}")
291
+ end
292
+
293
+ successful?
294
+ end
295
+ ```
296
+
297
+ ### 4. Idempotent Operations
298
+ Make operations safe to retry:
299
+
300
+ ```ruby
301
+ def charge_payment
302
+ # Check if already processed
303
+ return success! if payment_already_charged?
304
+
305
+ # Process only if not done
306
+ result = charge_customer(@items[:amount])
307
+ result.success? ? success! : failure(result.error)
308
+
309
+ successful?
310
+ end
311
+
312
+ private
313
+
314
+ def payment_already_charged?
315
+ PaymentRecord.exists?(order_id: @items[:order_id])
316
+ end
317
+ ```
318
+
319
+ ### 5. Meaningful Field Structures
320
+ Design clear, hierarchical data structures:
321
+
322
+ ```ruby
323
+ # Good: Clear hierarchy
324
+ fields :order_id, :total_amount,
325
+ { customer: [:name, :email, :phone] },
326
+ { billing_address: [:street, :city, :state, :zip] },
327
+ { items: [:product_id, :quantity, :unit_price] }
328
+
329
+ # Avoid: Flat structure
330
+ fields :order_id, :customer_name, :customer_email, :customer_phone,
331
+ :billing_street, :billing_city, :billing_state, :billing_zip
332
+ ```
333
+
334
+ ## Advanced Patterns
335
+
336
+ ### Message Inheritance
337
+ Create base classes for common functionality:
338
+
339
+ ```ruby
340
+ class BaseProcessingMessage < BunnyFarm::Message
341
+ def process
342
+ start_processing
343
+ perform_work
344
+ complete_processing
345
+ end
346
+
347
+ private
348
+
349
+ def start_processing
350
+ @items[:started_at] = Time.current
351
+ end
352
+
353
+ def complete_processing
354
+ @items[:completed_at] = Time.current
355
+ success!
356
+ end
357
+
358
+ def perform_work
359
+ raise NotImplementedError, "Subclass must implement perform_work"
360
+ end
361
+ end
362
+
363
+ class OrderProcessingMessage < BaseProcessingMessage
364
+ fields :order_id, :customer_id
365
+ actions :process
366
+
367
+ private
368
+
369
+ def perform_work
370
+ validate_order
371
+ charge_payment
372
+ update_inventory
373
+ end
374
+ end
375
+ ```
376
+
377
+ ### Message Composition
378
+ Compose complex operations from simpler ones:
379
+
380
+ ```ruby
381
+ class OrderWorkflowMessage < BunnyFarm::Message
382
+ actions :start_workflow
383
+
384
+ def start_workflow
385
+ # Chain multiple message types
386
+ validation_msg = OrderValidationMessage.new(@items)
387
+ validation_msg.publish('validate')
388
+
389
+ payment_msg = PaymentMessage.new(@items)
390
+ payment_msg.publish('charge')
391
+
392
+ shipping_msg = ShippingMessage.new(@items)
393
+ shipping_msg.publish('create_label')
394
+
395
+ success!
396
+ end
397
+ end
398
+ ```
399
+
400
+ ## Next Steps
401
+
402
+ Now that you understand message-centric design:
403
+
404
+ - **[Smart Routing](smart-routing.md)** - How messages find their destination
405
+ - **[JSON Serialization](json-serialization.md)** - Data format and serialization
406
+ - **[Message Structure](../message-structure/overview.md)** - Deep dive into implementation