tasker-engine 1.0.0

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 (605) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +443 -0
  4. data/Rakefile +10 -0
  5. data/app/controllers/tasker/analytics_controller.rb +179 -0
  6. data/app/controllers/tasker/application_controller.rb +45 -0
  7. data/app/controllers/tasker/graphql_controller.rb +193 -0
  8. data/app/controllers/tasker/handlers_controller.rb +217 -0
  9. data/app/controllers/tasker/health_controller.rb +229 -0
  10. data/app/controllers/tasker/metrics_controller.rb +111 -0
  11. data/app/controllers/tasker/page_sort.rb +97 -0
  12. data/app/controllers/tasker/task_diagrams_controller.rb +30 -0
  13. data/app/controllers/tasker/tasks_controller.rb +123 -0
  14. data/app/controllers/tasker/workflow_steps_controller.rb +69 -0
  15. data/app/graphql/examples/all_tasks.graphql +22 -0
  16. data/app/graphql/examples/pending_tasks.graphql +23 -0
  17. data/app/graphql/tasker/graph_ql_types/annotation_type.rb +14 -0
  18. data/app/graphql/tasker/graph_ql_types/base_argument.rb +9 -0
  19. data/app/graphql/tasker/graph_ql_types/base_connection.rb +11 -0
  20. data/app/graphql/tasker/graph_ql_types/base_edge.rb +10 -0
  21. data/app/graphql/tasker/graph_ql_types/base_enum.rb +9 -0
  22. data/app/graphql/tasker/graph_ql_types/base_field.rb +10 -0
  23. data/app/graphql/tasker/graph_ql_types/base_input_object.rb +10 -0
  24. data/app/graphql/tasker/graph_ql_types/base_interface.rb +14 -0
  25. data/app/graphql/tasker/graph_ql_types/base_object.rb +10 -0
  26. data/app/graphql/tasker/graph_ql_types/base_scalar.rb +9 -0
  27. data/app/graphql/tasker/graph_ql_types/base_union.rb +11 -0
  28. data/app/graphql/tasker/graph_ql_types/dependent_system_object_map_type.rb +18 -0
  29. data/app/graphql/tasker/graph_ql_types/dependent_system_type.rb +13 -0
  30. data/app/graphql/tasker/graph_ql_types/mutation_type.rb +16 -0
  31. data/app/graphql/tasker/graph_ql_types/named_step_type.rb +16 -0
  32. data/app/graphql/tasker/graph_ql_types/named_task_type.rb +14 -0
  33. data/app/graphql/tasker/graph_ql_types/named_tasks_named_step_type.rb +19 -0
  34. data/app/graphql/tasker/graph_ql_types/node_type.rb +12 -0
  35. data/app/graphql/tasker/graph_ql_types/query_type.rb +20 -0
  36. data/app/graphql/tasker/graph_ql_types/task_annotation_type.rb +17 -0
  37. data/app/graphql/tasker/graph_ql_types/task_interface.rb +17 -0
  38. data/app/graphql/tasker/graph_ql_types/task_type.rb +26 -0
  39. data/app/graphql/tasker/graph_ql_types/workflow_step_type.rb +154 -0
  40. data/app/graphql/tasker/graph_ql_types.rb +42 -0
  41. data/app/graphql/tasker/mutations/base_mutation.rb +13 -0
  42. data/app/graphql/tasker/mutations/cancel_step.rb +29 -0
  43. data/app/graphql/tasker/mutations/cancel_task.rb +29 -0
  44. data/app/graphql/tasker/mutations/create_task.rb +52 -0
  45. data/app/graphql/tasker/mutations/update_step.rb +36 -0
  46. data/app/graphql/tasker/mutations/update_task.rb +41 -0
  47. data/app/graphql/tasker/queries/all_annotation_types.rb +17 -0
  48. data/app/graphql/tasker/queries/all_tasks.rb +23 -0
  49. data/app/graphql/tasker/queries/base_query.rb +9 -0
  50. data/app/graphql/tasker/queries/helpers.rb +16 -0
  51. data/app/graphql/tasker/queries/one_step.rb +24 -0
  52. data/app/graphql/tasker/queries/one_task.rb +18 -0
  53. data/app/graphql/tasker/queries/tasks_by_annotation.rb +31 -0
  54. data/app/graphql/tasker/queries/tasks_by_status.rb +30 -0
  55. data/app/graphql/tasker/tasker_rails_schema.rb +52 -0
  56. data/app/jobs/tasker/application_job.rb +8 -0
  57. data/app/jobs/tasker/metrics_export_job.rb +252 -0
  58. data/app/jobs/tasker/task_runner_job.rb +224 -0
  59. data/app/models/tasker/annotation_type.rb +26 -0
  60. data/app/models/tasker/application_record.rb +70 -0
  61. data/app/models/tasker/dependent_system.rb +26 -0
  62. data/app/models/tasker/dependent_system_object_map.rb +64 -0
  63. data/app/models/tasker/diagram/edge.rb +106 -0
  64. data/app/models/tasker/diagram/flowchart.rb +137 -0
  65. data/app/models/tasker/diagram/node.rb +99 -0
  66. data/app/models/tasker/named_step.rb +41 -0
  67. data/app/models/tasker/named_task.rb +121 -0
  68. data/app/models/tasker/named_tasks_named_step.rb +82 -0
  69. data/app/models/tasker/step_dag_relationship.rb +65 -0
  70. data/app/models/tasker/step_readiness_status.rb +59 -0
  71. data/app/models/tasker/task.rb +424 -0
  72. data/app/models/tasker/task_annotation.rb +36 -0
  73. data/app/models/tasker/task_diagram.rb +332 -0
  74. data/app/models/tasker/task_execution_context.rb +29 -0
  75. data/app/models/tasker/task_namespace.rb +41 -0
  76. data/app/models/tasker/task_transition.rb +235 -0
  77. data/app/models/tasker/workflow_step.rb +461 -0
  78. data/app/models/tasker/workflow_step_edge.rb +94 -0
  79. data/app/models/tasker/workflow_step_transition.rb +434 -0
  80. data/app/serializers/tasker/annotation_type_serializer.rb +8 -0
  81. data/app/serializers/tasker/handler_serializer.rb +109 -0
  82. data/app/serializers/tasker/task_annotation_serializer.rb +32 -0
  83. data/app/serializers/tasker/task_serializer.rb +168 -0
  84. data/app/serializers/tasker/workflow_step_serializer.rb +27 -0
  85. data/app/services/tasker/analytics_service.rb +409 -0
  86. data/app/views/tasker/task/_diagram.html.erb +32 -0
  87. data/config/initializers/dry_struct.rb +11 -0
  88. data/config/initializers/statesman.rb +6 -0
  89. data/config/initializers/tasker_orchestration.rb +17 -0
  90. data/config/initializers/time_formats.rb +4 -0
  91. data/config/routes.rb +34 -0
  92. data/config/tasker/subscriptions/example_integrations.yml +67 -0
  93. data/config/tasker/system_events.yml +305 -0
  94. data/db/functions/calculate_dependency_levels_v01.sql +45 -0
  95. data/db/functions/get_analytics_metrics_v01.sql +137 -0
  96. data/db/functions/get_slowest_steps_v01.sql +82 -0
  97. data/db/functions/get_slowest_tasks_v01.sql +96 -0
  98. data/db/functions/get_step_readiness_status_batch_v01.sql +140 -0
  99. data/db/functions/get_step_readiness_status_v01.sql +139 -0
  100. data/db/functions/get_system_health_counts_v01.sql +108 -0
  101. data/db/functions/get_task_execution_context_v01.sql +108 -0
  102. data/db/functions/get_task_execution_contexts_batch_v01.sql +104 -0
  103. data/db/init/schema.sql +2277 -0
  104. data/db/migrate/20250701165431_initial_tasker_schema.rb +116 -0
  105. data/db/views/tasker_step_dag_relationships_v01.sql +69 -0
  106. data/docs/APPLICATION_GENERATOR.md +384 -0
  107. data/docs/AUTH.md +1780 -0
  108. data/docs/CIRCUIT_BREAKER.md +224 -0
  109. data/docs/DEVELOPER_GUIDE.md +2665 -0
  110. data/docs/EVENT_SYSTEM.md +637 -0
  111. data/docs/EXECUTION_CONFIGURATION.md +341 -0
  112. data/docs/FLOW_CHART.md +149 -0
  113. data/docs/HEALTH.md +542 -0
  114. data/docs/METRICS.md +731 -0
  115. data/docs/OPTIMIZATION_PLAN.md +1479 -0
  116. data/docs/OVERVIEW.md +552 -0
  117. data/docs/QUICK_START.md +270 -0
  118. data/docs/REGISTRY_SYSTEMS.md +373 -0
  119. data/docs/REST_API.md +632 -0
  120. data/docs/ROADMAP.md +221 -0
  121. data/docs/SQL_FUNCTIONS.md +1408 -0
  122. data/docs/TASK_DIAGRAM.md +252 -0
  123. data/docs/TASK_EXECUTION_CONTROL_FLOW.md +237 -0
  124. data/docs/TELEMETRY.md +795 -0
  125. data/docs/TROUBLESHOOTING.md +756 -0
  126. data/docs/TaskHandlerGenerator.html +255 -0
  127. data/docs/Tasker/Analysis/RuntimeGraphAnalyzer.html +907 -0
  128. data/docs/Tasker/Analysis/TemplateGraphAnalyzer.html +1236 -0
  129. data/docs/Tasker/Analysis.html +117 -0
  130. data/docs/Tasker/AnalyticsController.html +450 -0
  131. data/docs/Tasker/AnalyticsService/BottleneckAnalytics.html +816 -0
  132. data/docs/Tasker/AnalyticsService/PerformanceAnalytics.html +586 -0
  133. data/docs/Tasker/AnalyticsService.html +2221 -0
  134. data/docs/Tasker/AnnotationType.html +137 -0
  135. data/docs/Tasker/AnnotationTypeSerializer.html +124 -0
  136. data/docs/Tasker/ApplicationController.html +147 -0
  137. data/docs/Tasker/ApplicationJob.html +128 -0
  138. data/docs/Tasker/ApplicationRecord.html +378 -0
  139. data/docs/Tasker/Authentication/AuthenticationError.html +124 -0
  140. data/docs/Tasker/Authentication/ConfigurationError.html +124 -0
  141. data/docs/Tasker/Authentication/Coordinator.html +242 -0
  142. data/docs/Tasker/Authentication/Interface.html +560 -0
  143. data/docs/Tasker/Authentication/InterfaceError.html +124 -0
  144. data/docs/Tasker/Authentication/NoneAuthenticator.html +338 -0
  145. data/docs/Tasker/Authentication.html +119 -0
  146. data/docs/Tasker/Authorization/AuthorizationError.html +139 -0
  147. data/docs/Tasker/Authorization/BaseCoordinator.html +927 -0
  148. data/docs/Tasker/Authorization/ConfigurationError.html +153 -0
  149. data/docs/Tasker/Authorization/ResourceConstants/ACTIONS.html +428 -0
  150. data/docs/Tasker/Authorization/ResourceConstants/RESOURCES.html +365 -0
  151. data/docs/Tasker/Authorization/ResourceConstants.html +146 -0
  152. data/docs/Tasker/Authorization/ResourceRegistry.html +882 -0
  153. data/docs/Tasker/Authorization/UnauthorizedError.html +153 -0
  154. data/docs/Tasker/Authorization.html +582 -0
  155. data/docs/Tasker/CacheCapabilities.html +167 -0
  156. data/docs/Tasker/CacheStrategy.html +1297 -0
  157. data/docs/Tasker/Concerns/Authenticatable.html +116 -0
  158. data/docs/Tasker/Concerns/Authorizable/AdminStatusChecker.html +256 -0
  159. data/docs/Tasker/Concerns/Authorizable.html +816 -0
  160. data/docs/Tasker/Concerns/ControllerAuthorizable.html +157 -0
  161. data/docs/Tasker/Concerns/EventPublisher.html +4023 -0
  162. data/docs/Tasker/Concerns/IdempotentStateTransitions.html +806 -0
  163. data/docs/Tasker/Concerns/LifecycleEventHelpers.html +129 -0
  164. data/docs/Tasker/Concerns/OrchestrationPublisher.html +129 -0
  165. data/docs/Tasker/Concerns/StateMachineBase/ClassMethods.html +1075 -0
  166. data/docs/Tasker/Concerns/StateMachineBase/StateMachineBase/ClassMethods.html +191 -0
  167. data/docs/Tasker/Concerns/StateMachineBase/StateMachineBase.html +126 -0
  168. data/docs/Tasker/Concerns/StateMachineBase.html +153 -0
  169. data/docs/Tasker/Concerns/StructuredLogging.html +1413 -0
  170. data/docs/Tasker/Concerns.html +117 -0
  171. data/docs/Tasker/Configuration/AuthConfiguration.html +1023 -0
  172. data/docs/Tasker/Configuration/ConfigurationProxy.html +581 -0
  173. data/docs/Tasker/Configuration/DatabaseConfiguration.html +475 -0
  174. data/docs/Tasker/Configuration/EngineConfiguration.html +1265 -0
  175. data/docs/Tasker/Configuration/HealthConfiguration.html +791 -0
  176. data/docs/Tasker/Configuration/TelemetryConfiguration.html +1308 -0
  177. data/docs/Tasker/Configuration/TelemetryConfigurationProxy.html +388 -0
  178. data/docs/Tasker/Configuration.html +1669 -0
  179. data/docs/Tasker/ConfigurationError.html +143 -0
  180. data/docs/Tasker/ConfiguredTask.html +514 -0
  181. data/docs/Tasker/Constants/EventDefinitions.html +590 -0
  182. data/docs/Tasker/Constants/LifecycleEvents.html +137 -0
  183. data/docs/Tasker/Constants/ObservabilityEvents/Step.html +152 -0
  184. data/docs/Tasker/Constants/ObservabilityEvents/Task.html +142 -0
  185. data/docs/Tasker/Constants/ObservabilityEvents.html +126 -0
  186. data/docs/Tasker/Constants/RegistryEvents.html +285 -0
  187. data/docs/Tasker/Constants/StepEvents.html +177 -0
  188. data/docs/Tasker/Constants/TaskEvents.html +167 -0
  189. data/docs/Tasker/Constants/TaskExecution/ExecutionStatus.html +207 -0
  190. data/docs/Tasker/Constants/TaskExecution/HealthStatus.html +191 -0
  191. data/docs/Tasker/Constants/TaskExecution/RecommendedAction.html +207 -0
  192. data/docs/Tasker/Constants/TaskExecution.html +126 -0
  193. data/docs/Tasker/Constants/TaskFinalization/ErrorMessages.html +132 -0
  194. data/docs/Tasker/Constants/TaskFinalization/PendingReasons.html +207 -0
  195. data/docs/Tasker/Constants/TaskFinalization/ReenqueueReasons.html +239 -0
  196. data/docs/Tasker/Constants/TaskFinalization.html +126 -0
  197. data/docs/Tasker/Constants/TaskStatuses.html +223 -0
  198. data/docs/Tasker/Constants/TestEvents.html +163 -0
  199. data/docs/Tasker/Constants/WorkflowEvents.html +222 -0
  200. data/docs/Tasker/Constants/WorkflowStepStatuses.html +223 -0
  201. data/docs/Tasker/Constants.html +561 -0
  202. data/docs/Tasker/DependentSystem.html +137 -0
  203. data/docs/Tasker/DependentSystemObjectMap.html +250 -0
  204. data/docs/Tasker/DetectorRegistry.html +598 -0
  205. data/docs/Tasker/Diagram/Edge.html +1191 -0
  206. data/docs/Tasker/Diagram/Flowchart.html +1539 -0
  207. data/docs/Tasker/Diagram/Node.html +1165 -0
  208. data/docs/Tasker/Diagram.html +117 -0
  209. data/docs/Tasker/Engine.html +215 -0
  210. data/docs/Tasker/Error.html +139 -0
  211. data/docs/Tasker/Events/Bus.html +1226 -0
  212. data/docs/Tasker/Events/Catalog/CatalogPrinter.html +258 -0
  213. data/docs/Tasker/Events/Catalog/CustomEventRegistrar.html +276 -0
  214. data/docs/Tasker/Events/Catalog/ExamplePayloadGenerator.html +294 -0
  215. data/docs/Tasker/Events/Catalog.html +1291 -0
  216. data/docs/Tasker/Events/CustomRegistry.html +943 -0
  217. data/docs/Tasker/Events/DefinitionLoader.html +575 -0
  218. data/docs/Tasker/Events/EventPayloadBuilder/ErrorInfoExtractor.html +286 -0
  219. data/docs/Tasker/Events/EventPayloadBuilder/StepPayloadBuilder.html +312 -0
  220. data/docs/Tasker/Events/EventPayloadBuilder.html +664 -0
  221. data/docs/Tasker/Events/Publisher.html +365 -0
  222. data/docs/Tasker/Events/Subscribers/BaseSubscriber/ErrorCategorizer/ErrorTypeClassifier.html +1128 -0
  223. data/docs/Tasker/Events/Subscribers/BaseSubscriber/ErrorCategorizer.html +270 -0
  224. data/docs/Tasker/Events/Subscribers/BaseSubscriber/MetricTagsExtractor.html +266 -0
  225. data/docs/Tasker/Events/Subscribers/BaseSubscriber.html +2556 -0
  226. data/docs/Tasker/Events/Subscribers/MetricsSubscriber.html +723 -0
  227. data/docs/Tasker/Events/Subscribers/TelemetrySubscriber.html +2251 -0
  228. data/docs/Tasker/Events/Subscribers.html +117 -0
  229. data/docs/Tasker/Events/SubscriptionLoader.html +493 -0
  230. data/docs/Tasker/Events.html +294 -0
  231. data/docs/Tasker/EventsGenerator.html +459 -0
  232. data/docs/Tasker/Functions/FunctionBasedAnalyticsMetrics/AnalyticsMetrics.html +135 -0
  233. data/docs/Tasker/Functions/FunctionBasedAnalyticsMetrics.html +412 -0
  234. data/docs/Tasker/Functions/FunctionBasedDependencyLevels.html +598 -0
  235. data/docs/Tasker/Functions/FunctionBasedSlowestSteps/SlowestStep.html +135 -0
  236. data/docs/Tasker/Functions/FunctionBasedSlowestSteps.html +453 -0
  237. data/docs/Tasker/Functions/FunctionBasedSlowestTasks/SlowestTask.html +135 -0
  238. data/docs/Tasker/Functions/FunctionBasedSlowestTasks.html +453 -0
  239. data/docs/Tasker/Functions/FunctionBasedStepReadinessStatus.html +1457 -0
  240. data/docs/Tasker/Functions/FunctionBasedSystemHealthCounts/HealthMetrics.html +135 -0
  241. data/docs/Tasker/Functions/FunctionBasedSystemHealthCounts.html +370 -0
  242. data/docs/Tasker/Functions/FunctionBasedTaskExecutionContext.html +1250 -0
  243. data/docs/Tasker/Functions/FunctionWrapper.html +479 -0
  244. data/docs/Tasker/Functions.html +117 -0
  245. data/docs/Tasker/Generators/AuthenticatorGenerator/UsageInstructionsFormatter.html +244 -0
  246. data/docs/Tasker/Generators/AuthenticatorGenerator.html +373 -0
  247. data/docs/Tasker/Generators/AuthorizationCoordinatorGenerator.html +430 -0
  248. data/docs/Tasker/Generators/SubscriberGenerator.html +377 -0
  249. data/docs/Tasker/Generators/TaskHandlerGenerator.html +263 -0
  250. data/docs/Tasker/Generators.html +117 -0
  251. data/docs/Tasker/GraphQLTypes/AnnotationType.html +132 -0
  252. data/docs/Tasker/GraphQLTypes/BaseArgument.html +124 -0
  253. data/docs/Tasker/GraphQLTypes/BaseConnection.html +124 -0
  254. data/docs/Tasker/GraphQLTypes/BaseEdge.html +130 -0
  255. data/docs/Tasker/GraphQLTypes/BaseEnum.html +124 -0
  256. data/docs/Tasker/GraphQLTypes/BaseField.html +124 -0
  257. data/docs/Tasker/GraphQLTypes/BaseInputObject.html +124 -0
  258. data/docs/Tasker/GraphQLTypes/BaseInterface.html +116 -0
  259. data/docs/Tasker/GraphQLTypes/BaseObject.html +128 -0
  260. data/docs/Tasker/GraphQLTypes/BaseScalar.html +124 -0
  261. data/docs/Tasker/GraphQLTypes/BaseUnion.html +124 -0
  262. data/docs/Tasker/GraphQLTypes/DependentSystemObjectMapType.html +132 -0
  263. data/docs/Tasker/GraphQLTypes/DependentSystemType.html +132 -0
  264. data/docs/Tasker/GraphQLTypes/MutationType.html +132 -0
  265. data/docs/Tasker/GraphQLTypes/NamedStepType.html +132 -0
  266. data/docs/Tasker/GraphQLTypes/NamedTaskType.html +132 -0
  267. data/docs/Tasker/GraphQLTypes/NamedTasksNamedStepType.html +132 -0
  268. data/docs/Tasker/GraphQLTypes/NodeType.html +118 -0
  269. data/docs/Tasker/GraphQLTypes/QueryType.html +139 -0
  270. data/docs/Tasker/GraphQLTypes/TaskAnnotationType.html +132 -0
  271. data/docs/Tasker/GraphQLTypes/TaskInterface.html +111 -0
  272. data/docs/Tasker/GraphQLTypes/TaskType.html +201 -0
  273. data/docs/Tasker/GraphQLTypes/WorkflowStepType.html +694 -0
  274. data/docs/Tasker/GraphQLTypes.html +130 -0
  275. data/docs/Tasker/GraphqlController.html +251 -0
  276. data/docs/Tasker/HandlerFactory.html +1518 -0
  277. data/docs/Tasker/HandlerSerializer.html +682 -0
  278. data/docs/Tasker/HandlersController.html +574 -0
  279. data/docs/Tasker/HashIdentityStrategy.html +278 -0
  280. data/docs/Tasker/Health/ReadinessChecker.html +712 -0
  281. data/docs/Tasker/Health/StatusChecker.html +653 -0
  282. data/docs/Tasker/Health.html +117 -0
  283. data/docs/Tasker/HealthController.html +523 -0
  284. data/docs/Tasker/IdentityStrategy.html +276 -0
  285. data/docs/Tasker/InvalidTaskHandlerConfig.html +135 -0
  286. data/docs/Tasker/LifecycleEvents/Events/Step.html +162 -0
  287. data/docs/Tasker/LifecycleEvents/Events/Task.html +162 -0
  288. data/docs/Tasker/LifecycleEvents/Events.html +204 -0
  289. data/docs/Tasker/LifecycleEvents/Publisher.html +132 -0
  290. data/docs/Tasker/LifecycleEvents.html +799 -0
  291. data/docs/Tasker/Logging/CorrelationIdGenerator.html +688 -0
  292. data/docs/Tasker/Logging.html +115 -0
  293. data/docs/Tasker/MetricsController.html +293 -0
  294. data/docs/Tasker/MetricsExportJob.html +414 -0
  295. data/docs/Tasker/Mutations/BaseMutation.html +128 -0
  296. data/docs/Tasker/Mutations/CancelStep.html +219 -0
  297. data/docs/Tasker/Mutations/CancelTask.html +221 -0
  298. data/docs/Tasker/Mutations/CreateTask.html +243 -0
  299. data/docs/Tasker/Mutations/UpdateStep.html +243 -0
  300. data/docs/Tasker/Mutations/UpdateTask.html +243 -0
  301. data/docs/Tasker/Mutations.html +117 -0
  302. data/docs/Tasker/NamedStep.html +216 -0
  303. data/docs/Tasker/NamedTask.html +910 -0
  304. data/docs/Tasker/NamedTasksNamedStep.html +435 -0
  305. data/docs/Tasker/Orchestration/BackoffCalculator.html +404 -0
  306. data/docs/Tasker/Orchestration/ConnectionBuilder/ConfigValidator.html +258 -0
  307. data/docs/Tasker/Orchestration/ConnectionBuilder.html +435 -0
  308. data/docs/Tasker/Orchestration/ConnectionPoolIntelligence.html +513 -0
  309. data/docs/Tasker/Orchestration/Coordinator.html +641 -0
  310. data/docs/Tasker/Orchestration/FutureStateAnalyzer.html +1045 -0
  311. data/docs/Tasker/Orchestration/Orchestrator.html +679 -0
  312. data/docs/Tasker/Orchestration/PluginIntegration.html +1127 -0
  313. data/docs/Tasker/Orchestration/ResponseProcessor.html +504 -0
  314. data/docs/Tasker/Orchestration/RetryHeaderParser.html +304 -0
  315. data/docs/Tasker/Orchestration/StepExecutor.html +995 -0
  316. data/docs/Tasker/Orchestration/StepSequenceFactory.html +644 -0
  317. data/docs/Tasker/Orchestration/TaskFinalizer/BlockageChecker.html +264 -0
  318. data/docs/Tasker/Orchestration/TaskFinalizer/ContextManager.html +254 -0
  319. data/docs/Tasker/Orchestration/TaskFinalizer/DelayCalculator.html +556 -0
  320. data/docs/Tasker/Orchestration/TaskFinalizer/FinalizationDecisionMaker.html +348 -0
  321. data/docs/Tasker/Orchestration/TaskFinalizer/FinalizationProcessor.html +286 -0
  322. data/docs/Tasker/Orchestration/TaskFinalizer/ReasonDeterminer.html +432 -0
  323. data/docs/Tasker/Orchestration/TaskFinalizer/ReenqueueManager.html +296 -0
  324. data/docs/Tasker/Orchestration/TaskFinalizer/UnclearStateHandler.html +314 -0
  325. data/docs/Tasker/Orchestration/TaskFinalizer.html +1212 -0
  326. data/docs/Tasker/Orchestration/TaskInitializer.html +766 -0
  327. data/docs/Tasker/Orchestration/TaskReenqueuer.html +506 -0
  328. data/docs/Tasker/Orchestration/ViableStepDiscovery.html +442 -0
  329. data/docs/Tasker/Orchestration/WorkflowCoordinator.html +510 -0
  330. data/docs/Tasker/Orchestration.html +130 -0
  331. data/docs/Tasker/PageSort/PageSortParamsBuilder.html +296 -0
  332. data/docs/Tasker/PageSort.html +247 -0
  333. data/docs/Tasker/PermanentError.html +518 -0
  334. data/docs/Tasker/ProceduralError.html +147 -0
  335. data/docs/Tasker/Queries/AllAnnotationTypes.html +217 -0
  336. data/docs/Tasker/Queries/AllTasks.html +221 -0
  337. data/docs/Tasker/Queries/BaseQuery.html +128 -0
  338. data/docs/Tasker/Queries/Helpers.html +187 -0
  339. data/docs/Tasker/Queries/OneStep.html +225 -0
  340. data/docs/Tasker/Queries/OneTask.html +217 -0
  341. data/docs/Tasker/Queries/TasksByAnnotation.html +231 -0
  342. data/docs/Tasker/Queries/TasksByStatus.html +233 -0
  343. data/docs/Tasker/Queries.html +119 -0
  344. data/docs/Tasker/Railtie.html +124 -0
  345. data/docs/Tasker/Registry/BaseRegistry.html +1690 -0
  346. data/docs/Tasker/Registry/EventPublisher.html +667 -0
  347. data/docs/Tasker/Registry/InterfaceValidator.html +569 -0
  348. data/docs/Tasker/Registry/RegistrationError.html +132 -0
  349. data/docs/Tasker/Registry/RegistryError.html +139 -0
  350. data/docs/Tasker/Registry/StatisticsCollector.html +841 -0
  351. data/docs/Tasker/Registry/SubscriberRegistry.html +1504 -0
  352. data/docs/Tasker/Registry/ValidationError.html +132 -0
  353. data/docs/Tasker/Registry.html +119 -0
  354. data/docs/Tasker/RetryableError.html +515 -0
  355. data/docs/Tasker/StateMachine/Compatibility.html +282 -0
  356. data/docs/Tasker/StateMachine/InvalidStateTransition.html +135 -0
  357. data/docs/Tasker/StateMachine/StepStateMachine/StandardizedPayloadBuilder.html +260 -0
  358. data/docs/Tasker/StateMachine/StepStateMachine.html +2215 -0
  359. data/docs/Tasker/StateMachine/TaskStateMachine.html +734 -0
  360. data/docs/Tasker/StateMachine.html +602 -0
  361. data/docs/Tasker/StepDagRelationship.html +657 -0
  362. data/docs/Tasker/StepHandler/Api/Config.html +1091 -0
  363. data/docs/Tasker/StepHandler/Api.html +884 -0
  364. data/docs/Tasker/StepHandler/AutomaticEventPublishing.html +321 -0
  365. data/docs/Tasker/StepHandler/Base.html +970 -0
  366. data/docs/Tasker/StepHandler.html +119 -0
  367. data/docs/Tasker/StepReadinessStatus.html +836 -0
  368. data/docs/Tasker/Task.html +2575 -0
  369. data/docs/Tasker/TaskAnnotation.html +137 -0
  370. data/docs/Tasker/TaskAnnotationSerializer.html +124 -0
  371. data/docs/Tasker/TaskBuilder/StepNameValidator.html +264 -0
  372. data/docs/Tasker/TaskBuilder/StepTemplateDefiner.html +264 -0
  373. data/docs/Tasker/TaskBuilder.html +764 -0
  374. data/docs/Tasker/TaskDiagram/StepToStepEdgeBuilder.html +260 -0
  375. data/docs/Tasker/TaskDiagram/TaskToRootStepEdgeBuilder.html +290 -0
  376. data/docs/Tasker/TaskDiagram.html +548 -0
  377. data/docs/Tasker/TaskDiagramsController.html +240 -0
  378. data/docs/Tasker/TaskExecutionContext.html +469 -0
  379. data/docs/Tasker/TaskHandler/ClassMethods/StepTemplateDefiner/ClassBasedEventRegistrar.html +238 -0
  380. data/docs/Tasker/TaskHandler/ClassMethods/StepTemplateDefiner/YamlEventRegistrar.html +254 -0
  381. data/docs/Tasker/TaskHandler/ClassMethods/StepTemplateDefiner.html +988 -0
  382. data/docs/Tasker/TaskHandler/ClassMethods.html +357 -0
  383. data/docs/Tasker/TaskHandler/InstanceMethods.html +1396 -0
  384. data/docs/Tasker/TaskHandler/StepGroup.html +1748 -0
  385. data/docs/Tasker/TaskHandler.html +271 -0
  386. data/docs/Tasker/TaskNamespace.html +312 -0
  387. data/docs/Tasker/TaskRunnerJob.html +406 -0
  388. data/docs/Tasker/TaskSerializer.html +474 -0
  389. data/docs/Tasker/TaskTransition.html +1517 -0
  390. data/docs/Tasker/TaskWorkflowSummary.html +988 -0
  391. data/docs/Tasker/TaskerRailsSchema/InvalidObjectTypeError.html +132 -0
  392. data/docs/Tasker/TaskerRailsSchema/TypeResolutionError.html +139 -0
  393. data/docs/Tasker/TaskerRailsSchema/UnknownInterfaceError.html +132 -0
  394. data/docs/Tasker/TaskerRailsSchema.html +384 -0
  395. data/docs/Tasker/TasksController.html +595 -0
  396. data/docs/Tasker/Telemetry/EventMapping.html +1307 -0
  397. data/docs/Tasker/Telemetry/EventRouter.html +2178 -0
  398. data/docs/Tasker/Telemetry/Events/ExportEvents.html +246 -0
  399. data/docs/Tasker/Telemetry/Events.html +115 -0
  400. data/docs/Tasker/Telemetry/ExportCoordinator/DistributedLockTimeoutError.html +135 -0
  401. data/docs/Tasker/Telemetry/ExportCoordinator.html +2137 -0
  402. data/docs/Tasker/Telemetry/IntelligentCacheManager.html +1083 -0
  403. data/docs/Tasker/Telemetry/LogBackend.html +1088 -0
  404. data/docs/Tasker/Telemetry/MetricTypes/Counter.html +1054 -0
  405. data/docs/Tasker/Telemetry/MetricTypes/Gauge.html +1270 -0
  406. data/docs/Tasker/Telemetry/MetricTypes/Histogram.html +1492 -0
  407. data/docs/Tasker/Telemetry/MetricTypes.html +153 -0
  408. data/docs/Tasker/Telemetry/MetricsBackend.html +2510 -0
  409. data/docs/Tasker/Telemetry/MetricsExportService.html +578 -0
  410. data/docs/Tasker/Telemetry/PluginRegistry.html +1774 -0
  411. data/docs/Tasker/Telemetry/Plugins/BaseExporter.html +1835 -0
  412. data/docs/Tasker/Telemetry/Plugins/CsvExporter.html +768 -0
  413. data/docs/Tasker/Telemetry/Plugins/JsonExporter.html +747 -0
  414. data/docs/Tasker/Telemetry/Plugins.html +117 -0
  415. data/docs/Tasker/Telemetry/PrometheusExporter.html +481 -0
  416. data/docs/Tasker/Telemetry/TraceBackend.html +891 -0
  417. data/docs/Tasker/Telemetry.html +130 -0
  418. data/docs/Tasker/Types/AuthConfig.html +886 -0
  419. data/docs/Tasker/Types/BackoffConfig.html +1063 -0
  420. data/docs/Tasker/Types/BaseConfig.html +227 -0
  421. data/docs/Tasker/Types/CacheConfig.html +1731 -0
  422. data/docs/Tasker/Types/DatabaseConfig.html +388 -0
  423. data/docs/Tasker/Types/DependencyGraph.html +526 -0
  424. data/docs/Tasker/Types/DependencyGraphConfig.html +753 -0
  425. data/docs/Tasker/Types/EngineConfig.html +1181 -0
  426. data/docs/Tasker/Types/ExecutionConfig.html +1963 -0
  427. data/docs/Tasker/Types/GraphEdge.html +517 -0
  428. data/docs/Tasker/Types/GraphMetadata.html +781 -0
  429. data/docs/Tasker/Types/GraphNode.html +694 -0
  430. data/docs/Tasker/Types/HealthConfig.html +784 -0
  431. data/docs/Tasker/Types/StepSequence.html +353 -0
  432. data/docs/Tasker/Types/StepTemplate.html +1193 -0
  433. data/docs/Tasker/Types/TaskRequest.html +1179 -0
  434. data/docs/Tasker/Types/TelemetryConfig.html +2746 -0
  435. data/docs/Tasker/Types.html +154 -0
  436. data/docs/Tasker/WorkflowStep/StepFinder.html +282 -0
  437. data/docs/Tasker/WorkflowStep.html +2724 -0
  438. data/docs/Tasker/WorkflowStepEdge.html +304 -0
  439. data/docs/Tasker/WorkflowStepSerializer.html +305 -0
  440. data/docs/Tasker/WorkflowStepTransition/TransitionDescriptionFormatter.html +282 -0
  441. data/docs/Tasker/WorkflowStepTransition.html +2201 -0
  442. data/docs/Tasker/WorkflowStepsController.html +462 -0
  443. data/docs/Tasker.html +452 -0
  444. data/docs/VISION.md +584 -0
  445. data/docs/WHY.md +21 -0
  446. data/docs/_index.html +2375 -0
  447. data/docs/class_list.html +54 -0
  448. data/docs/css/common.css +1 -0
  449. data/docs/css/full_list.css +58 -0
  450. data/docs/css/style.css +503 -0
  451. data/docs/events/migration_plan_outcomes.md +80 -0
  452. data/docs/file.README.html +541 -0
  453. data/docs/file_list.html +59 -0
  454. data/docs/frames.html +22 -0
  455. data/docs/index.html +541 -0
  456. data/docs/js/app.js +344 -0
  457. data/docs/js/full_list.js +242 -0
  458. data/docs/js/jquery.js +4 -0
  459. data/docs/method_list.html +9182 -0
  460. data/docs/top-level-namespace.html +110 -0
  461. data/lib/generators/tasker/authenticator_generator.rb +301 -0
  462. data/lib/generators/tasker/authorization_coordinator_generator.rb +139 -0
  463. data/lib/generators/tasker/events_generator.rb +91 -0
  464. data/lib/generators/tasker/subscriber_generator.rb +107 -0
  465. data/lib/generators/tasker/task_handler_generator.rb +138 -0
  466. data/lib/generators/tasker/templates/api_token_authenticator.rb.erb +113 -0
  467. data/lib/generators/tasker/templates/api_token_authenticator_spec.rb.erb +144 -0
  468. data/lib/generators/tasker/templates/authorization_coordinator.rb.erb +95 -0
  469. data/lib/generators/tasker/templates/authorization_coordinator_spec.rb.erb +142 -0
  470. data/lib/generators/tasker/templates/custom_authenticator.rb.erb +108 -0
  471. data/lib/generators/tasker/templates/custom_authenticator_spec.rb.erb +162 -0
  472. data/lib/generators/tasker/templates/custom_events.yml.erb +62 -0
  473. data/lib/generators/tasker/templates/custom_subscriber.rb.erb +72 -0
  474. data/lib/generators/tasker/templates/devise_authenticator.rb.erb +101 -0
  475. data/lib/generators/tasker/templates/devise_authenticator_spec.rb.erb +126 -0
  476. data/lib/generators/tasker/templates/initialize.rb.erb +202 -0
  477. data/lib/generators/tasker/templates/jwt_authenticator.rb.erb +144 -0
  478. data/lib/generators/tasker/templates/jwt_authenticator_spec.rb.erb +298 -0
  479. data/lib/generators/tasker/templates/metrics_subscriber.rb.erb +258 -0
  480. data/lib/generators/tasker/templates/metrics_subscriber_spec.rb.erb +308 -0
  481. data/lib/generators/tasker/templates/omniauth_authenticator.rb.erb +135 -0
  482. data/lib/generators/tasker/templates/omniauth_authenticator_spec.rb.erb +196 -0
  483. data/lib/generators/tasker/templates/opentelemetry_initializer.rb +52 -0
  484. data/lib/generators/tasker/templates/subscriber.rb.erb +64 -0
  485. data/lib/generators/tasker/templates/subscriber_spec.rb.erb +80 -0
  486. data/lib/generators/tasker/templates/task_config.yaml.erb +117 -0
  487. data/lib/generators/tasker/templates/task_handler.rb.erb +59 -0
  488. data/lib/generators/tasker/templates/task_handler_spec.rb.erb +159 -0
  489. data/lib/tasker/analysis/runtime_graph_analyzer.rb +1168 -0
  490. data/lib/tasker/analysis/template_graph_analyzer.rb +328 -0
  491. data/lib/tasker/authentication/coordinator.rb +78 -0
  492. data/lib/tasker/authentication/errors.rb +9 -0
  493. data/lib/tasker/authentication/interface.rb +36 -0
  494. data/lib/tasker/authentication/none_authenticator.rb +26 -0
  495. data/lib/tasker/authorization/base_coordinator.rb +112 -0
  496. data/lib/tasker/authorization/errors.rb +26 -0
  497. data/lib/tasker/authorization/resource_constants.rb +74 -0
  498. data/lib/tasker/authorization/resource_registry.rb +143 -0
  499. data/lib/tasker/authorization.rb +75 -0
  500. data/lib/tasker/cache_capabilities.rb +131 -0
  501. data/lib/tasker/cache_strategy.rb +469 -0
  502. data/lib/tasker/concerns/authenticatable.rb +41 -0
  503. data/lib/tasker/concerns/authorizable.rb +204 -0
  504. data/lib/tasker/concerns/controller_authorizable.rb +124 -0
  505. data/lib/tasker/concerns/event_publisher.rb +716 -0
  506. data/lib/tasker/concerns/idempotent_state_transitions.rb +128 -0
  507. data/lib/tasker/concerns/state_machine_base.rb +218 -0
  508. data/lib/tasker/concerns/structured_logging.rb +387 -0
  509. data/lib/tasker/configuration.rb +325 -0
  510. data/lib/tasker/constants/event_definitions.rb +147 -0
  511. data/lib/tasker/constants/registry_events.rb +54 -0
  512. data/lib/tasker/constants.rb +417 -0
  513. data/lib/tasker/engine.rb +90 -0
  514. data/lib/tasker/errors.rb +90 -0
  515. data/lib/tasker/events/catalog.rb +432 -0
  516. data/lib/tasker/events/custom_registry.rb +175 -0
  517. data/lib/tasker/events/definition_loader.rb +199 -0
  518. data/lib/tasker/events/event_payload_builder.rb +461 -0
  519. data/lib/tasker/events/publisher.rb +149 -0
  520. data/lib/tasker/events/subscribers/base_subscriber.rb +601 -0
  521. data/lib/tasker/events/subscribers/metrics_subscriber.rb +120 -0
  522. data/lib/tasker/events/subscribers/telemetry_subscriber.rb +462 -0
  523. data/lib/tasker/events/subscription_loader.rb +161 -0
  524. data/lib/tasker/events.rb +37 -0
  525. data/lib/tasker/functions/function_based_analytics_metrics.rb +103 -0
  526. data/lib/tasker/functions/function_based_dependency_levels.rb +54 -0
  527. data/lib/tasker/functions/function_based_slowest_steps.rb +84 -0
  528. data/lib/tasker/functions/function_based_slowest_tasks.rb +84 -0
  529. data/lib/tasker/functions/function_based_step_readiness_status.rb +183 -0
  530. data/lib/tasker/functions/function_based_system_health_counts.rb +94 -0
  531. data/lib/tasker/functions/function_based_task_execution_context.rb +148 -0
  532. data/lib/tasker/functions/function_wrapper.rb +42 -0
  533. data/lib/tasker/functions.rb +12 -0
  534. data/lib/tasker/handler_factory.rb +322 -0
  535. data/lib/tasker/health/readiness_checker.rb +186 -0
  536. data/lib/tasker/health/status_checker.rb +203 -0
  537. data/lib/tasker/identity_strategy.rb +38 -0
  538. data/lib/tasker/logging/correlation_id_generator.rb +120 -0
  539. data/lib/tasker/orchestration/backoff_calculator.rb +184 -0
  540. data/lib/tasker/orchestration/connection_builder.rb +122 -0
  541. data/lib/tasker/orchestration/connection_pool_intelligence.rb +177 -0
  542. data/lib/tasker/orchestration/coordinator.rb +119 -0
  543. data/lib/tasker/orchestration/future_state_analyzer.rb +137 -0
  544. data/lib/tasker/orchestration/plugin_integration.rb +124 -0
  545. data/lib/tasker/orchestration/response_processor.rb +168 -0
  546. data/lib/tasker/orchestration/retry_header_parser.rb +78 -0
  547. data/lib/tasker/orchestration/step_executor.rb +941 -0
  548. data/lib/tasker/orchestration/step_sequence_factory.rb +67 -0
  549. data/lib/tasker/orchestration/task_finalizer.rb +564 -0
  550. data/lib/tasker/orchestration/task_initializer.rb +140 -0
  551. data/lib/tasker/orchestration/task_reenqueuer.rb +71 -0
  552. data/lib/tasker/orchestration/viable_step_discovery.rb +65 -0
  553. data/lib/tasker/orchestration/workflow_coordinator.rb +294 -0
  554. data/lib/tasker/orchestration.rb +45 -0
  555. data/lib/tasker/railtie.rb +9 -0
  556. data/lib/tasker/registry/base_registry.rb +177 -0
  557. data/lib/tasker/registry/event_publisher.rb +91 -0
  558. data/lib/tasker/registry/interface_validator.rb +140 -0
  559. data/lib/tasker/registry/statistics_collector.rb +381 -0
  560. data/lib/tasker/registry/subscriber_registry.rb +285 -0
  561. data/lib/tasker/registry.rb +22 -0
  562. data/lib/tasker/state_machine/step_state_machine.rb +508 -0
  563. data/lib/tasker/state_machine/task_state_machine.rb +192 -0
  564. data/lib/tasker/state_machine.rb +83 -0
  565. data/lib/tasker/step_handler/api.rb +410 -0
  566. data/lib/tasker/step_handler/base.rb +206 -0
  567. data/lib/tasker/task_builder.rb +432 -0
  568. data/lib/tasker/task_handler/class_methods.rb +324 -0
  569. data/lib/tasker/task_handler/instance_methods.rb +293 -0
  570. data/lib/tasker/task_handler/step_group.rb +182 -0
  571. data/lib/tasker/task_handler.rb +43 -0
  572. data/lib/tasker/telemetry/event_mapping.rb +126 -0
  573. data/lib/tasker/telemetry/event_router.rb +318 -0
  574. data/lib/tasker/telemetry/events/export_events.rb +38 -0
  575. data/lib/tasker/telemetry/export_coordinator.rb +497 -0
  576. data/lib/tasker/telemetry/intelligent_cache_manager.rb +508 -0
  577. data/lib/tasker/telemetry/log_backend.rb +224 -0
  578. data/lib/tasker/telemetry/metric_types.rb +368 -0
  579. data/lib/tasker/telemetry/metrics_backend.rb +1227 -0
  580. data/lib/tasker/telemetry/metrics_export_service.rb +392 -0
  581. data/lib/tasker/telemetry/plugin_registry.rb +333 -0
  582. data/lib/tasker/telemetry/plugins/base_exporter.rb +246 -0
  583. data/lib/tasker/telemetry/plugins/csv_exporter.rb +198 -0
  584. data/lib/tasker/telemetry/plugins/json_exporter.rb +141 -0
  585. data/lib/tasker/telemetry/prometheus_exporter.rb +249 -0
  586. data/lib/tasker/telemetry/trace_backend.rb +186 -0
  587. data/lib/tasker/telemetry.rb +59 -0
  588. data/lib/tasker/types/auth_config.rb +81 -0
  589. data/lib/tasker/types/backoff_config.rb +142 -0
  590. data/lib/tasker/types/cache_config.rb +257 -0
  591. data/lib/tasker/types/database_config.rb +39 -0
  592. data/lib/tasker/types/dependency_graph.rb +225 -0
  593. data/lib/tasker/types/dependency_graph_config.rb +149 -0
  594. data/lib/tasker/types/engine_config.rb +131 -0
  595. data/lib/tasker/types/execution_config.rb +289 -0
  596. data/lib/tasker/types/health_config.rb +84 -0
  597. data/lib/tasker/types/step_sequence.rb +24 -0
  598. data/lib/tasker/types/step_template.rb +63 -0
  599. data/lib/tasker/types/task_request.rb +60 -0
  600. data/lib/tasker/types/telemetry_config.rb +273 -0
  601. data/lib/tasker/types.rb +64 -0
  602. data/lib/tasker/version.rb +7 -0
  603. data/lib/tasker.rb +82 -0
  604. data/lib/tasks/tasker_tasks.rake +302 -0
  605. metadata +958 -0
@@ -0,0 +1,224 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'concurrent-ruby'
4
+ require 'singleton'
5
+
6
+ module Tasker
7
+ module Telemetry
8
+ # LogBackend provides thread-safe structured logging for events
9
+ #
10
+ # This class implements Tasker's core logging system with thread-safe operations,
11
+ # automatic EventRouter integration, and structured log data collection.
12
+ # It complements Rails logging with structured event data suitable for
13
+ # log aggregation systems like ELK, Splunk, or Fluentd.
14
+ #
15
+ # The backend follows the same singleton pattern as MetricsBackend for consistency
16
+ # and provides structured log data with correlation IDs and contextual information.
17
+ #
18
+ # @example Basic usage
19
+ # backend = LogBackend.instance
20
+ # backend.log_event('task.started', { task_id: '123', level: 'info' })
21
+ #
22
+ # @example EventRouter integration
23
+ # # Automatic log collection based on event routing
24
+ # backend.handle_event('task.failed', { task_id: '123', error: 'timeout', level: 'error' })
25
+ #
26
+ class LogBackend
27
+ include Singleton
28
+
29
+ # Core log storage for structured events
30
+ # Using ConcurrentHash for thread-safe operations without locks
31
+ # @return [Concurrent::Hash] Thread-safe log storage
32
+ attr_reader :logs
33
+
34
+ # Backend creation timestamp for monitoring
35
+ # @return [Time] When this backend was initialized
36
+ attr_reader :created_at
37
+
38
+ # Log levels in order of severity
39
+ LOG_LEVELS = %w[debug info warn error fatal].freeze
40
+
41
+ def initialize
42
+ @logs = Concurrent::Hash.new { |h, k| h[k] = Concurrent::Array.new }
43
+ @created_at = Time.current
44
+ @instance_id = Socket.gethostname
45
+ end
46
+
47
+ # Handle an event from EventRouter and collect appropriate log data
48
+ #
49
+ # This method is called by EventRouter when an event should be routed to
50
+ # the log backend. It automatically creates structured log entries based on
51
+ # event type and payload.
52
+ #
53
+ # @param event_name [String] The lifecycle event name
54
+ # @param payload [Hash] Event payload with log data
55
+ # @return [Boolean] True if log data was collected successfully
56
+ #
57
+ # @example Automatic usage via EventRouter
58
+ # # EventRouter calls this automatically:
59
+ # backend.handle_event('task.failed', {
60
+ # task_id: '123',
61
+ # error: 'Payment gateway timeout',
62
+ # context: { user_id: 456, amount: 100.0 }
63
+ # })
64
+ #
65
+ def handle_event(event_name, payload = {})
66
+ return false unless payload.is_a?(Hash)
67
+
68
+ log_entry = {
69
+ timestamp: Time.current.iso8601,
70
+ event_name: event_name,
71
+ level: determine_log_level(event_name),
72
+ message: build_log_message(event_name, payload),
73
+ payload: payload,
74
+ instance_id: @instance_id,
75
+ correlation_id: extract_correlation_id(payload)
76
+ }
77
+
78
+ # Store log entry by level for organized retrieval
79
+ level = log_entry[:level]
80
+ @logs[level] << log_entry
81
+
82
+ # Also store in chronological order
83
+ @logs[:all] << log_entry
84
+
85
+ true
86
+ rescue StandardError => e
87
+ # Log error but don't raise to prevent breaking the event flow
88
+ Rails.logger&.error("LogBackend error handling #{event_name}: #{e.message}")
89
+ false
90
+ end
91
+
92
+ # Export all collected log data
93
+ #
94
+ # @param level [String, nil] Specific log level to export, or nil for all
95
+ # @return [Hash] Log data with metadata
96
+ def export(level: nil)
97
+ logs_to_export = if level && LOG_LEVELS.include?(level.to_s)
98
+ { level.to_s => @logs[level.to_s].to_a }
99
+ else
100
+ @logs.each_with_object({}) { |(k, v), h| h[k.to_s] = v.to_a }
101
+ end
102
+
103
+ {
104
+ logs: logs_to_export,
105
+ metadata: {
106
+ backend: 'log',
107
+ instance_id: @instance_id,
108
+ created_at: @created_at.iso8601,
109
+ exported_at: Time.current.iso8601,
110
+ total_entries: @logs[:all]&.size || 0,
111
+ level_counts: LOG_LEVELS.index_with { |l| @logs[l]&.size || 0 }
112
+ }
113
+ }
114
+ end
115
+
116
+ # Clear all log data (primarily for testing)
117
+ #
118
+ # @return [void]
119
+ def reset!
120
+ @logs.clear
121
+ end
122
+
123
+ # Get log statistics
124
+ #
125
+ # @return [Hash] Statistics about collected logs
126
+ def stats
127
+ {
128
+ total_entries: @logs[:all]&.size || 0,
129
+ level_counts: LOG_LEVELS.index_with { |level| @logs[level]&.size || 0 },
130
+ backend_uptime: Time.current - @created_at,
131
+ instance_id: @instance_id
132
+ }
133
+ end
134
+
135
+ # Get recent log entries
136
+ #
137
+ # @param limit [Integer] Number of recent entries to return
138
+ # @param level [String, nil] Specific log level to filter by
139
+ # @return [Array<Hash>] Recent log entries
140
+ def recent_entries(limit: 100, level: nil)
141
+ entries = if level && LOG_LEVELS.include?(level.to_s)
142
+ @logs[level.to_s].to_a
143
+ else
144
+ @logs[:all].to_a
145
+ end
146
+
147
+ entries.last(limit)
148
+ end
149
+
150
+ private
151
+
152
+ def determine_log_level(event_name)
153
+ case event_name
154
+ when /\.failed$/, /\.error$/
155
+ 'error'
156
+ when /\.warn$/, /\.warning$/
157
+ 'warn'
158
+ when /\.started$/, /\.completed$/
159
+ 'info'
160
+ when /\.debug$/, /\.trace$/
161
+ 'debug'
162
+ else
163
+ 'info'
164
+ end
165
+ end
166
+
167
+ def build_log_message(event_name, payload)
168
+ # Create a human-readable message from the event and payload
169
+ entity_type = extract_entity_type(event_name)
170
+ action = extract_action(event_name)
171
+
172
+ base_message = "#{entity_type.capitalize} #{action}"
173
+
174
+ # Add key details from payload
175
+ details = []
176
+ details << "ID: #{payload[:task_id]}" if payload[:task_id]
177
+ details << "Step: #{payload[:workflow_step_id]}" if payload[:workflow_step_id]
178
+ details << "Error: #{payload[:error]}" if payload[:error]
179
+ details << "Duration: #{payload[:duration]}s" if payload[:duration]
180
+
181
+ details.empty? ? base_message : "#{base_message} (#{details.join(', ')})"
182
+ end
183
+
184
+ def extract_entity_type(event_name)
185
+ case event_name
186
+ when /^task\./
187
+ 'task'
188
+ when /^step\./
189
+ 'step'
190
+ when /^workflow\./
191
+ 'workflow'
192
+ else
193
+ 'system'
194
+ end
195
+ end
196
+
197
+ def extract_action(event_name)
198
+ case event_name
199
+ when /\.started$/
200
+ 'started'
201
+ when /\.completed$/
202
+ 'completed'
203
+ when /\.failed$/
204
+ 'failed'
205
+ when /\.before_/
206
+ 'preparing'
207
+ when /\.after_/
208
+ 'finished'
209
+ else
210
+ 'event'
211
+ end
212
+ end
213
+
214
+ def extract_correlation_id(payload)
215
+ # Extract correlation ID for log tracing
216
+ payload[:correlation_id] ||
217
+ payload[:request_id] ||
218
+ payload[:task_id] ||
219
+ payload[:workflow_step_id] ||
220
+ SecureRandom.uuid
221
+ end
222
+ end
223
+ end
224
+ end
@@ -0,0 +1,368 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'concurrent-ruby'
4
+
5
+ module Tasker
6
+ module Telemetry
7
+ # MetricTypes provides thread-safe metric storage classes for high-performance telemetry
8
+ #
9
+ # This module implements the core metric types for Tasker's native metrics collection
10
+ # backend. All metric types are thread-safe using atomic operations and follow
11
+ # Tasker's fail-fast principles with explicit error handling.
12
+ #
13
+ # @example Basic metric operations
14
+ # counter = Counter.new('tasks_completed')
15
+ # counter.increment # +1
16
+ # counter.increment(5) # +5
17
+ # counter.value # → current count
18
+ #
19
+ # @example Gauge operations
20
+ # gauge = Gauge.new('active_tasks')
21
+ # gauge.set(42) # Set to specific value
22
+ # gauge.increment # +1
23
+ # gauge.decrement(3) # -3
24
+ #
25
+ module MetricTypes
26
+ # Counter represents a monotonically increasing metric value
27
+ #
28
+ # Counters are thread-safe and use atomic operations for increment operations.
29
+ # They follow the fail-fast principle with explicit validation and meaningful
30
+ # error messages for invalid operations.
31
+ #
32
+ # @example Production usage
33
+ # counter = Counter.new('api_requests_total', labels: { endpoint: '/tasks' })
34
+ # counter.increment # Increment by 1
35
+ # counter.increment(batch_size) # Increment by batch size
36
+ # counter.value # Get current value (thread-safe read)
37
+ #
38
+ class Counter
39
+ # @return [String] The metric name
40
+ attr_reader :name
41
+
42
+ # @return [Hash] The metric labels for dimensional data
43
+ attr_reader :labels
44
+
45
+ # @return [Time] When this metric was first created
46
+ attr_reader :created_at
47
+
48
+ # Initialize a new counter metric
49
+ #
50
+ # @param name [String] The metric name (must be present)
51
+ # @param labels [Hash] Optional labels for dimensional metrics
52
+ # @raise [ArgumentError] If name is nil or empty
53
+ def initialize(name, labels: {})
54
+ raise ArgumentError, 'Metric name cannot be nil or empty' if name.nil? || name.strip.empty?
55
+
56
+ @name = name.to_s.freeze
57
+ @labels = labels.freeze
58
+ @value = Concurrent::AtomicFixnum.new(0)
59
+ @created_at = Time.current.freeze
60
+ end
61
+
62
+ # Increment the counter by a specified amount
63
+ #
64
+ # @param amount [Integer] Amount to increment (must be non-negative)
65
+ # @return [Integer] The new counter value
66
+ # @raise [ArgumentError] If amount is negative or not an integer
67
+ def increment(amount = 1)
68
+ return false unless amount.is_a?(Integer)
69
+ raise ArgumentError, "Counter increment amount must be positive, got: #{amount}" if amount.negative?
70
+
71
+ @value.update { |current| current + amount }
72
+ end
73
+
74
+ # Get the current counter value (thread-safe read)
75
+ #
76
+ # @return [Integer] Current counter value
77
+ delegate :value, to: :@value
78
+
79
+ # Reset the counter to zero (primarily for testing)
80
+ #
81
+ # @return [Integer] The reset value (0)
82
+ def reset!
83
+ @value.value = 0
84
+ end
85
+
86
+ # Get a hash representation of this metric
87
+ #
88
+ # @return [Hash] Metric data including name, labels, value, type
89
+ def to_h
90
+ {
91
+ name: name,
92
+ labels: labels,
93
+ value: value,
94
+ type: :counter,
95
+ created_at: created_at
96
+ }
97
+ end
98
+
99
+ # Get a description of this metric for debugging
100
+ #
101
+ # @return [String] Human-readable description
102
+ def description
103
+ label_str = labels.empty? ? '' : labels.inspect
104
+ "#{name}#{label_str} = #{value} (counter)"
105
+ end
106
+ end
107
+
108
+ # Gauge represents a metric value that can go up or down
109
+ #
110
+ # Gauges are thread-safe and support atomic set, increment, and decrement
111
+ # operations. They follow fail-fast principles with explicit validation.
112
+ #
113
+ # @example Production usage
114
+ # gauge = Gauge.new('active_connections')
115
+ # gauge.set(100) # Set to specific value
116
+ # gauge.increment(5) # +5 connections
117
+ # gauge.decrement(2) # -2 connections
118
+ # gauge.value # Get current value
119
+ #
120
+ class Gauge
121
+ # @return [String] The metric name
122
+ attr_reader :name
123
+
124
+ # @return [Hash] The metric labels for dimensional data
125
+ attr_reader :labels
126
+
127
+ # @return [Time] When this metric was first created
128
+ attr_reader :created_at
129
+
130
+ # Initialize a new gauge metric
131
+ #
132
+ # @param name [String] The metric name (must be present)
133
+ # @param labels [Hash] Optional labels for dimensional metrics
134
+ # @param initial_value [Numeric] Initial gauge value
135
+ # @raise [ArgumentError] If name is nil or empty, or initial_value is not numeric
136
+ def initialize(name, labels: {}, initial_value: 0)
137
+ raise ArgumentError, 'Metric name cannot be nil or empty' if name.nil? || name.strip.empty?
138
+
139
+ unless initial_value.is_a?(Numeric)
140
+ raise ArgumentError,
141
+ "Initial value must be numeric, got: #{initial_value.class}"
142
+ end
143
+
144
+ @name = name.to_s.freeze
145
+ @labels = labels.freeze
146
+ @value = Concurrent::AtomicReference.new(initial_value)
147
+ @created_at = Time.current.freeze
148
+ end
149
+
150
+ # Set the gauge to a specific value
151
+ #
152
+ # @param new_value [Numeric] The new gauge value
153
+ # @return [Numeric] The new gauge value
154
+ # @raise [ArgumentError] If new_value is not numeric
155
+ def set(new_value)
156
+ raise ArgumentError, "Gauge value must be numeric, got: #{new_value.class}" unless new_value.is_a?(Numeric)
157
+
158
+ @value.set(new_value)
159
+ new_value
160
+ end
161
+
162
+ # Increment the gauge by a specified amount
163
+ #
164
+ # @param amount [Numeric] Amount to increment (can be negative)
165
+ # @return [Numeric] The new gauge value
166
+ # @raise [ArgumentError] If amount is not numeric
167
+ def increment(amount = 1)
168
+ unless amount.is_a?(Numeric)
169
+ raise ArgumentError,
170
+ "Gauge increment amount must be numeric, got: #{amount.class}"
171
+ end
172
+
173
+ @value.update { |current| current + amount }
174
+ end
175
+
176
+ # Decrement the gauge by a specified amount
177
+ #
178
+ # @param amount [Numeric] Amount to decrement (must be positive)
179
+ # @return [Numeric] The new gauge value
180
+ # @raise [ArgumentError] If amount is not numeric or is negative
181
+ def decrement(amount = 1)
182
+ unless amount.is_a?(Numeric)
183
+ raise ArgumentError,
184
+ "Gauge decrement amount must be numeric, got: #{amount.class}"
185
+ end
186
+ raise ArgumentError, "Gauge decrement amount must be positive, got: #{amount}" if amount.negative?
187
+
188
+ increment(-amount)
189
+ end
190
+
191
+ # Get the current gauge value (thread-safe read)
192
+ #
193
+ # @return [Numeric] Current gauge value
194
+ def value
195
+ @value.get
196
+ end
197
+
198
+ # Get a hash representation of this metric
199
+ #
200
+ # @return [Hash] Metric data including name, labels, value, type
201
+ def to_h
202
+ {
203
+ name: name,
204
+ labels: labels,
205
+ value: value,
206
+ type: :gauge,
207
+ created_at: created_at
208
+ }
209
+ end
210
+
211
+ # Get a description of this metric for debugging
212
+ #
213
+ # @return [String] Human-readable description
214
+ def description
215
+ label_str = labels.empty? ? '' : labels.inspect
216
+ "#{name}#{label_str} = #{value} (gauge)"
217
+ end
218
+ end
219
+
220
+ # Histogram represents a metric that samples observations and counts them in buckets
221
+ #
222
+ # Histograms are thread-safe and provide statistical analysis of observed values.
223
+ # They track count, sum, and bucket distributions for duration and size metrics.
224
+ #
225
+ # @example Production usage
226
+ # histogram = Histogram.new('task_duration_seconds', buckets: [0.1, 0.5, 1.0, 5.0])
227
+ # histogram.observe(0.45) # Record a 0.45 second duration
228
+ # histogram.observe(2.1) # Record a 2.1 second duration
229
+ # histogram.count # Total observations
230
+ # histogram.sum # Sum of all observed values
231
+ # histogram.buckets # Bucket counts
232
+ #
233
+ class Histogram
234
+ # @return [String] The metric name
235
+ attr_reader :name
236
+
237
+ # @return [Hash] The metric labels for dimensional data
238
+ attr_reader :labels
239
+
240
+ # @return [Array<Numeric>] The histogram bucket boundaries
241
+ attr_reader :bucket_boundaries
242
+
243
+ # @return [Time] When this metric was first created
244
+ attr_reader :created_at
245
+
246
+ # Default bucket boundaries for duration metrics (in seconds)
247
+ DEFAULT_BUCKETS = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0].freeze
248
+
249
+ # Initialize a new histogram metric
250
+ #
251
+ # @param name [String] The metric name (must be present)
252
+ # @param labels [Hash] Optional labels for dimensional metrics
253
+ # @param buckets [Array<Numeric>] Bucket boundaries (must be sorted ascending)
254
+ # @raise [ArgumentError] If name is nil/empty or buckets are invalid
255
+ def initialize(name, labels: {}, buckets: DEFAULT_BUCKETS)
256
+ raise ArgumentError, 'Metric name cannot be nil or empty' if name.nil? || name.strip.empty?
257
+ raise ArgumentError, 'Buckets must be an array' unless buckets.is_a?(Array)
258
+ raise ArgumentError, 'Buckets cannot be empty' if buckets.empty?
259
+
260
+ @name = name.to_s.freeze
261
+ @labels = labels.freeze
262
+ @bucket_boundaries = buckets.sort.freeze
263
+ @created_at = Time.current.freeze
264
+
265
+ # Thread-safe counters for each bucket + infinity bucket
266
+ @bucket_counts = (@bucket_boundaries + [Float::INFINITY]).map do |_|
267
+ Concurrent::AtomicFixnum.new(0)
268
+ end
269
+
270
+ @count = Concurrent::AtomicFixnum.new(0)
271
+ @sum = Concurrent::AtomicReference.new(0.0)
272
+ end
273
+
274
+ # Observe a value and update histogram buckets
275
+ #
276
+ # @param value [Numeric] The observed value
277
+ # @return [Numeric] The observed value (for chaining)
278
+ # @raise [ArgumentError] If value is not numeric
279
+ def observe(value)
280
+ raise ArgumentError, "Observed value must be numeric, got: #{value.class}" unless value.is_a?(Numeric)
281
+
282
+ # Update count and sum atomically
283
+ @count.increment
284
+ @sum.update { |current| current + value }
285
+
286
+ # Increment all buckets where value <= boundary (cumulative histogram)
287
+ @bucket_boundaries.each_with_index do |boundary, index|
288
+ @bucket_counts[index].increment if value <= boundary
289
+ end
290
+
291
+ # Always increment the infinity bucket (total count)
292
+ @bucket_counts.last.increment
293
+
294
+ value
295
+ end
296
+
297
+ # Get the total number of observations
298
+ #
299
+ # @return [Integer] Total observation count
300
+ def count
301
+ @count.value
302
+ end
303
+
304
+ # Get the sum of all observed values
305
+ #
306
+ # @return [Numeric] Sum of observations
307
+ def sum
308
+ @sum.get
309
+ end
310
+
311
+ # Get the current bucket counts
312
+ #
313
+ # @return [Hash] Bucket boundaries to counts mapping
314
+ def buckets
315
+ result = {}
316
+ @bucket_boundaries.each_with_index do |boundary, index|
317
+ result[boundary] = @bucket_counts[index].value
318
+ end
319
+ result[Float::INFINITY] = @bucket_counts.last.value
320
+ result
321
+ end
322
+
323
+ # Calculate the average of observed values
324
+ #
325
+ # @return [Float] Average value, or 0.0 if no observations
326
+ def average
327
+ current_count = count
328
+ return 0.0 if current_count.zero?
329
+
330
+ sum.to_f / current_count
331
+ end
332
+
333
+ # Get a hash representation of this metric
334
+ #
335
+ # @return [Hash] Metric data including name, labels, buckets, count, sum, type
336
+ def to_h
337
+ {
338
+ name: name,
339
+ labels: labels,
340
+ buckets: buckets,
341
+ count: count,
342
+ sum: sum,
343
+ average: average,
344
+ type: :histogram,
345
+ created_at: created_at
346
+ }
347
+ end
348
+
349
+ # Get a description of this metric for debugging
350
+ #
351
+ # @return [String] Human-readable description
352
+ def description
353
+ label_str = labels.empty? ? '' : labels.inspect
354
+ "#{name}#{label_str} = #{count} observations, avg: #{average.round(3)} (histogram)"
355
+ end
356
+
357
+ # Reset the histogram (primarily for testing)
358
+ #
359
+ # @return [void]
360
+ def reset!
361
+ @count.value = 0
362
+ @sum.set(0.0)
363
+ @bucket_counts.each { |bucket| bucket.value = 0 }
364
+ end
365
+ end
366
+ end
367
+ end
368
+ end