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,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_subscriber'
4
+
5
+ module Tasker
6
+ module Events
7
+ module Subscribers
8
+ # MetricsSubscriber bridges events to the EventRouter for automatic metrics collection
9
+ #
10
+ # This subscriber is the critical bridge between Tasker's event publishing system
11
+ # and the EventRouter-based metrics collection. It subscribes to all events that
12
+ # should route to metrics and forwards them to EventRouter.route_event().
13
+ #
14
+ # Architecture:
15
+ # - TelemetrySubscriber: Creates OpenTelemetry spans for debugging
16
+ # - MetricsSubscriber: Routes events to EventRouter for metrics collection
17
+ # - EventRouter: Intelligent routing to MetricsBackend based on configuration
18
+ # - MetricsBackend: Thread-safe native metrics storage
19
+ #
20
+ # This subscriber automatically subscribes to all events configured in EventRouter
21
+ # that route to metrics, ensuring zero-configuration metrics collection.
22
+ class MetricsSubscriber < BaseSubscriber
23
+ def initialize
24
+ super
25
+ @event_router = Tasker::Telemetry::EventRouter.instance
26
+
27
+ # Dynamically subscribe to all events that route to metrics
28
+ subscribe_to_metrics_events
29
+ end
30
+
31
+ # Handle any event by routing it through EventRouter
32
+ #
33
+ # This is a catch-all handler that routes events to the EventRouter
34
+ # based on the configured mappings.
35
+ #
36
+ # @param event_name [String] The event name
37
+ # @param event [Hash, Dry::Events::Event] The event payload
38
+ # @return [void]
39
+ def handle_event(event_name, event)
40
+ return unless should_process_event?(event_name)
41
+
42
+ # Extract payload from event object if needed
43
+ payload = event.respond_to?(:payload) ? event.payload : event
44
+
45
+ # Route to EventRouter for intelligent backend routing
46
+ @event_router.route_event(event_name, payload)
47
+ end
48
+
49
+ # Override method_missing to handle dynamic event methods
50
+ #
51
+ # Since we subscribe to events dynamically, we need to handle
52
+ # the resulting method calls dynamically as well.
53
+ #
54
+ # @param method_name [Symbol] The method name
55
+ # @param args [Array] Method arguments
56
+ # @return [void]
57
+ def method_missing(method_name, *args)
58
+ if method_name.to_s.start_with?('handle_')
59
+ # Extract event name from method name
60
+ event_name = method_name.to_s.sub(/^handle_/, '').tr('_', '.')
61
+ handle_event(event_name, args.first)
62
+ else
63
+ super
64
+ end
65
+ end
66
+
67
+ # Check if we respond to dynamic event handler methods
68
+ #
69
+ # @param method_name [Symbol] The method name
70
+ # @param include_private [Boolean] Whether to include private methods
71
+ # @return [Boolean] True if we respond to the method
72
+ def respond_to_missing?(method_name, include_private = false)
73
+ method_name.to_s.start_with?('handle_') || super
74
+ end
75
+
76
+ # Override BaseSubscriber to check EventRouter configuration
77
+ #
78
+ # @param event_constant [String] The event constant or name
79
+ # @return [Boolean] True if the event should be processed
80
+ def should_process_event?(event_constant)
81
+ # Only process if telemetry is enabled
82
+ return false unless Tasker.configuration.telemetry.enabled
83
+
84
+ # Convert constant to event name if needed
85
+ event_name = event_constant.respond_to?(:name) ? event_constant.name : event_constant.to_s
86
+
87
+ # Check if EventRouter routes this event to metrics
88
+ @event_router.routes_to_metrics?(event_name)
89
+ end
90
+
91
+ private
92
+
93
+ # Subscribe to all events that route to metrics
94
+ #
95
+ # This method dynamically subscribes to events based on EventRouter configuration
96
+ # @return [void]
97
+ def subscribe_to_metrics_events
98
+ metrics_events = @event_router.events_for_backend(:metrics)
99
+
100
+ # Convert event names to constants and subscribe
101
+ event_constants = metrics_events.filter_map do |event_name|
102
+ # Convert dot notation to constant path
103
+ constant_path = event_name.split('.').map(&:upcase).join('::')
104
+
105
+ begin
106
+ # Try to resolve the constant
107
+ Tasker::Constants.const_get(constant_path)
108
+ rescue NameError
109
+ # If constant doesn't exist, use the string directly
110
+ event_name
111
+ end
112
+ end
113
+
114
+ # Subscribe to the events
115
+ self.class.subscribe_to(*event_constants) unless event_constants.empty?
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,462 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../constants'
4
+ require_relative 'base_subscriber'
5
+
6
+ module Tasker
7
+ module Events
8
+ module Subscribers
9
+ # TelemetrySubscriber handles telemetry events for observability
10
+ #
11
+ # This subscriber creates OpenTelemetry spans with proper hierarchical context
12
+ # for distributed tracing in systems like Jaeger. It follows OpenTelemetry
13
+ # best practices by creating detailed spans for debugging while allowing
14
+ # metrics to be derived from span data.
15
+ #
16
+ # Architecture Decision:
17
+ # - SPANS: Individual trace records for detailed debugging (this class)
18
+ # - METRICS: Aggregated data for dashboards/alerts (derived from spans or separate collectors)
19
+ class TelemetrySubscriber < BaseSubscriber
20
+ attr_accessor :tracer
21
+
22
+ # Use actual constants for consistent subscription (no string literals)
23
+ subscribe_to Tasker::Constants::TaskEvents::INITIALIZE_REQUESTED,
24
+ Tasker::Constants::TaskEvents::START_REQUESTED,
25
+ Tasker::Constants::TaskEvents::COMPLETED,
26
+ Tasker::Constants::TaskEvents::FAILED,
27
+ Tasker::Constants::StepEvents::EXECUTION_REQUESTED,
28
+ Tasker::Constants::StepEvents::COMPLETED,
29
+ Tasker::Constants::StepEvents::FAILED,
30
+ Tasker::Constants::StepEvents::RETRY_REQUESTED
31
+
32
+ def initialize
33
+ super
34
+ @tracer = create_tracer
35
+ end
36
+
37
+ # Handle task initialization events
38
+ def handle_task_initialize_requested(event)
39
+ return unless should_process_event?(Tasker::Constants::TaskEvents::INITIALIZE_REQUESTED)
40
+
41
+ attributes = extract_core_attributes(event).merge(
42
+ task_name: safe_get(event, :task_name, 'unknown_task')
43
+ )
44
+
45
+ # Only create basic span for initialization - task.start_requested will create the main span
46
+ create_simple_span(event, 'tasker.task.initialize', attributes)
47
+ end
48
+
49
+ # Handle task start events
50
+ def handle_task_start_requested(event)
51
+ return unless should_process_event?(Tasker::Constants::TaskEvents::START_REQUESTED)
52
+
53
+ attributes = extract_core_attributes(event).merge(
54
+ task_name: safe_get(event, :task_name, 'unknown_task')
55
+ )
56
+
57
+ # Create root span for task and store it for child spans
58
+ create_task_span(event, 'tasker.task.execution', attributes)
59
+ end
60
+
61
+ # Handle task completion events
62
+ def handle_task_completed(event)
63
+ return unless should_process_event?(Tasker::Constants::TaskEvents::COMPLETED)
64
+
65
+ attributes = extract_core_attributes(event).merge(
66
+ task_name: safe_get(event, :task_name, 'unknown_task'),
67
+ duration: calculate_duration(event),
68
+ total_execution_duration: safe_get(event, :total_execution_duration, 0.0),
69
+ current_execution_duration: safe_get(event, :current_execution_duration, 0.0),
70
+ total_steps: safe_get(event, :total_steps, 0),
71
+ completed_steps: safe_get(event, :completed_steps, 0)
72
+ )
73
+
74
+ # Finish the task span with success status
75
+ finish_task_span(event, :ok, attributes)
76
+ end
77
+
78
+ # Handle task failure events
79
+ def handle_task_failed(event)
80
+ return unless should_process_event?(Tasker::Constants::TaskEvents::FAILED)
81
+
82
+ attributes = extract_core_attributes(event).merge(
83
+ task_name: safe_get(event, :task_name, 'unknown_task'),
84
+ error: safe_get(event, :error_message, safe_get(event, :error, 'Unknown error')),
85
+ exception_class: safe_get(event, :exception_class, 'StandardError'),
86
+ failed_steps: safe_get(event, :failed_steps, 0)
87
+ )
88
+
89
+ # Finish the task span with error status
90
+ finish_task_span(event, :error, attributes)
91
+ end
92
+
93
+ # Handle step execution requested events
94
+ def handle_step_execution_requested(event)
95
+ return unless should_process_event?(Tasker::Constants::StepEvents::EXECUTION_REQUESTED)
96
+
97
+ attributes = extract_step_attributes(event).merge(
98
+ attempt_number: safe_get(event, :attempt_number, 1)
99
+ )
100
+
101
+ # Create a simple span for step queuing
102
+ create_simple_span(event, 'tasker.step.queued', attributes)
103
+ end
104
+
105
+ # Handle step completion events
106
+ def handle_step_completed(event)
107
+ return unless should_process_event?(Tasker::Constants::StepEvents::COMPLETED)
108
+
109
+ attributes = extract_step_attributes(event).merge(
110
+ execution_duration: safe_get(event, :execution_duration, 0.0),
111
+ attempt_number: safe_get(event, :attempt_number, 1)
112
+ )
113
+
114
+ # Create step span as child of task span
115
+ create_step_span(event, 'tasker.step.execution', attributes, :ok)
116
+ end
117
+
118
+ # Handle step failure events
119
+ def handle_step_failed(event)
120
+ return unless should_process_event?(Tasker::Constants::StepEvents::FAILED)
121
+
122
+ attributes = extract_step_attributes(event).merge(
123
+ error: safe_get(event, :error_message, safe_get(event, :error, 'Unknown error')),
124
+ attempt_number: safe_get(event, :attempt_number, 1),
125
+ exception_class: safe_get(event, :exception_class, 'StandardError'),
126
+ retry_limit: safe_get(event, :retry_limit, 3)
127
+ )
128
+
129
+ # Create step span as child of task span with error status
130
+ create_step_span(event, 'tasker.step.execution', attributes, :error)
131
+ end
132
+
133
+ # Handle step retry events
134
+ def handle_step_retry_requested(event)
135
+ return unless should_process_event?(Tasker::Constants::StepEvents::RETRY_REQUESTED)
136
+
137
+ attributes = extract_step_attributes(event).merge(
138
+ attempt_number: safe_get(event, :attempt_number, 1),
139
+ retry_limit: safe_get(event, :retry_limit, 3)
140
+ )
141
+
142
+ # Create a simple span for retry events
143
+ create_simple_span(event, 'tasker.step.retry', attributes)
144
+ end
145
+
146
+ # Override BaseSubscriber to add telemetry-specific filtering
147
+ def should_process_event?(event_constant)
148
+ # Get configuration once for efficiency
149
+ config = Tasker.configuration
150
+
151
+ # Only process if telemetry is enabled
152
+ return false unless config.telemetry.enabled
153
+
154
+ super
155
+ end
156
+
157
+ # Extract step-specific attributes (enhanced from BaseSubscriber)
158
+ def extract_step_attributes(event)
159
+ super.merge(
160
+ step_name: safe_get(event, :step_name, 'unknown_step')
161
+ )
162
+ end
163
+
164
+ # Check if telemetry is enabled
165
+ def telemetry_enabled?
166
+ Tasker.configuration.telemetry.enabled != false
167
+ end
168
+
169
+ # Create a simple span for events that don't need complex hierarchy
170
+ #
171
+ # @param event [Hash] The event data
172
+ # @param span_name [String] The name for the span
173
+ # @param attributes [Hash] Span attributes
174
+ def create_simple_span(event, span_name, attributes)
175
+ return unless opentelemetry_available?
176
+
177
+ otel_attributes = convert_attributes_for_otel(attributes)
178
+
179
+ tracer.in_span(span_name, attributes: otel_attributes) do |span|
180
+ # Add event annotation
181
+ span.add_event(event_to_annotation_name(event), attributes: otel_attributes)
182
+ end
183
+ rescue StandardError => e
184
+ Rails.logger.warn("Failed to create simple span: #{e.message}")
185
+ end
186
+
187
+ # Create a root span for a task and store it for child spans
188
+ #
189
+ # @param event [Hash] The event data
190
+ # @param span_name [String] The name for the span
191
+ # @param attributes [Hash] Span attributes
192
+ def create_task_span(event, span_name, attributes)
193
+ return unless opentelemetry_available?
194
+
195
+ task_id = safe_get(event, :task_id)
196
+ return unless task_id
197
+
198
+ otel_attributes = convert_attributes_for_otel(attributes)
199
+
200
+ span = tracer.start_root_span(span_name, attributes: otel_attributes)
201
+ store_task_span(task_id, span)
202
+
203
+ # Add an event to mark the task start
204
+ span.add_event('task.started', attributes: otel_attributes)
205
+ rescue StandardError => e
206
+ Rails.logger.warn("Failed to create task span: #{e.message}")
207
+ end
208
+
209
+ # Finish a task span with the appropriate status
210
+ #
211
+ # @param event [Hash] The event data
212
+ # @param status [Symbol] The span status (:ok or :error)
213
+ # @param attributes [Hash] Final span attributes
214
+ def finish_task_span(event, status, attributes)
215
+ return unless opentelemetry_available?
216
+
217
+ task_id = safe_get(event, :task_id)
218
+ return unless task_id
219
+
220
+ span = get_task_span(task_id)
221
+ return unless span
222
+
223
+ otel_attributes = convert_attributes_for_otel(attributes)
224
+
225
+ # Add completion event
226
+ event_name = status == :error ? 'task.failed' : 'task.completed'
227
+ span.add_event(event_name, attributes: otel_attributes)
228
+
229
+ # Set span status
230
+ set_span_status(span, status, attributes)
231
+
232
+ # Finish the span
233
+ span.finish
234
+ remove_task_span(task_id)
235
+ rescue StandardError => e
236
+ Rails.logger.warn("Failed to finish task span: #{e.message}")
237
+ end
238
+
239
+ # Create a step span as a child of the task span
240
+ #
241
+ # @param event [Hash] The event data
242
+ # @param span_name [String] The name for the span
243
+ # @param attributes [Hash] Span attributes
244
+ # @param status [Symbol] The span status (:ok or :error)
245
+ def create_step_span(event, span_name, attributes, status)
246
+ return unless opentelemetry_available?
247
+
248
+ task_id = safe_get(event, :task_id)
249
+ step_id = safe_get(event, :step_id)
250
+ return unless task_id && step_id
251
+
252
+ task_span = get_task_span(task_id)
253
+ return unless task_span
254
+
255
+ otel_attributes = convert_attributes_for_otel(attributes)
256
+
257
+ # Create child span context
258
+ span_context = ::OpenTelemetry::Trace.context_with_span(task_span)
259
+
260
+ ::OpenTelemetry::Context.with_current(span_context) do
261
+ tracer.in_span(span_name, attributes: otel_attributes) do |step_span|
262
+ # Add step event
263
+ event_name = status == :error ? 'step.failed' : 'step.completed'
264
+ step_span.add_event(event_name, attributes: otel_attributes)
265
+
266
+ # Set span status
267
+ set_span_status(step_span, status, attributes)
268
+ end
269
+ end
270
+ rescue StandardError => e
271
+ Rails.logger.warn("Failed to create step span: #{e.message}")
272
+ end
273
+
274
+ # Event type to annotation name mapping
275
+ EVENT_ANNOTATION_MAP = {
276
+ 'initialize_requested' => 'task.initialize',
277
+ 'execution_requested' => 'step.queued',
278
+ 'retry_requested' => 'step.retry'
279
+ }.freeze
280
+
281
+ # Convert event to annotation name
282
+ def event_to_annotation_name(event)
283
+ # Simple mapping from event to annotation
284
+ event_type = safe_get(event, :event_type)
285
+ EVENT_ANNOTATION_MAP.fetch(event_type, 'event.processed')
286
+ end
287
+
288
+ # Check if OpenTelemetry is available and configured
289
+ #
290
+ # @return [Boolean] True if OpenTelemetry is available
291
+ def opentelemetry_available?
292
+ defined?(::OpenTelemetry) && ::OpenTelemetry.tracer_provider
293
+ end
294
+
295
+ # Create the OpenTelemetry tracer
296
+ #
297
+ # @return [OpenTelemetry::Tracer] The tracer instance
298
+ def create_tracer
299
+ config = Tasker.configuration
300
+ ::OpenTelemetry.tracer_provider.tracer(
301
+ config.telemetry.service_name,
302
+ config.telemetry.service_version
303
+ )
304
+ end
305
+
306
+ # Convert event attributes to OpenTelemetry format
307
+ #
308
+ # @param attributes [Hash] The attributes to convert
309
+ # @return [Hash] OpenTelemetry-compatible attributes
310
+ def convert_attributes_for_otel(attributes)
311
+ result = {}
312
+ config = Tasker.configuration
313
+ service_name = config.telemetry.service_name
314
+
315
+ # Filter sensitive data first
316
+ filtered_attributes = filter_sensitive_attributes(attributes)
317
+
318
+ # Ensure attributes are properly formatted for OpenTelemetry
319
+ filtered_attributes.each do |key, value|
320
+ # Skip exception_object as it can't be properly serialized
321
+ next if key == :exception_object
322
+
323
+ # Use the configured service name as prefix for all attributes
324
+ attr_prefix = "#{service_name}."
325
+ attr_key = key.to_s.start_with?(attr_prefix) ? key.to_s : "#{attr_prefix}#{key}"
326
+
327
+ # Convert values based on their type
328
+ result[attr_key] = convert_value_for_otel(value)
329
+ end
330
+
331
+ result
332
+ end
333
+
334
+ private
335
+
336
+ # Convert value to OpenTelemetry-compatible format
337
+ #
338
+ # @param value [Object] The value to convert
339
+ # @return [String] OpenTelemetry-compatible value
340
+ def convert_value_for_otel(value)
341
+ case value
342
+ when Hash, Array
343
+ value.to_json
344
+ when nil
345
+ ''
346
+ else
347
+ value.to_s
348
+ end
349
+ end
350
+
351
+ # Set the span status based on the event status
352
+ #
353
+ # @param span [OpenTelemetry::Trace::Span] The span to set status on
354
+ # @param status [Symbol] The status (:ok or :error)
355
+ # @param attributes [Hash] The event attributes (for error message)
356
+ def set_span_status(span, status, attributes)
357
+ return unless defined?(::OpenTelemetry::Trace::Status)
358
+
359
+ if status == :error
360
+ error_msg = attributes[:error] || attributes[:error_message] || 'Unknown error'
361
+ span.status = ::OpenTelemetry::Trace::Status.error(error_msg)
362
+ elsif status == :ok
363
+ span.status = ::OpenTelemetry::Trace::Status.ok
364
+ end
365
+ rescue StandardError => e
366
+ Rails.logger.debug { "Failed to set span status: #{e.message}" }
367
+ end
368
+
369
+ # Filter sensitive data from attributes
370
+ #
371
+ # @param attributes [Hash] The attributes to filter
372
+ # @return [Hash] The filtered attributes
373
+ def filter_sensitive_attributes(attributes)
374
+ filter = Tasker.configuration.telemetry.parameter_filter
375
+ return attributes unless filter
376
+
377
+ filtered_data = {}
378
+ attributes.each do |key, value|
379
+ filtered_data[key] = if key == :exception_object
380
+ # Skip exception objects for filtering but preserve them
381
+ value
382
+ else
383
+ filter.filter_param(key.to_s, value)
384
+ end
385
+ end
386
+
387
+ filtered_data
388
+ end
389
+
390
+ # Get a hash of active spans for tasks
391
+ #
392
+ # @return [Hash<String, OpenTelemetry::Trace::Span>] Task spans
393
+ def task_spans
394
+ @task_spans ||= {}
395
+ end
396
+
397
+ # Store a span for a task
398
+ #
399
+ # @param task_id [String, Integer] The task ID
400
+ # @param span [OpenTelemetry::Trace::Span] The span to store
401
+ def store_task_span(task_id, span)
402
+ return unless task_id && span
403
+
404
+ task_spans[task_id.to_s] = span
405
+ end
406
+
407
+ # Get a span for a task
408
+ #
409
+ # @param task_id [String, Integer] The task ID
410
+ # @return [OpenTelemetry::Trace::Span, nil] The span or nil if not found
411
+ def get_task_span(task_id)
412
+ return nil unless task_id
413
+
414
+ task_spans[task_id.to_s]
415
+ end
416
+
417
+ # Remove a span for a task
418
+ #
419
+ # @param task_id [String, Integer] The task ID
420
+ def remove_task_span(task_id)
421
+ return unless task_id
422
+
423
+ task_spans.delete(task_id.to_s)
424
+ end
425
+
426
+ # Calculate duration from event timestamps with fallbacks
427
+ def calculate_duration(event)
428
+ started_at = safe_get(event, :started_at)
429
+ completed_at = safe_get(event, :completed_at)
430
+
431
+ return nil unless started_at && completed_at
432
+
433
+ # Handle different timestamp formats
434
+ start_time = parse_timestamp(started_at)
435
+ end_time = parse_timestamp(completed_at)
436
+
437
+ return nil unless start_time && end_time
438
+
439
+ (end_time - start_time).round(3)
440
+ rescue StandardError => e
441
+ Rails.logger.warn("Failed to calculate duration for telemetry: #{e.message}")
442
+ nil
443
+ end
444
+
445
+ # Parse timestamp in various formats
446
+ #
447
+ # @param timestamp [String, Time, DateTime] The timestamp to parse
448
+ # @return [Time, nil] The parsed time or nil if parsing fails
449
+ def parse_timestamp(timestamp)
450
+ return timestamp.to_time if timestamp.is_a?(Time) || timestamp.is_a?(DateTime)
451
+ if timestamp.is_a?(String) && timestamp.match?(/\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/)
452
+ return Time.zone.parse(timestamp)
453
+ end
454
+
455
+ nil
456
+ rescue StandardError
457
+ nil
458
+ end
459
+ end
460
+ end
461
+ end
462
+ end