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,601 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tasker
4
+ module Events
5
+ module Subscribers
6
+ # BaseSubscriber provides a clean foundation for creating custom event subscribers
7
+ #
8
+ # This class extracts common patterns from TelemetrySubscriber and provides:
9
+ # - Declarative subscription registration via class methods
10
+ # - Automatic method routing from event names to handler methods
11
+ # - Defensive payload handling with safe accessors
12
+ # - Easy integration with the Tasker event system
13
+ # - Metrics collection helper methods for common patterns
14
+ #
15
+ # Usage:
16
+ # class OrderNotificationSubscriber < Tasker::Events::Subscribers::BaseSubscriber
17
+ # subscribe_to :task_completed, :step_failed
18
+ #
19
+ # def handle_task_completed(event)
20
+ # OrderMailer.completion_email(event[:task_id]).deliver_later
21
+ # end
22
+ #
23
+ # def handle_step_failed(event)
24
+ # AlertService.notify("Step failed: #{event[:step_name]}")
25
+ # end
26
+ # end
27
+ #
28
+ # # Register the subscriber
29
+ # OrderNotificationSubscriber.subscribe(Tasker::Events::Publisher.instance)
30
+ class BaseSubscriber
31
+ class_attribute :subscribed_events, instance_writer: false, default: []
32
+ class_attribute :event_filter, instance_writer: false
33
+
34
+ def initialize(name: nil, events: nil, config: {})
35
+ @subscription_name = name
36
+ @subscription_config = config
37
+
38
+ # If events are provided via constructor (from YAML), add them to subscribed events
39
+ return if events.blank?
40
+
41
+ current_events = self.class.subscribed_events || []
42
+ self.class.subscribed_events = (current_events + Array(events)).uniq
43
+ end
44
+
45
+ class << self
46
+ # Declarative method to register events this subscriber cares about
47
+ #
48
+ # @param events [Array<Symbol, String>] Event names to subscribe to
49
+ # @return [void]
50
+ #
51
+ # Example:
52
+ # subscribe_to :task_completed, :step_failed
53
+ # subscribe_to 'order.created', 'payment.processed'
54
+ def subscribe_to(*events)
55
+ # Accumulate events instead of replacing them
56
+ current_events = subscribed_events || []
57
+ self.subscribed_events = (current_events + events.map(&:to_s)).uniq
58
+ end
59
+
60
+ # Set a filter for events (optional)
61
+ #
62
+ # @param filter_proc [Proc] A proc that returns true for events to process
63
+ # @return [void]
64
+ #
65
+ # Example:
66
+ # filter_events { |event_name| event_name.include?('order') }
67
+ def filter_events(&filter_proc)
68
+ self.event_filter = filter_proc
69
+ end
70
+
71
+ # Subscribe this subscriber to a publisher
72
+ #
73
+ # @param publisher [Tasker::Events::Publisher] The event publisher
74
+ # @return [BaseSubscriber] The subscriber instance
75
+ def subscribe(publisher)
76
+ subscriber = new
77
+ subscriber.subscribe_to_publisher(publisher)
78
+ subscriber
79
+ end
80
+ end
81
+
82
+ # Subscribe to all events defined by the class
83
+ #
84
+ # @param publisher [Tasker::Events::Publisher] The event publisher
85
+ # @return [void]
86
+ def subscribe_to_publisher(publisher)
87
+ event_subscriptions.each do |event_constant, handler_method|
88
+ # Apply filtering if defined
89
+ next unless should_handle_event?(event_constant)
90
+
91
+ # Subscribe to the event with automatic method routing
92
+ # This will fail fast if the event doesn't exist, which is the correct behavior
93
+ publisher.subscribe(event_constant, &method(handler_method))
94
+ end
95
+ end
96
+
97
+ protected
98
+
99
+ # Check if an event is a custom event (not a system constant)
100
+ #
101
+ # @param event_constant [String] The event constant or name
102
+ # @return [Boolean] Whether it's a custom event
103
+ def custom_event?(event_constant)
104
+ event_str = event_constant.to_s
105
+ event_str.exclude?('Tasker::Constants::') && event_str.include?('.')
106
+ end
107
+
108
+ # Get event subscriptions mapping for this subscriber
109
+ #
110
+ # This method maps event constants to handler methods using naming conventions.
111
+ # Override this method to customize the mapping.
112
+ #
113
+ # @return [Hash] Mapping of event constants to handler method symbols
114
+ def event_subscriptions
115
+ @event_subscriptions ||= build_event_subscriptions
116
+ end
117
+
118
+ # Build event subscriptions using explicit constants
119
+ #
120
+ # @return [Hash] Mapping of event constants to handler method symbols
121
+ def build_event_subscriptions
122
+ subscriptions = {}
123
+
124
+ (self.class.subscribed_events || []).each do |event_name|
125
+ # Convert developer-friendly name to internal constant
126
+ internal_constant = resolve_internal_event_constant(event_name)
127
+
128
+ # Generate handler method name: order.processed -> handle_order_processed
129
+ handler_method = generate_handler_method_name(event_name)
130
+
131
+ # Only add if the handler method exists
132
+ if respond_to?(handler_method, true)
133
+ subscriptions[internal_constant] = handler_method
134
+ else
135
+ Rails.logger.warn("#{self.class.name}: Handler method #{handler_method} not found for event #{event_name}")
136
+ end
137
+ end
138
+
139
+ subscriptions
140
+ end
141
+
142
+ # Resolve developer-friendly event name to internal constant
143
+ #
144
+ # This handles the transparent namespace mapping:
145
+ # - "order.processed" -> "custom.order.processed" (for custom events)
146
+ # - "task.completed" -> "task.completed" (for system events)
147
+ #
148
+ # @param event_name [String] The developer-friendly event name
149
+ # @return [String] The internal event constant
150
+ def resolve_internal_event_constant(event_name)
151
+ event_str = event_name.to_s
152
+
153
+ # Check if it's already an internal constant (starts with system prefixes)
154
+ system_prefixes = %w[task. step. workflow. observability.]
155
+ if system_prefixes.any? { |prefix| event_str.start_with?(prefix) }
156
+ return event_str # It's a system event, use as-is
157
+ end
158
+
159
+ # Check if it's already prefixed with custom.
160
+ if event_str.start_with?('custom.')
161
+ return event_str # Already internal format
162
+ end
163
+
164
+ # Assume it's a custom event and add the prefix
165
+ "custom.#{event_str}"
166
+ end
167
+
168
+ # Generate handler method name from event name
169
+ #
170
+ # @param event_name [String] The event name (should be consistent format)
171
+ # @return [Symbol] The handler method name
172
+ def generate_handler_method_name(event_name)
173
+ # Convert dots to underscores and prefix with handle_
174
+ # Examples:
175
+ # 'task.completed' -> :handle_task_completed
176
+ # 'step.failed' -> :handle_step_failed
177
+ # 'custom.event' -> :handle_custom_event
178
+ clean_name = event_name.to_s.tr('.', '_').underscore
179
+ :"handle_#{clean_name}"
180
+ end
181
+
182
+ # Check if this subscriber should handle the given event
183
+ #
184
+ # @param event_constant [String] The event constant
185
+ # @return [Boolean] Whether to handle this event
186
+ def should_handle_event?(event_constant)
187
+ # Apply class-level filter if defined
188
+ return false if self.class.event_filter && !self.class.event_filter.call(event_constant)
189
+
190
+ # Apply instance-level filtering (override in subclasses)
191
+ should_process_event?(event_constant)
192
+ end
193
+
194
+ # Instance-level event filtering (override in subclasses)
195
+ #
196
+ # @param _event_constant [String] The event constant (unused in base implementation)
197
+ # @return [Boolean] Whether to handle this event
198
+ def should_process_event?(_event_constant)
199
+ true # Process all events by default
200
+ end
201
+
202
+ # Safe accessor for event payload keys with fallback values
203
+ #
204
+ # @param event [Hash, Dry::Events::Event] The event payload or event object
205
+ # @param key [Symbol, String] The key to access
206
+ # @param default [Object] The default value if key is missing
207
+ # @return [Object] The value or default
208
+ def safe_get(event, key, default = nil)
209
+ return default if event.nil?
210
+
211
+ # Handle Dry::Events::Event objects
212
+ if event.respond_to?(:payload)
213
+ payload = event.payload
214
+ return payload.fetch(key.to_sym) { payload.fetch(key.to_s, default) }
215
+ end
216
+
217
+ # Handle plain hash events
218
+ event.fetch(key.to_sym) do
219
+ event.fetch(key.to_s, default)
220
+ end
221
+ end
222
+
223
+ # Extract core attributes common to most events
224
+ #
225
+ # @param event [Hash, Dry::Events::Event] The event payload or event object
226
+ # @return [Hash] Core attributes
227
+ def extract_core_attributes(event)
228
+ {
229
+ task_id: safe_get(event, :task_id, 'unknown'),
230
+ step_id: safe_get(event, :step_id),
231
+ event_timestamp: safe_get(event, :timestamp, Time.current).to_s
232
+ }.compact
233
+ end
234
+
235
+ # Extract step-specific attributes (for TelemetrySubscriber compatibility)
236
+ #
237
+ # @param event [Hash, Dry::Events::Event] The event payload or event object
238
+ # @return [Hash] Step attributes
239
+ def extract_step_attributes(event)
240
+ extract_core_attributes(event).merge(
241
+ step_id: safe_get(event, :step_id),
242
+ step_name: safe_get(event, :step_name, 'unknown_step')
243
+ ).compact
244
+ end
245
+
246
+ # ===============================
247
+ # METRICS COLLECTION HELPERS
248
+ # ===============================
249
+ # These methods make it easy to extract common metrics data from events
250
+
251
+ # Extract timing metrics from completion events
252
+ #
253
+ # @param event [Hash, Dry::Events::Event] The event payload
254
+ # @return [Hash] Timing metrics with default values
255
+ #
256
+ # Example:
257
+ # timing = extract_timing_metrics(event)
258
+ # StatsD.histogram('tasker.task.duration', timing[:execution_duration])
259
+ # StatsD.gauge('tasker.task.step_count', timing[:step_count])
260
+ def extract_timing_metrics(event)
261
+ {
262
+ execution_duration: safe_get(event, :execution_duration, 0.0).to_f,
263
+ started_at: safe_get(event, :started_at),
264
+ completed_at: safe_get(event, :completed_at),
265
+ step_count: safe_get(event, :total_steps, 0).to_i,
266
+ completed_steps: safe_get(event, :completed_steps, 0).to_i,
267
+ failed_steps: safe_get(event, :failed_steps, 0).to_i
268
+ }
269
+ end
270
+
271
+ # Extract error metrics from failure events
272
+ #
273
+ # @param event [Hash, Dry::Events::Event] The event payload
274
+ # @return [Hash] Error metrics with categorization
275
+ #
276
+ # Example:
277
+ # error = extract_error_metrics(event)
278
+ # StatsD.increment('tasker.errors', tags: ["error_type:#{error[:error_type]}"])
279
+ def extract_error_metrics(event)
280
+ {
281
+ error_message: safe_get(event, :error_message, 'unknown_error'),
282
+ error_class: safe_get(event, :exception_class, 'UnknownError'),
283
+ error_type: categorize_error(safe_get(event, :exception_class)),
284
+ attempt_number: safe_get(event, :attempt_number, 1).to_i,
285
+ is_retryable: safe_get(event, :retryable, false),
286
+ final_failure: safe_get(event, :attempt_number, 1).to_i >= safe_get(event, :retry_limit, 1).to_i
287
+ }
288
+ end
289
+
290
+ # Extract performance metrics for operational monitoring
291
+ #
292
+ # @param event [Hash, Dry::Events::Event] The event payload
293
+ # @return [Hash] Performance metrics
294
+ #
295
+ # Example:
296
+ # perf = extract_performance_metrics(event)
297
+ # StatsD.histogram('tasker.memory_usage', perf[:memory_usage])
298
+ def extract_performance_metrics(event)
299
+ {
300
+ memory_usage: safe_get(event, :memory_usage, 0).to_i,
301
+ cpu_time: safe_get(event, :cpu_time, 0.0).to_f,
302
+ queue_time: safe_get(event, :queue_time, 0.0).to_f,
303
+ processing_time: safe_get(event, :processing_time, 0.0).to_f,
304
+ retry_delay: safe_get(event, :retry_delay, 0.0).to_f
305
+ }
306
+ end
307
+
308
+ # Extract business metrics tags for categorization
309
+ #
310
+ # @param event [Hash, Dry::Events::Event] The event payload
311
+ # @return [Array<String>] Array of tag strings for metrics systems
312
+ #
313
+ # Example:
314
+ # tags = extract_metric_tags(event)
315
+ # StatsD.increment('tasker.task.completed', tags: tags)
316
+ def extract_metric_tags(event)
317
+ MetricTagsExtractor.extract(event)
318
+ end
319
+
320
+ # Service class to extract and build metric tags from events
321
+ # Reduces complexity by organizing tag building logic
322
+ class MetricTagsExtractor
323
+ class << self
324
+ # Extract all metric tags from event
325
+ #
326
+ # @param event [Hash, Dry::Events::Event] The event payload
327
+ # @return [Array<String>] Array of tag strings
328
+ def extract(event)
329
+ tags = []
330
+
331
+ tags.concat(extract_entity_tags(event))
332
+ tags.concat(extract_environment_tags(event))
333
+ tags.concat(extract_status_tags(event))
334
+ tags.concat(extract_business_tags(event))
335
+
336
+ tags.compact
337
+ end
338
+
339
+ private
340
+
341
+ # Extract core entity tags (task, step names)
342
+ #
343
+ # @param event [Hash, Dry::Events::Event] The event payload
344
+ # @return [Array<String>] Entity tags
345
+ def extract_entity_tags(event)
346
+ tags = []
347
+
348
+ task_name = safe_get_from_event(event, :task_name)
349
+ tags << "task:#{task_name}" if task_name && task_name != 'unknown'
350
+
351
+ step_name = safe_get_from_event(event, :step_name)
352
+ tags << "step:#{step_name}" if step_name && step_name != 'unknown_step'
353
+
354
+ tags
355
+ end
356
+
357
+ # Extract environment and source tags
358
+ #
359
+ # @param event [Hash, Dry::Events::Event] The event payload
360
+ # @return [Array<String>] Environment tags
361
+ def extract_environment_tags(event)
362
+ tags = []
363
+
364
+ tags << "environment:#{Rails.env}" if defined?(Rails)
365
+
366
+ source_system = safe_get_from_event(event, :source_system)
367
+ tags << "source:#{source_system}" if source_system
368
+
369
+ tags
370
+ end
371
+
372
+ # Extract status and retry tags
373
+ #
374
+ # @param event [Hash, Dry::Events::Event] The event payload
375
+ # @return [Array<String>] Status tags
376
+ def extract_status_tags(event)
377
+ tags = []
378
+
379
+ retryable = safe_get_from_event(event, :retryable)
380
+ tags << "retryable:#{retryable}" if retryable
381
+
382
+ attempt_number = safe_get_from_event(event, :attempt_number)
383
+ tags << "attempt:#{attempt_number}" if attempt_number
384
+
385
+ tags
386
+ end
387
+
388
+ # Extract business context tags
389
+ #
390
+ # @param event [Hash, Dry::Events::Event] The event payload
391
+ # @return [Array<String>] Business tags
392
+ def extract_business_tags(event)
393
+ tags = []
394
+
395
+ priority = safe_get_from_event(event, :priority)
396
+ tags << "priority:#{priority}" if priority
397
+
398
+ tags
399
+ end
400
+
401
+ # Safely get value from event (reuse BaseSubscriber logic)
402
+ #
403
+ # @param event [Hash, Dry::Events::Event] The event payload
404
+ # @param key [Symbol] The key to extract
405
+ # @param default [Object] Default value
406
+ # @return [Object] Extracted value
407
+ def safe_get_from_event(event, key, default = nil)
408
+ return default if event.nil?
409
+
410
+ # Handle Dry::Events::Event object
411
+ if event.respond_to?(:payload) && event.payload.respond_to?(:fetch)
412
+ payload = event.payload
413
+ return payload.fetch(key.to_sym) { payload.fetch(key.to_s, default) }
414
+ end
415
+
416
+ # Handle plain hash events
417
+ event.fetch(key.to_sym) do
418
+ event.fetch(key.to_s, default)
419
+ end
420
+ end
421
+ end
422
+ end
423
+
424
+ # Create metric name with consistent naming convention
425
+ #
426
+ # @param base_name [String] The base metric name
427
+ # @param event_type [String] The event type (completed, failed, etc.)
428
+ # @return [String] Standardized metric name
429
+ #
430
+ # Example:
431
+ # metric_name = build_metric_name('tasker.task', 'completed')
432
+ # # => 'tasker.task.completed'
433
+ def build_metric_name(base_name, event_type)
434
+ "#{base_name}.#{event_type}".squeeze('.')
435
+ end
436
+
437
+ # Extract numeric value safely for metrics
438
+ #
439
+ # @param event [Hash, Dry::Events::Event] The event payload
440
+ # @param key [Symbol, String] The key to extract
441
+ # @param default [Numeric] The default value
442
+ # @return [Numeric] The numeric value
443
+ #
444
+ # Example:
445
+ # duration = extract_numeric_metric(event, :execution_duration, 0.0)
446
+ # StatsD.histogram('task.duration', duration)
447
+ def extract_numeric_metric(event, key, default = 0)
448
+ value = safe_get(event, key, default)
449
+
450
+ # Handle nil values and non-numeric types
451
+ return default if value.nil? || !value.respond_to?(:to_f)
452
+
453
+ # Try to convert to float
454
+ converted = value.to_f
455
+
456
+ # Check if this was a valid numeric conversion
457
+ # For strings that can't convert, to_f returns 0.0
458
+ return default if converted == 0.0 && value.is_a?(String) && value !~ /\A\s*0*(\.0*)?\s*\z/
459
+
460
+ converted
461
+ end
462
+
463
+ private
464
+
465
+ # Categorize error types for metrics tagging
466
+ #
467
+ # @param error_class [String] The exception class name
468
+ # @return [String] Categorized error type
469
+ def categorize_error(error_class)
470
+ ErrorCategorizer.categorize(error_class)
471
+ end
472
+
473
+ # Service class to categorize error types for metrics
474
+ # Reduces complexity by organizing error classification logic
475
+ class ErrorCategorizer
476
+ class << self
477
+ # Categorize error based on class name
478
+ #
479
+ # @param error_class [String] The exception class name
480
+ # @return [String] Categorized error type
481
+ def categorize(error_class)
482
+ return 'unknown' if error_class.blank?
483
+
484
+ error_string = error_class.to_s
485
+
486
+ classify_error_type(error_string)
487
+ end
488
+
489
+ private
490
+
491
+ # Classify error type using pattern matching
492
+ #
493
+ # @param error_string [String] The error class as string
494
+ # @return [String] Classified error type
495
+ def classify_error_type(error_string)
496
+ ErrorTypeClassifier.classify(error_string)
497
+ end
498
+
499
+ # Service class to classify error types using pattern matching
500
+ # Reduces complexity by organizing error type classification logic
501
+ class ErrorTypeClassifier
502
+ class << self
503
+ # Classify error type from error string
504
+ #
505
+ # @param error_string [String] The error class as string
506
+ # @return [String] Classified error type
507
+ def classify(error_string)
508
+ ERROR_TYPE_MATCHERS.each do |type, matcher|
509
+ return type if matcher.call(error_string)
510
+ end
511
+
512
+ 'other'
513
+ end
514
+
515
+ # Map of error types to their matching logic
516
+ ERROR_TYPE_MATCHERS = {
517
+ 'timeout' => ->(str) { timeout_error?(str) },
518
+ 'network' => ->(str) { network_error?(str) },
519
+ 'not_found' => ->(str) { not_found_error?(str) },
520
+ 'auth' => ->(str) { auth_error?(str) },
521
+ 'rate_limit' => ->(str) { rate_limit_error?(str) },
522
+ 'client_error' => ->(str) { client_error?(str) },
523
+ 'server_error' => ->(str) { server_error?(str) },
524
+ 'runtime' => ->(str) { runtime_error?(str) }
525
+ }.freeze
526
+
527
+ # Check if error is timeout-related
528
+ #
529
+ # @param error_string [String] The error class as string
530
+ # @return [Boolean] True if timeout error
531
+ def self.timeout_error?(error_string)
532
+ error_string.match?(/Timeout/i) || error_string.match?(/TimeoutError/i)
533
+ end
534
+
535
+ # Check if error is network-related
536
+ #
537
+ # @param error_string [String] The error class as string
538
+ # @return [Boolean] True if network error
539
+ def self.network_error?(error_string)
540
+ error_string.match?(/Connection/i) || error_string.match?(/Network/i)
541
+ end
542
+
543
+ # Check if error is not found-related
544
+ #
545
+ # @param error_string [String] The error class as string
546
+ # @return [Boolean] True if not found error
547
+ def self.not_found_error?(error_string)
548
+ error_string.match?(/NotFound/i) || error_string.match?(/Missing/i) || error_string.include?('404')
549
+ end
550
+
551
+ # Check if error is authentication-related
552
+ #
553
+ # @param error_string [String] The error class as string
554
+ # @return [Boolean] True if auth error
555
+ def self.auth_error?(error_string)
556
+ error_string.match?(/Unauthorized/i) || error_string.match?(/Forbidden/i) ||
557
+ error_string.include?('401') || error_string.include?('403')
558
+ end
559
+
560
+ # Check if error is rate limit-related
561
+ #
562
+ # @param error_string [String] The error class as string
563
+ # @return [Boolean] True if rate limit error
564
+ def self.rate_limit_error?(error_string)
565
+ error_string.match?(/RateLimit/i) || error_string.match?(/TooManyRequests/i) ||
566
+ error_string.include?('429')
567
+ end
568
+
569
+ # Check if error is client error-related
570
+ #
571
+ # @param error_string [String] The error class as string
572
+ # @return [Boolean] True if client error
573
+ def self.client_error?(error_string)
574
+ error_string.match?(/BadRequest/i) || error_string.match?(/Invalid/i) ||
575
+ error_string.include?('400')
576
+ end
577
+
578
+ # Check if error is server error-related
579
+ #
580
+ # @param error_string [String] The error class as string
581
+ # @return [Boolean] True if server error
582
+ def self.server_error?(error_string)
583
+ error_string.match?(/ServerError/i) || error_string.match?(/InternalError/i) ||
584
+ error_string.include?('500')
585
+ end
586
+
587
+ # Check if error is runtime-related
588
+ #
589
+ # @param error_string [String] The error class as string
590
+ # @return [Boolean] True if runtime error
591
+ def self.runtime_error?(error_string)
592
+ error_string.match?(/StandardError/i) || error_string.match?(/RuntimeError/i)
593
+ end
594
+ end
595
+ end
596
+ end
597
+ end
598
+ end
599
+ end
600
+ end
601
+ end