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,545 @@
1
+ # JSON Serialization
2
+
3
+ BunnyFarm uses JSON as its message serialization format, providing human-readable, language-agnostic message passing that's easy to debug and integrate with other systems.
4
+
5
+ ## Why JSON?
6
+
7
+ ### Human Readable
8
+ JSON messages are easy to read and debug:
9
+
10
+ ```json
11
+ {
12
+ "order_id": 12345,
13
+ "customer": {
14
+ "name": "John Doe",
15
+ "email": "john@example.com"
16
+ },
17
+ "items": [
18
+ {
19
+ "product_id": 1,
20
+ "quantity": 2,
21
+ "price": 29.99
22
+ }
23
+ ],
24
+ "total": 59.98,
25
+ "timestamp": "2024-01-15T10:30:00Z"
26
+ }
27
+ ```
28
+
29
+ ### Language Agnostic
30
+ Other systems can easily produce and consume messages:
31
+
32
+ ```python
33
+ # Python producer
34
+ import json
35
+ import pika
36
+
37
+ message = {
38
+ "order_id": 12345,
39
+ "customer": {"name": "John", "email": "john@example.com"},
40
+ "total": 59.98
41
+ }
42
+
43
+ channel.basic_publish(
44
+ exchange='bunny_farm_exchange',
45
+ routing_key='OrderMessage.process',
46
+ body=json.dumps(message)
47
+ )
48
+ ```
49
+
50
+ ### Tooling Support
51
+ Rich ecosystem of JSON tools for debugging and monitoring.
52
+
53
+ ## Serialization Process
54
+
55
+ ### Publishing Flow
56
+
57
+ ```ruby
58
+ class OrderMessage < BunnyFarm::Message
59
+ fields :order_id, :customer, :items
60
+ end
61
+
62
+ # 1. Create message
63
+ message = OrderMessage.new
64
+ message[:order_id] = 12345
65
+ message[:customer] = { name: "John", email: "john@example.com" }
66
+
67
+ # 2. Publish - automatic serialization
68
+ message.publish('process')
69
+ ```
70
+
71
+ **Internal process:**
72
+ 1. Message data collected from `@items` hash
73
+ 2. Data serialized to JSON string
74
+ 3. JSON sent to RabbitMQ as message body
75
+ 4. Routing key: `OrderMessage.process`
76
+
77
+ ### Consumption Flow
78
+
79
+ ```ruby
80
+ # Consumer receives JSON message body and routing key
81
+ # BunnyFarm automatically:
82
+ # 1. Parses routing key → OrderMessage.process
83
+ # 2. Deserializes JSON to Ruby hash
84
+ # 3. Creates OrderMessage instance
85
+ # 4. Populates @items with deserialized data
86
+ # 5. Calls 'process' method
87
+
88
+ class OrderMessage < BunnyFarm::Message
89
+ def process
90
+ puts @items[:order_id] # 12345
91
+ puts @items[:customer][:name] # "John"
92
+ success!
93
+ end
94
+ end
95
+ ```
96
+
97
+ ## Data Types and Serialization
98
+
99
+ ### Supported Data Types
100
+
101
+ JSON supports these Ruby types natively:
102
+
103
+ ```ruby
104
+ message = OrderMessage.new
105
+
106
+ # String
107
+ message[:customer_name] = "John Doe"
108
+
109
+ # Number (Integer/Float)
110
+ message[:order_id] = 12345
111
+ message[:total] = 59.99
112
+
113
+ # Boolean
114
+ message[:is_priority] = true
115
+ message[:requires_signature] = false
116
+
117
+ # Null
118
+ message[:notes] = nil
119
+
120
+ # Array
121
+ message[:items] = [
122
+ { product_id: 1, quantity: 2 },
123
+ { product_id: 2, quantity: 1 }
124
+ ]
125
+
126
+ # Hash/Object
127
+ message[:customer] = {
128
+ name: "John Doe",
129
+ email: "john@example.com",
130
+ address: {
131
+ street: "123 Main St",
132
+ city: "Boston",
133
+ state: "MA"
134
+ }
135
+ }
136
+ ```
137
+
138
+ ### Serialized JSON Output
139
+
140
+ ```json
141
+ {
142
+ "customer_name": "John Doe",
143
+ "order_id": 12345,
144
+ "total": 59.99,
145
+ "is_priority": true,
146
+ "requires_signature": false,
147
+ "notes": null,
148
+ "items": [
149
+ {"product_id": 1, "quantity": 2},
150
+ {"product_id": 2, "quantity": 1}
151
+ ],
152
+ "customer": {
153
+ "name": "John Doe",
154
+ "email": "john@example.com",
155
+ "address": {
156
+ "street": "123 Main St",
157
+ "city": "Boston",
158
+ "state": "MA"
159
+ }
160
+ }
161
+ }
162
+ ```
163
+
164
+ ## Complex Data Handling
165
+
166
+ ### Date and Time
167
+
168
+ Dates should be serialized as ISO 8601 strings:
169
+
170
+ ```ruby
171
+ class OrderMessage < BunnyFarm::Message
172
+ def set_timestamps
173
+ @items[:created_at] = Time.current.iso8601
174
+ @items[:processed_at] = DateTime.current.iso8601
175
+ end
176
+
177
+ def get_created_time
178
+ Time.parse(@items[:created_at])
179
+ end
180
+ end
181
+
182
+ # JSON output
183
+ {
184
+ "created_at": "2024-01-15T10:30:00Z",
185
+ "processed_at": "2024-01-15T10:30:00+00:00"
186
+ }
187
+ ```
188
+
189
+ ### Binary Data
190
+
191
+ Base64 encode binary data:
192
+
193
+ ```ruby
194
+ class DocumentMessage < BunnyFarm::Message
195
+ def set_file_content(file_path)
196
+ content = File.binread(file_path)
197
+ @items[:file_content] = Base64.encode64(content)
198
+ @items[:filename] = File.basename(file_path)
199
+ end
200
+
201
+ def get_file_content
202
+ Base64.decode64(@items[:file_content])
203
+ end
204
+ end
205
+ ```
206
+
207
+ ### Custom Objects
208
+
209
+ Convert complex objects to simple data structures:
210
+
211
+ ```ruby
212
+ class Customer
213
+ attr_accessor :id, :name, :email, :created_at
214
+
215
+ def to_hash
216
+ {
217
+ id: @id,
218
+ name: @name,
219
+ email: @email,
220
+ created_at: @created_at.iso8601
221
+ }
222
+ end
223
+
224
+ def self.from_hash(data)
225
+ customer = new
226
+ customer.id = data[:id]
227
+ customer.name = data[:name]
228
+ customer.email = data[:email]
229
+ customer.created_at = Time.parse(data[:created_at])
230
+ customer
231
+ end
232
+ end
233
+
234
+ class OrderMessage < BunnyFarm::Message
235
+ def set_customer(customer)
236
+ @items[:customer] = customer.to_hash
237
+ end
238
+
239
+ def get_customer
240
+ Customer.from_hash(@items[:customer])
241
+ end
242
+ end
243
+ ```
244
+
245
+ ## Performance Considerations
246
+
247
+ ### Message Size
248
+
249
+ JSON can become large with complex data:
250
+
251
+ ```ruby
252
+ # Monitor message sizes
253
+ class OrderMessage < BunnyFarm::Message
254
+ def publish(action)
255
+ json_size = to_json.bytesize
256
+ logger.warn "Large message: #{json_size} bytes" if json_size > 10.kilobytes
257
+
258
+ super(action)
259
+ end
260
+ end
261
+ ```
262
+
263
+ ### Compression
264
+
265
+ For large messages, consider compression:
266
+
267
+ ```ruby
268
+ require 'zlib'
269
+
270
+ class LargeDataMessage < BunnyFarm::Message
271
+ def set_compressed_data(data)
272
+ json_data = data.to_json
273
+ compressed = Zlib::Deflate.deflate(json_data)
274
+ @items[:compressed_data] = Base64.encode64(compressed)
275
+ @items[:compression] = 'zlib'
276
+ end
277
+
278
+ def get_decompressed_data
279
+ return @items[:data] unless @items[:compression]
280
+
281
+ compressed = Base64.decode64(@items[:compressed_data])
282
+ json_data = Zlib::Inflate.inflate(compressed)
283
+ JSON.parse(json_data)
284
+ end
285
+ end
286
+ ```
287
+
288
+ ### Parsing Performance
289
+
290
+ JSON parsing can be optimized:
291
+
292
+ ```ruby
293
+ # Use Oj gem for faster JSON parsing
294
+ require 'oj'
295
+
296
+ class FastMessage < BunnyFarm::Message
297
+ def to_json
298
+ Oj.dump(@items, mode: :compat)
299
+ end
300
+
301
+ def self.from_json(json_string)
302
+ data = Oj.load(json_string, mode: :compat)
303
+ message = new
304
+ message.instance_variable_set(:@items, data)
305
+ message
306
+ end
307
+ end
308
+ ```
309
+
310
+ ## Debugging JSON Messages
311
+
312
+ ### Pretty Printing
313
+
314
+ Format JSON for easier reading:
315
+
316
+ ```ruby
317
+ require 'json'
318
+
319
+ class OrderMessage < BunnyFarm::Message
320
+ def pretty_print
321
+ JSON.pretty_generate(@items)
322
+ end
323
+ end
324
+
325
+ puts message.pretty_print
326
+ ```
327
+
328
+ Output:
329
+ ```json
330
+ {
331
+ "order_id": 12345,
332
+ "customer": {
333
+ "name": "John Doe",
334
+ "email": "john@example.com"
335
+ },
336
+ "items": [
337
+ {
338
+ "product_id": 1,
339
+ "quantity": 2
340
+ }
341
+ ]
342
+ }
343
+ ```
344
+
345
+ ### JSON Validation
346
+
347
+ Validate message structure:
348
+
349
+ ```ruby
350
+ require 'json-schema'
351
+
352
+ class ValidatedMessage < BunnyFarm::Message
353
+ SCHEMA = {
354
+ type: 'object',
355
+ required: ['order_id', 'customer'],
356
+ properties: {
357
+ order_id: { type: 'integer' },
358
+ customer: {
359
+ type: 'object',
360
+ required: ['name', 'email'],
361
+ properties: {
362
+ name: { type: 'string' },
363
+ email: { type: 'string', format: 'email' }
364
+ }
365
+ }
366
+ }
367
+ }.freeze
368
+
369
+ def validate_schema
370
+ errors = JSON::Validator.fully_validate(SCHEMA, @items)
371
+ failure("Schema validation failed: #{errors.join(', ')}") unless errors.empty?
372
+ end
373
+ end
374
+ ```
375
+
376
+ ### Message Inspection
377
+
378
+ Inspect messages in RabbitMQ management UI or with tools:
379
+
380
+ ```bash
381
+ # View message in RabbitMQ management interface
382
+ # Messages tab → Get Messages → View JSON payload
383
+
384
+ # Use rabbitmqadmin to inspect messages
385
+ rabbitmqadmin get queue=order_queue requeue=true
386
+
387
+ # Use jq to format JSON in command line
388
+ echo '{"order_id":12345,"customer":{"name":"John"}}' | jq '.'
389
+ ```
390
+
391
+ ## Integration Patterns
392
+
393
+ ### Multi-Language Consumers
394
+
395
+ Other languages can consume BunnyFarm messages:
396
+
397
+ **Python Consumer:**
398
+ ```python
399
+ import json
400
+ import pika
401
+
402
+ def process_order(channel, method, properties, body):
403
+ # Parse BunnyFarm JSON message
404
+ message_data = json.loads(body)
405
+ order_id = message_data['order_id']
406
+ customer = message_data['customer']
407
+
408
+ # Process order
409
+ print(f"Processing order {order_id} for {customer['name']}")
410
+
411
+ # Acknowledge message
412
+ channel.basic_ack(delivery_tag=method.delivery_tag)
413
+
414
+ # Set up consumer
415
+ connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
416
+ channel = connection.channel()
417
+ channel.basic_consume(queue='order_queue', on_message_callback=process_order)
418
+ channel.start_consuming()
419
+ ```
420
+
421
+ **Node.js Consumer:**
422
+ ```javascript
423
+ const amqp = require('amqplib');
424
+
425
+ async function processOrders() {
426
+ const connection = await amqp.connect('amqp://localhost');
427
+ const channel = await connection.createChannel();
428
+
429
+ channel.consume('order_queue', (message) => {
430
+ // Parse BunnyFarm JSON message
431
+ const messageData = JSON.parse(message.content.toString());
432
+ const orderId = messageData.order_id;
433
+ const customer = messageData.customer;
434
+
435
+ console.log(`Processing order ${orderId} for ${customer.name}`);
436
+
437
+ // Acknowledge message
438
+ channel.ack(message);
439
+ });
440
+ }
441
+ ```
442
+
443
+ ### API Gateway Integration
444
+
445
+ Expose message creation via REST API:
446
+
447
+ ```ruby
448
+ class OrdersController < ApplicationController
449
+ def create
450
+ # Create message from API payload
451
+ order_message = OrderMessage.new
452
+ order_message[:order_id] = params[:order_id]
453
+ order_message[:customer] = params[:customer]
454
+ order_message[:items] = params[:items]
455
+
456
+ # Publish for processing
457
+ if order_message.publish('process')
458
+ render json: { status: 'accepted', order_id: params[:order_id] }
459
+ else
460
+ render json: { error: 'Failed to process order' }, status: 500
461
+ end
462
+ end
463
+ end
464
+ ```
465
+
466
+ ## Best Practices
467
+
468
+ ### 1. Keep Messages Focused
469
+
470
+ ```ruby
471
+ # Good: Focused message structure
472
+ class OrderMessage < BunnyFarm::Message
473
+ fields :order_id, :customer_id, :items, :total, :shipping_address
474
+ end
475
+
476
+ # Avoid: Kitchen sink approach
477
+ class EverythingMessage < BunnyFarm::Message
478
+ fields :order_data, :customer_data, :inventory_data, :shipping_data,
479
+ :payment_data, :analytics_data, :audit_data, :metadata
480
+ end
481
+ ```
482
+
483
+ ### 2. Use Consistent Naming
484
+
485
+ ```ruby
486
+ # Good: Consistent snake_case
487
+ {
488
+ "order_id": 12345,
489
+ "customer_email": "john@example.com",
490
+ "created_at": "2024-01-15T10:30:00Z"
491
+ }
492
+
493
+ # Avoid: Mixed naming conventions
494
+ {
495
+ "orderId": 12345, # camelCase
496
+ "customer_email": "john@example.com", # snake_case
497
+ "CreatedAt": "2024-01-15T10:30:00Z" # PascalCase
498
+ }
499
+ ```
500
+
501
+ ### 3. Version Your Message Structure
502
+
503
+ ```ruby
504
+ class OrderMessage < BunnyFarm::Message
505
+ def initialize
506
+ super
507
+ @items[:_version] = '1.0'
508
+ end
509
+
510
+ def process
511
+ case @items[:_version]
512
+ when '1.0'
513
+ process_v1
514
+ when '2.0'
515
+ process_v2
516
+ else
517
+ failure("Unsupported message version: #{@items[:_version]}")
518
+ end
519
+ end
520
+ end
521
+ ```
522
+
523
+ ### 4. Handle Missing Fields Gracefully
524
+
525
+ ```ruby
526
+ def process
527
+ order_id = @items[:order_id]
528
+ return failure("Order ID required") unless order_id
529
+
530
+ customer_email = @items.dig(:customer, :email)
531
+ return failure("Customer email required") unless customer_email
532
+
533
+ # Process with validated data
534
+ success!
535
+ end
536
+ ```
537
+
538
+ ## Next Steps
539
+
540
+ With JSON serialization mastered:
541
+
542
+ - **[Configure message formats](../configuration/overview.md)** for your environment
543
+ - **[Design message structures](../message-structure/overview.md)** for optimal serialization
544
+ - **[Handle errors](error-handling.md)** in serialization and deserialization
545
+ - **[Integrate with other systems](../architecture/integration.md)** using JSON