fractor 0.1.6 → 0.1.7

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 (172) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +227 -102
  3. data/README.adoc +113 -1940
  4. data/docs/.lycheeignore +16 -0
  5. data/docs/Gemfile +24 -0
  6. data/docs/README.md +157 -0
  7. data/docs/_config.yml +151 -0
  8. data/docs/_features/error-handling.adoc +1192 -0
  9. data/docs/_features/index.adoc +80 -0
  10. data/docs/_features/monitoring.adoc +589 -0
  11. data/docs/_features/signal-handling.adoc +202 -0
  12. data/docs/_features/workflows.adoc +1235 -0
  13. data/docs/_guides/continuous-mode.adoc +736 -0
  14. data/docs/_guides/cookbook.adoc +1133 -0
  15. data/docs/_guides/index.adoc +55 -0
  16. data/docs/_guides/pipeline-mode.adoc +730 -0
  17. data/docs/_guides/troubleshooting.adoc +358 -0
  18. data/docs/_pages/architecture.adoc +1390 -0
  19. data/docs/_pages/core-concepts.adoc +1392 -0
  20. data/docs/_pages/design-principles.adoc +862 -0
  21. data/docs/_pages/getting-started.adoc +290 -0
  22. data/docs/_pages/installation.adoc +143 -0
  23. data/docs/_reference/api.adoc +1080 -0
  24. data/docs/_reference/error-reporting.adoc +670 -0
  25. data/docs/_reference/examples.adoc +181 -0
  26. data/docs/_reference/index.adoc +96 -0
  27. data/docs/_reference/troubleshooting.adoc +862 -0
  28. data/docs/_tutorials/complex-workflows.adoc +1022 -0
  29. data/docs/_tutorials/data-processing-pipeline.adoc +740 -0
  30. data/docs/_tutorials/first-application.adoc +384 -0
  31. data/docs/_tutorials/index.adoc +48 -0
  32. data/docs/_tutorials/long-running-services.adoc +931 -0
  33. data/docs/assets/images/favicon-16.png +0 -0
  34. data/docs/assets/images/favicon-32.png +0 -0
  35. data/docs/assets/images/favicon-48.png +0 -0
  36. data/docs/assets/images/favicon.ico +0 -0
  37. data/docs/assets/images/favicon.png +0 -0
  38. data/docs/assets/images/favicon.svg +45 -0
  39. data/docs/assets/images/fractor-icon.svg +49 -0
  40. data/docs/assets/images/fractor-logo.svg +61 -0
  41. data/docs/index.adoc +131 -0
  42. data/docs/lychee.toml +39 -0
  43. data/examples/api_aggregator/README.adoc +627 -0
  44. data/examples/api_aggregator/api_aggregator.rb +376 -0
  45. data/examples/auto_detection/README.adoc +407 -29
  46. data/examples/continuous_chat_common/message_protocol.rb +1 -1
  47. data/examples/error_reporting.rb +207 -0
  48. data/examples/file_processor/README.adoc +170 -0
  49. data/examples/file_processor/file_processor.rb +615 -0
  50. data/examples/file_processor/sample_files/invalid.csv +1 -0
  51. data/examples/file_processor/sample_files/orders.xml +24 -0
  52. data/examples/file_processor/sample_files/products.json +23 -0
  53. data/examples/file_processor/sample_files/users.csv +6 -0
  54. data/examples/hierarchical_hasher/README.adoc +629 -41
  55. data/examples/image_processor/README.adoc +610 -0
  56. data/examples/image_processor/image_processor.rb +349 -0
  57. data/examples/image_processor/processed_images/sample_10_processed.jpg.json +12 -0
  58. data/examples/image_processor/processed_images/sample_1_processed.jpg.json +12 -0
  59. data/examples/image_processor/processed_images/sample_2_processed.jpg.json +12 -0
  60. data/examples/image_processor/processed_images/sample_3_processed.jpg.json +12 -0
  61. data/examples/image_processor/processed_images/sample_4_processed.jpg.json +12 -0
  62. data/examples/image_processor/processed_images/sample_5_processed.jpg.json +12 -0
  63. data/examples/image_processor/processed_images/sample_6_processed.jpg.json +12 -0
  64. data/examples/image_processor/processed_images/sample_7_processed.jpg.json +12 -0
  65. data/examples/image_processor/processed_images/sample_8_processed.jpg.json +12 -0
  66. data/examples/image_processor/processed_images/sample_9_processed.jpg.json +12 -0
  67. data/examples/image_processor/test_images/sample_1.png +1 -0
  68. data/examples/image_processor/test_images/sample_10.png +1 -0
  69. data/examples/image_processor/test_images/sample_2.png +1 -0
  70. data/examples/image_processor/test_images/sample_3.png +1 -0
  71. data/examples/image_processor/test_images/sample_4.png +1 -0
  72. data/examples/image_processor/test_images/sample_5.png +1 -0
  73. data/examples/image_processor/test_images/sample_6.png +1 -0
  74. data/examples/image_processor/test_images/sample_7.png +1 -0
  75. data/examples/image_processor/test_images/sample_8.png +1 -0
  76. data/examples/image_processor/test_images/sample_9.png +1 -0
  77. data/examples/log_analyzer/README.adoc +662 -0
  78. data/examples/log_analyzer/log_analyzer.rb +579 -0
  79. data/examples/log_analyzer/sample_logs/apache.log +20 -0
  80. data/examples/log_analyzer/sample_logs/json.log +15 -0
  81. data/examples/log_analyzer/sample_logs/nginx.log +15 -0
  82. data/examples/log_analyzer/sample_logs/rails.log +29 -0
  83. data/examples/multi_work_type/README.adoc +576 -26
  84. data/examples/performance_monitoring.rb +120 -0
  85. data/examples/pipeline_processing/README.adoc +740 -26
  86. data/examples/pipeline_processing/pipeline_processing.rb +2 -2
  87. data/examples/priority_work_example.rb +155 -0
  88. data/examples/producer_subscriber/README.adoc +889 -46
  89. data/examples/scatter_gather/README.adoc +829 -27
  90. data/examples/simple/README.adoc +347 -0
  91. data/examples/specialized_workers/README.adoc +622 -26
  92. data/examples/specialized_workers/specialized_workers.rb +44 -8
  93. data/examples/stream_processor/README.adoc +206 -0
  94. data/examples/stream_processor/stream_processor.rb +284 -0
  95. data/examples/web_scraper/README.adoc +625 -0
  96. data/examples/web_scraper/web_scraper.rb +285 -0
  97. data/examples/workflow/README.adoc +406 -0
  98. data/examples/workflow/circuit_breaker/README.adoc +360 -0
  99. data/examples/workflow/circuit_breaker/circuit_breaker_workflow.rb +225 -0
  100. data/examples/workflow/conditional/README.adoc +483 -0
  101. data/examples/workflow/conditional/conditional_workflow.rb +215 -0
  102. data/examples/workflow/dead_letter_queue/README.adoc +374 -0
  103. data/examples/workflow/dead_letter_queue/dead_letter_queue_workflow.rb +217 -0
  104. data/examples/workflow/fan_out/README.adoc +381 -0
  105. data/examples/workflow/fan_out/fan_out_workflow.rb +202 -0
  106. data/examples/workflow/retry/README.adoc +248 -0
  107. data/examples/workflow/retry/retry_workflow.rb +195 -0
  108. data/examples/workflow/simple_linear/README.adoc +267 -0
  109. data/examples/workflow/simple_linear/simple_linear_workflow.rb +175 -0
  110. data/examples/workflow/simplified/README.adoc +329 -0
  111. data/examples/workflow/simplified/simplified_workflow.rb +222 -0
  112. data/exe/fractor +10 -0
  113. data/lib/fractor/cli.rb +288 -0
  114. data/lib/fractor/configuration.rb +307 -0
  115. data/lib/fractor/continuous_server.rb +60 -65
  116. data/lib/fractor/error_formatter.rb +72 -0
  117. data/lib/fractor/error_report_generator.rb +152 -0
  118. data/lib/fractor/error_reporter.rb +244 -0
  119. data/lib/fractor/error_statistics.rb +147 -0
  120. data/lib/fractor/execution_tracer.rb +162 -0
  121. data/lib/fractor/logger.rb +230 -0
  122. data/lib/fractor/main_loop_handler.rb +406 -0
  123. data/lib/fractor/main_loop_handler3.rb +135 -0
  124. data/lib/fractor/main_loop_handler4.rb +299 -0
  125. data/lib/fractor/performance_metrics_collector.rb +181 -0
  126. data/lib/fractor/performance_monitor.rb +215 -0
  127. data/lib/fractor/performance_report_generator.rb +202 -0
  128. data/lib/fractor/priority_work.rb +93 -0
  129. data/lib/fractor/priority_work_queue.rb +189 -0
  130. data/lib/fractor/result_aggregator.rb +32 -0
  131. data/lib/fractor/shutdown_handler.rb +168 -0
  132. data/lib/fractor/signal_handler.rb +80 -0
  133. data/lib/fractor/supervisor.rb +382 -269
  134. data/lib/fractor/supervisor_logger.rb +88 -0
  135. data/lib/fractor/version.rb +1 -1
  136. data/lib/fractor/work.rb +12 -0
  137. data/lib/fractor/work_distribution_manager.rb +151 -0
  138. data/lib/fractor/work_queue.rb +20 -0
  139. data/lib/fractor/work_result.rb +181 -9
  140. data/lib/fractor/worker.rb +73 -0
  141. data/lib/fractor/workflow/builder.rb +210 -0
  142. data/lib/fractor/workflow/chain_builder.rb +169 -0
  143. data/lib/fractor/workflow/circuit_breaker.rb +183 -0
  144. data/lib/fractor/workflow/circuit_breaker_orchestrator.rb +208 -0
  145. data/lib/fractor/workflow/circuit_breaker_registry.rb +112 -0
  146. data/lib/fractor/workflow/dead_letter_queue.rb +334 -0
  147. data/lib/fractor/workflow/execution_hooks.rb +39 -0
  148. data/lib/fractor/workflow/execution_strategy.rb +225 -0
  149. data/lib/fractor/workflow/execution_trace.rb +134 -0
  150. data/lib/fractor/workflow/helpers.rb +191 -0
  151. data/lib/fractor/workflow/job.rb +290 -0
  152. data/lib/fractor/workflow/job_dependency_validator.rb +120 -0
  153. data/lib/fractor/workflow/logger.rb +110 -0
  154. data/lib/fractor/workflow/pre_execution_context.rb +193 -0
  155. data/lib/fractor/workflow/retry_config.rb +156 -0
  156. data/lib/fractor/workflow/retry_orchestrator.rb +184 -0
  157. data/lib/fractor/workflow/retry_strategy.rb +93 -0
  158. data/lib/fractor/workflow/structured_logger.rb +30 -0
  159. data/lib/fractor/workflow/type_compatibility_validator.rb +222 -0
  160. data/lib/fractor/workflow/visualizer.rb +211 -0
  161. data/lib/fractor/workflow/workflow_context.rb +132 -0
  162. data/lib/fractor/workflow/workflow_executor.rb +669 -0
  163. data/lib/fractor/workflow/workflow_result.rb +55 -0
  164. data/lib/fractor/workflow/workflow_validator.rb +295 -0
  165. data/lib/fractor/workflow.rb +333 -0
  166. data/lib/fractor/wrapped_ractor.rb +66 -101
  167. data/lib/fractor/wrapped_ractor3.rb +161 -0
  168. data/lib/fractor/wrapped_ractor4.rb +242 -0
  169. data/lib/fractor.rb +92 -4
  170. metadata +179 -6
  171. data/tests/sample.rb.bak +0 -309
  172. data/tests/sample_working.rb.bak +0 -209
@@ -0,0 +1,1080 @@
1
+ ---
2
+ layout: default
3
+ title: API Reference
4
+ nav_order: 2
5
+ ---
6
+ = API Reference
7
+
8
+ This document provides a comprehensive reference for the Fractor API, including all public classes, methods, and their usage.
9
+
10
+ == Core Classes
11
+
12
+ === Fractor::Work
13
+
14
+ Represents a unit of work to be processed by workers.
15
+
16
+ ==== Class Methods
17
+
18
+ ===== `new(payload)`
19
+
20
+ Creates a new Work instance.
21
+
22
+ [cols="1,1,3"]
23
+ |===
24
+ |Parameter |Type |Description
25
+
26
+ |`payload`
27
+ |Hash or Any
28
+ |The data to be processed by the worker
29
+ |===
30
+
31
+ **Example:**
32
+
33
+ [source,ruby]
34
+ ----
35
+ work = Fractor::Work.new(value: 42, operation: :double)
36
+ ----
37
+
38
+ ==== Instance Methods
39
+
40
+ ===== `input`
41
+
42
+ Returns the work payload.
43
+
44
+ **Returns:** The payload passed during initialization
45
+
46
+ **Example:**
47
+
48
+ [source,ruby]
49
+ ----
50
+ work = Fractor::Work.new(value: 42)
51
+ work.input # => { value: 42 }
52
+ ----
53
+
54
+ === Fractor::Worker
55
+
56
+ Base class for all workers. Workers process Work objects and return WorkResult objects.
57
+
58
+ ==== Class Methods
59
+
60
+ ===== `perform(work)`
61
+
62
+ Main entry point for processing work. Handles error catching and result wrapping.
63
+
64
+ [cols="1,1,3"]
65
+ |===
66
+ |Parameter |Type |Description
67
+
68
+ |`work`
69
+ |Fractor::Work
70
+ |The work item to process
71
+ |===
72
+
73
+ **Returns:** Fractor::WorkResult
74
+
75
+ **Example:**
76
+
77
+ [source,ruby]
78
+ ----
79
+ class DoubleWorker < Fractor::Worker
80
+ def process(work)
81
+ result = work.input[:value] * 2
82
+ Fractor::WorkResult.new(result: result, work: work)
83
+ end
84
+ end
85
+
86
+ work = Fractor::Work.new(value: 21)
87
+ result = DoubleWorker.perform(work)
88
+ result.result # => 42
89
+ ----
90
+
91
+ ==== Instance Methods
92
+
93
+ ===== `process(work)` (abstract)
94
+
95
+ Process the work and return a result. Must be implemented by subclasses.
96
+
97
+ [cols="1,1,3"]
98
+ |===
99
+ |Parameter |Type |Description
100
+
101
+ |`work`
102
+ |Fractor::Work
103
+ |The work item to process
104
+ |===
105
+
106
+ **Returns:** Fractor::WorkResult
107
+
108
+ **Raises:** NotImplementedError if not overridden
109
+
110
+ **Example:**
111
+
112
+ [source,ruby]
113
+ ----
114
+ class CustomWorker < Fractor::Worker
115
+ def process(work)
116
+ # Your processing logic here
117
+ result = perform_computation(work.input)
118
+ Fractor::WorkResult.new(result: result, work: work)
119
+ end
120
+ end
121
+ ----
122
+
123
+ === Fractor::WorkResult
124
+
125
+ Encapsulates the result of work processing, including success/failure status and error information.
126
+
127
+ ==== Class Methods
128
+
129
+ ===== `new(result: nil, error: nil, work: nil, error_code: nil, error_context: {})`
130
+
131
+ Creates a new WorkResult instance.
132
+
133
+ [cols="1,1,3"]
134
+ |===
135
+ |Parameter |Type |Description
136
+
137
+ |`result`
138
+ |Any
139
+ |The successful result value (optional)
140
+
141
+ |`error`
142
+ |String or Exception
143
+ |Error message or exception (optional)
144
+
145
+ |`work`
146
+ |Fractor::Work
147
+ |The original work item (optional)
148
+
149
+ |`error_code`
150
+ |Symbol
151
+ |Categorized error code (optional)
152
+
153
+ |`error_context`
154
+ |Hash
155
+ |Additional error context (optional)
156
+ |===
157
+
158
+ **Example:**
159
+
160
+ [source,ruby]
161
+ ----
162
+ # Success result
163
+ Fractor::WorkResult.new(
164
+ result: { status: "completed" },
165
+ work: work
166
+ )
167
+
168
+ # Error result with context
169
+ Fractor::WorkResult.new(
170
+ error: "Connection timeout",
171
+ error_code: :timeout,
172
+ error_context: {
173
+ endpoint: "https://api.example.com",
174
+ attempt: 3,
175
+ duration: 30.5
176
+ },
177
+ work: work
178
+ )
179
+ ----
180
+
181
+ ==== Instance Methods
182
+
183
+ ===== `success?`
184
+
185
+ Returns whether the work completed successfully.
186
+
187
+ **Returns:** Boolean
188
+
189
+ **Example:**
190
+
191
+ [source,ruby]
192
+ ----
193
+ result.success? # => true or false
194
+ ----
195
+
196
+ ===== `error?`
197
+
198
+ Returns whether the work encountered an error.
199
+
200
+ **Returns:** Boolean
201
+
202
+ **Example:**
203
+
204
+ [source,ruby]
205
+ ----
206
+ result.error? # => true or false
207
+ ----
208
+
209
+ ===== `result`
210
+
211
+ Returns the result value.
212
+
213
+ **Returns:** The result value or nil
214
+
215
+ ===== `error`
216
+
217
+ Returns the error message or exception.
218
+
219
+ **Returns:** String, Exception, or nil
220
+
221
+ ===== `work`
222
+
223
+ Returns the original work item.
224
+
225
+ **Returns:** Fractor::Work or nil
226
+
227
+ ===== `error_code`
228
+
229
+ Returns the categorized error code.
230
+
231
+ **Returns:** Symbol or nil
232
+
233
+ ===== `error_context`
234
+
235
+ Returns additional error context.
236
+
237
+ **Returns:** Hash
238
+
239
+ === Fractor::Supervisor
240
+
241
+ Manages worker pools and distributes work across workers.
242
+
243
+ ==== Class Methods
244
+
245
+ ===== `new(worker_pools: [], work_queue: nil, max_queue_size: nil)`
246
+
247
+ Creates a new Supervisor instance.
248
+
249
+ [cols="1,1,3"]
250
+ |===
251
+ |Parameter |Type |Description
252
+
253
+ |`worker_pools`
254
+ |Array<Hash>
255
+ |Array of worker pool configurations
256
+
257
+ |`work_queue`
258
+ |Fractor::WorkQueue
259
+ |Custom work queue (optional)
260
+
261
+ |`max_queue_size`
262
+ |Integer
263
+ |Maximum queue size (optional)
264
+ |===
265
+
266
+ **Worker Pool Configuration:**
267
+
268
+ [cols="1,1,3"]
269
+ |===
270
+ |Key |Type |Description
271
+
272
+ |`worker_class`
273
+ |Class
274
+ |The worker class to instantiate
275
+
276
+ |`num_workers`
277
+ |Integer
278
+ |Number of workers in the pool (default: 1)
279
+ |===
280
+
281
+ **Example:**
282
+
283
+ [source,ruby]
284
+ ----
285
+ supervisor = Fractor::Supervisor.new(
286
+ worker_pools: [
287
+ { worker_class: FastWorker, num_workers: 4 },
288
+ { worker_class: SlowWorker, num_workers: 2 }
289
+ ],
290
+ max_queue_size: 1000
291
+ )
292
+ ----
293
+
294
+ ==== Instance Methods
295
+
296
+ ===== `add_work(work)`
297
+
298
+ Adds a single work item to the queue.
299
+
300
+ [cols="1,1,3"]
301
+ |===
302
+ |Parameter |Type |Description
303
+
304
+ |`work`
305
+ |Fractor::Work
306
+ |Work item to add
307
+ |===
308
+
309
+ **Example:**
310
+
311
+ [source,ruby]
312
+ ----
313
+ supervisor.add_work(Fractor::Work.new(value: 42))
314
+ ----
315
+
316
+ ===== `add_work_items(work_items)`
317
+
318
+ Adds multiple work items to the queue.
319
+
320
+ [cols="1,1,3"]
321
+ |===
322
+ |Parameter |Type |Description
323
+
324
+ |`work_items`
325
+ |Array<Fractor::Work>
326
+ |Array of work items to add
327
+ |===
328
+
329
+ **Example:**
330
+
331
+ [source,ruby]
332
+ ----
333
+ items = (1..100).map { |i| Fractor::Work.new(value: i) }
334
+ supervisor.add_work_items(items)
335
+ ----
336
+
337
+ ===== `run`
338
+
339
+ Starts processing work. Blocks until all work is complete.
340
+
341
+ **Example:**
342
+
343
+ [source,ruby]
344
+ ----
345
+ supervisor.add_work_items(work_items)
346
+ supervisor.run
347
+ puts "All work completed!"
348
+ ----
349
+
350
+ ===== `stop`
351
+
352
+ Stops the supervisor and all workers gracefully.
353
+
354
+ **Example:**
355
+
356
+ [source,ruby]
357
+ ----
358
+ supervisor.stop
359
+ ----
360
+
361
+ ===== `results`
362
+
363
+ Returns the result aggregator containing all work results.
364
+
365
+ **Returns:** Fractor::ResultAggregator
366
+
367
+ **Example:**
368
+
369
+ [source,ruby]
370
+ ----
371
+ supervisor.run
372
+ aggregator = supervisor.results
373
+ puts "Success: #{aggregator.results.size}"
374
+ puts "Errors: #{aggregator.errors.size}"
375
+ ----
376
+
377
+ === Fractor::WorkQueue
378
+
379
+ Thread-safe queue for managing work items.
380
+
381
+ ==== Class Methods
382
+
383
+ ===== `new(max_size: nil)`
384
+
385
+ Creates a new WorkQueue instance.
386
+
387
+ [cols="1,1,3"]
388
+ |===
389
+ |Parameter |Type |Description
390
+
391
+ |`max_size`
392
+ |Integer
393
+ |Maximum queue size (optional, unlimited by default)
394
+ |===
395
+
396
+ **Example:**
397
+
398
+ [source,ruby]
399
+ ----
400
+ queue = Fractor::WorkQueue.new(max_size: 100)
401
+ ----
402
+
403
+ ==== Instance Methods
404
+
405
+ ===== `<<(work)` or `push(work)`
406
+
407
+ Adds work to the queue.
408
+
409
+ [cols="1,1,3"]
410
+ |===
411
+ |Parameter |Type |Description
412
+
413
+ |`work`
414
+ |Fractor::Work
415
+ |Work item to add
416
+ |===
417
+
418
+ **Example:**
419
+
420
+ [source,ruby]
421
+ ----
422
+ queue << Fractor::Work.new(value: 42)
423
+ queue.push(Fractor::Work.new(value: 43))
424
+ ----
425
+
426
+ ===== `pop`
427
+
428
+ Retrieves and removes the next work item from the queue. Blocks if queue is empty.
429
+
430
+ **Returns:** Fractor::Work
431
+
432
+ **Example:**
433
+
434
+ [source,ruby]
435
+ ----
436
+ work = queue.pop
437
+ ----
438
+
439
+ ===== `size`
440
+
441
+ Returns the current number of items in the queue.
442
+
443
+ **Returns:** Integer
444
+
445
+ **Example:**
446
+
447
+ [source,ruby]
448
+ ----
449
+ queue.size # => 5
450
+ ----
451
+
452
+ ===== `empty?`
453
+
454
+ Returns whether the queue is empty.
455
+
456
+ **Returns:** Boolean
457
+
458
+ **Example:**
459
+
460
+ [source,ruby]
461
+ ----
462
+ queue.empty? # => false
463
+ ----
464
+
465
+ === Fractor::ResultAggregator
466
+
467
+ Collects and organizes work results.
468
+
469
+ ==== Instance Methods
470
+
471
+ ===== `add_result(result)`
472
+
473
+ Adds a work result.
474
+
475
+ [cols="1,1,3"]
476
+ |===
477
+ |Parameter |Type |Description
478
+
479
+ |`result`
480
+ |Fractor::WorkResult
481
+ |Result to add
482
+ |===
483
+
484
+ ===== `results`
485
+
486
+ Returns all successful results.
487
+
488
+ **Returns:** Array<Fractor::WorkResult>
489
+
490
+ **Example:**
491
+
492
+ [source,ruby]
493
+ ----
494
+ aggregator.results.each do |result|
495
+ puts result.result
496
+ end
497
+ ----
498
+
499
+ ===== `errors`
500
+
501
+ Returns all error results.
502
+
503
+ **Returns:** Array<Fractor::WorkResult>
504
+
505
+ **Example:**
506
+
507
+ [source,ruby]
508
+ ----
509
+ aggregator.errors.each do |result|
510
+ puts "Error: #{result.error}"
511
+ end
512
+ ----
513
+
514
+ ===== `all`
515
+
516
+ Returns all results (both successful and failed).
517
+
518
+ **Returns:** Array<Fractor::WorkResult>
519
+
520
+ === Fractor::PerformanceMonitor
521
+
522
+ Monitors and tracks performance metrics for supervisors and workers.
523
+
524
+ ==== Class Methods
525
+
526
+ ===== `new(supervisor, sample_interval: 1.0)`
527
+
528
+ Creates a new PerformanceMonitor instance.
529
+
530
+ [cols="1,1,3"]
531
+ |===
532
+ |Parameter |Type |Description
533
+
534
+ |`supervisor`
535
+ |Fractor::Supervisor
536
+ |The supervisor to monitor
537
+
538
+ |`sample_interval`
539
+ |Float
540
+ |Sampling interval in seconds (default: 1.0)
541
+ |===
542
+
543
+ **Example:**
544
+
545
+ [source,ruby]
546
+ ----
547
+ monitor = Fractor::PerformanceMonitor.new(
548
+ supervisor,
549
+ sample_interval: 0.5
550
+ )
551
+ ----
552
+
553
+ ==== Instance Methods
554
+
555
+ ===== `start`
556
+
557
+ Starts monitoring in a background thread.
558
+
559
+ **Example:**
560
+
561
+ [source,ruby]
562
+ ----
563
+ monitor.start
564
+ ----
565
+
566
+ ===== `stop`
567
+
568
+ Stops monitoring and waits for background thread to finish.
569
+
570
+ **Example:**
571
+
572
+ [source,ruby]
573
+ ----
574
+ monitor.stop
575
+ ----
576
+
577
+ ===== `snapshot`
578
+
579
+ Returns current metrics snapshot.
580
+
581
+ **Returns:** Hash containing all current metrics
582
+
583
+ **Example:**
584
+
585
+ [source,ruby]
586
+ ----
587
+ stats = monitor.snapshot
588
+ puts "Jobs processed: #{stats[:jobs_processed]}"
589
+ puts "Throughput: #{stats[:throughput]} jobs/sec"
590
+ puts "Queue depth: #{stats[:queue_depth]}"
591
+ ----
592
+
593
+ ===== `report`
594
+
595
+ Generates a human-readable performance report.
596
+
597
+ **Returns:** String
598
+
599
+ **Example:**
600
+
601
+ [source,ruby]
602
+ ----
603
+ puts monitor.report
604
+ ----
605
+
606
+ ===== `to_json`
607
+
608
+ Exports metrics in JSON format.
609
+
610
+ **Returns:** String (JSON)
611
+
612
+ **Example:**
613
+
614
+ [source,ruby]
615
+ ----
616
+ json_metrics = monitor.to_json
617
+ ----
618
+
619
+ ===== `to_prometheus`
620
+
621
+ Exports metrics in Prometheus text format.
622
+
623
+ **Returns:** String (Prometheus format)
624
+
625
+ **Example:**
626
+
627
+ [source,ruby]
628
+ ----
629
+ prometheus_metrics = monitor.to_prometheus
630
+ ----
631
+
632
+ ===== `record_job(latency, success: true)`
633
+
634
+ Manually records a job completion.
635
+
636
+ [cols="1,1,3"]
637
+ |===
638
+ |Parameter |Type |Description
639
+
640
+ |`latency`
641
+ |Float
642
+ |Job latency in seconds
643
+
644
+ |`success`
645
+ |Boolean
646
+ |Whether job succeeded (default: true)
647
+ |===
648
+
649
+ **Example:**
650
+
651
+ [source,ruby]
652
+ ----
653
+ start_time = Time.now
654
+ # ... perform work ...
655
+ latency = Time.now - start_time
656
+ monitor.record_job(latency, success: true)
657
+ ----
658
+
659
+ == Workflow Classes
660
+
661
+ === Fractor::Workflow
662
+
663
+ Base class for declarative workflows.
664
+
665
+ ==== Class Methods
666
+
667
+ ===== `workflow(name, &block)`
668
+
669
+ Defines a workflow with the given name.
670
+
671
+ [cols="1,1,3"]
672
+ |===
673
+ |Parameter |Type |Description
674
+
675
+ |`name`
676
+ |String
677
+ |Workflow name
678
+
679
+ |`block`
680
+ |Proc
681
+ |Workflow definition block
682
+ |===
683
+
684
+ **Example:**
685
+
686
+ [source,ruby]
687
+ ----
688
+ class MyWorkflow < Fractor::Workflow
689
+ workflow "data-pipeline" do
690
+ input_type InputData
691
+ output_type OutputData
692
+
693
+ job "extract" do
694
+ runs_with ExtractWorker
695
+ inputs_from_workflow
696
+ end
697
+
698
+ job "transform" do
699
+ needs "extract"
700
+ runs_with TransformWorker
701
+ inputs_from_job "extract"
702
+ end
703
+
704
+ job "load" do
705
+ needs "transform"
706
+ runs_with LoadWorker
707
+ inputs_from_job "transform"
708
+ outputs_to_workflow
709
+ terminates_workflow
710
+ end
711
+ end
712
+ end
713
+ ----
714
+
715
+ ===== `define(name, &block)`
716
+
717
+ Creates a workflow class dynamically.
718
+
719
+ [cols="1,1,3"]
720
+ |===
721
+ |Parameter |Type |Description
722
+
723
+ |`name`
724
+ |String
725
+ |Workflow name
726
+
727
+ |`block`
728
+ |Proc
729
+ |Workflow definition block
730
+ |===
731
+
732
+ **Returns:** Class (anonymous workflow class)
733
+
734
+ **Example:**
735
+
736
+ [source,ruby]
737
+ ----
738
+ workflow_class = Fractor::Workflow.define("simple") do
739
+ job :process, ProcessWorker
740
+ job :finalize, FinalizeWorker, needs: :process
741
+ end
742
+
743
+ workflow = workflow_class.new
744
+ result = workflow.execute(input_data)
745
+ ----
746
+
747
+ ===== `chain(name)`
748
+
749
+ Creates a linear workflow builder.
750
+
751
+ [cols="1,1,3"]
752
+ |===
753
+ |Parameter |Type |Description
754
+
755
+ |`name`
756
+ |String
757
+ |Workflow name
758
+ |===
759
+
760
+ **Returns:** Fractor::Workflow::ChainBuilder
761
+
762
+ **Example:**
763
+
764
+ [source,ruby]
765
+ ----
766
+ workflow = Fractor::Workflow.chain("linear")
767
+ .step(:extract, ExtractWorker)
768
+ .step(:transform, TransformWorker)
769
+ .step(:load, LoadWorker)
770
+ .build
771
+
772
+ result = workflow.new.execute(input_data)
773
+ ----
774
+
775
+ ==== Instance Methods
776
+
777
+ ===== `execute(input)`
778
+
779
+ Executes the workflow with the given input.
780
+
781
+ [cols="1,1,3"]
782
+ |===
783
+ |Parameter |Type |Description
784
+
785
+ |`input`
786
+ |Any
787
+ |Workflow input data
788
+ |===
789
+
790
+ **Returns:** Workflow output data
791
+
792
+ **Raises:** Fractor::Workflow::WorkflowExecutionError on failure
793
+
794
+ **Example:**
795
+
796
+ [source,ruby]
797
+ ----
798
+ workflow = MyWorkflow.new
799
+ begin
800
+ result = workflow.execute(input_data)
801
+ puts "Success: #{result}"
802
+ rescue Fractor::Workflow::WorkflowExecutionError => e
803
+ puts "Failed: #{e.message}"
804
+ end
805
+ ----
806
+
807
+ ===== `dead_letter_queue`
808
+
809
+ Returns the workflow's dead letter queue.
810
+
811
+ **Returns:** Fractor::Workflow::DeadLetterQueue or nil
812
+
813
+ **Example:**
814
+
815
+ [source,ruby]
816
+ ----
817
+ dlq = workflow.dead_letter_queue
818
+ if dlq
819
+ puts "Failed items: #{dlq.size}"
820
+ end
821
+ ----
822
+
823
+ == Workflow DSL Reference
824
+
825
+ === Job Configuration
826
+
827
+ ==== `runs_with(worker_class)`
828
+
829
+ Specifies the worker class for the job.
830
+
831
+ **Example:**
832
+
833
+ [source,ruby]
834
+ ----
835
+ job "process" do
836
+ runs_with ProcessWorker
837
+ end
838
+ ----
839
+
840
+ ==== `needs(job_ids...)`
841
+
842
+ Specifies job dependencies.
843
+
844
+ **Example:**
845
+
846
+ [source,ruby]
847
+ ----
848
+ job "aggregate" do
849
+ needs "job1", "job2", "job3"
850
+ runs_with AggregateWorker
851
+ end
852
+ ----
853
+
854
+ ==== `inputs_from_workflow`
855
+
856
+ Job receives input from workflow input.
857
+
858
+ **Example:**
859
+
860
+ [source,ruby]
861
+ ----
862
+ job "first" do
863
+ runs_with FirstWorker
864
+ inputs_from_workflow
865
+ end
866
+ ----
867
+
868
+ ==== `inputs_from_job(job_id)`
869
+
870
+ Job receives input from another job's output.
871
+
872
+ **Example:**
873
+
874
+ [source,ruby]
875
+ ----
876
+ job "second" do
877
+ needs "first"
878
+ runs_with SecondWorker
879
+ inputs_from_job "first"
880
+ end
881
+ ----
882
+
883
+ ==== `outputs_to_workflow`
884
+
885
+ Job's output becomes the workflow output.
886
+
887
+ **Example:**
888
+
889
+ [source,ruby]
890
+ ----
891
+ job "final" do
892
+ runs_with FinalWorker
893
+ outputs_to_workflow
894
+ end
895
+ ----
896
+
897
+ ==== `terminates_workflow`
898
+
899
+ Job completion terminates the workflow.
900
+
901
+ **Example:**
902
+
903
+ [source,ruby]
904
+ ----
905
+ job "final" do
906
+ runs_with FinalWorker
907
+ outputs_to_workflow
908
+ terminates_workflow
909
+ end
910
+ ----
911
+
912
+ === Error Handling
913
+
914
+ ==== `retry_on_error(options)`
915
+
916
+ Configures automatic retry for the job.
917
+
918
+ [cols="1,1,3"]
919
+ |===
920
+ |Option |Type |Description
921
+
922
+ |`max_attempts`
923
+ |Integer
924
+ |Maximum retry attempts (default: 3)
925
+
926
+ |`backoff`
927
+ |Symbol
928
+ |Backoff strategy: `:exponential`, `:linear`, `:constant`, `:none`
929
+
930
+ |`initial_delay`
931
+ |Float
932
+ |Initial delay in seconds (default: 1)
933
+
934
+ |`max_delay`
935
+ |Float
936
+ |Maximum delay cap in seconds
937
+
938
+ |`multiplier`
939
+ |Float
940
+ |Exponential backoff multiplier (default: 2)
941
+
942
+ |`increment`
943
+ |Float
944
+ |Linear backoff increment (default: 1)
945
+
946
+ |`delay`
947
+ |Float
948
+ |Constant backoff delay (default: 1)
949
+
950
+ |`retryable_errors`
951
+ |Array<Class>
952
+ |Error classes to retry (default: [StandardError])
953
+ |===
954
+
955
+ **Example:**
956
+
957
+ [source,ruby]
958
+ ----
959
+ job "fetch_data" do
960
+ runs_with ApiWorker
961
+ retry_on_error max_attempts: 5,
962
+ backoff: :exponential,
963
+ initial_delay: 1,
964
+ max_delay: 60
965
+ end
966
+ ----
967
+
968
+ ==== `on_error(&block)`
969
+
970
+ Registers an error handler for the job.
971
+
972
+ **Example:**
973
+
974
+ [source,ruby]
975
+ ----
976
+ job "process" do
977
+ runs_with ProcessWorker
978
+ on_error do |error, context|
979
+ Logger.error("Job failed: #{error.message}")
980
+ AlertService.notify(error)
981
+ end
982
+ end
983
+ ----
984
+
985
+ ==== `fallback_to(job_id)`
986
+
987
+ Specifies a fallback job if this job fails.
988
+
989
+ **Example:**
990
+
991
+ [source,ruby]
992
+ ----
993
+ job "fetch_live" do
994
+ runs_with LiveDataWorker
995
+ retry_on_error max_attempts: 3
996
+ fallback_to "fetch_cached"
997
+ end
998
+
999
+ job "fetch_cached" do
1000
+ runs_with CachedDataWorker
1001
+ end
1002
+ ----
1003
+
1004
+ ==== `circuit_breaker(options)`
1005
+
1006
+ Configures circuit breaker for the job.
1007
+
1008
+ [cols="1,1,3"]
1009
+ |===
1010
+ |Option |Type |Description
1011
+
1012
+ |`threshold`
1013
+ |Integer
1014
+ |Failure threshold to open circuit (default: 5)
1015
+
1016
+ |`timeout`
1017
+ |Integer
1018
+ |Seconds to wait before half-open (default: 60)
1019
+
1020
+ |`half_open_calls`
1021
+ |Integer
1022
+ |Test calls in half-open state (default: 3)
1023
+
1024
+ |`shared_key`
1025
+ |String
1026
+ |Key for sharing circuit across jobs
1027
+ |===
1028
+
1029
+ **Example:**
1030
+
1031
+ [source,ruby]
1032
+ ----
1033
+ job "external_api" do
1034
+ runs_with ApiWorker
1035
+ circuit_breaker threshold: 5,
1036
+ timeout: 60,
1037
+ half_open_calls: 3
1038
+ end
1039
+ ----
1040
+
1041
+ === Dead Letter Queue
1042
+
1043
+ ==== `configure_dead_letter_queue(options)`
1044
+
1045
+ Configures the dead letter queue for the workflow.
1046
+
1047
+ [cols="1,1,3"]
1048
+ |===
1049
+ |Option |Type |Description
1050
+
1051
+ |`max_size`
1052
+ |Integer
1053
+ |Maximum DLQ size (default: 1000)
1054
+
1055
+ |`persister`
1056
+ |Object
1057
+ |Persistence strategy (optional)
1058
+
1059
+ |`on_add`
1060
+ |Proc
1061
+ |Callback when item added (optional)
1062
+ |===
1063
+
1064
+ **Example:**
1065
+
1066
+ [source,ruby]
1067
+ ----
1068
+ workflow "my-workflow" do
1069
+ configure_dead_letter_queue(
1070
+ max_size: 500,
1071
+ on_add: ->(entry) { Logger.error("DLQ: #{entry.error}") }
1072
+ )
1073
+ end
1074
+ ----
1075
+
1076
+ == See Also
1077
+
1078
+ * link:../pages/core-concepts/[Core Concepts] - Understanding Fractor components
1079
+ * link:../features/workflows/[Workflows] - Complete workflow documentation
1080
+ * link:../examples/[Examples] - Usage examples