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,308 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ RSpec.describe <%= class_name %>Subscriber do
6
+ let(:subscriber) { described_class.new }
7
+
8
+ describe 'subscription registration' do
9
+ it 'subscribes to the expected events' do
10
+ <% if subscribed_events.any? -%>
11
+ expected_events = <%= subscribed_events.map { |e| "'#{e}'" }.join(', ') %>
12
+ expect(described_class.subscribed_events).to contain_exactly(<%= subscribed_events.map { |e| "'#{e}'" }.join(', ') %>)
13
+ <% else -%>
14
+ # TODO: Test subscription to your specific events
15
+ # expect(described_class.subscribed_events).to contain_exactly('task.completed', 'task.failed')
16
+ <% end -%>
17
+ end
18
+ end
19
+
20
+ <% handler_methods.each do |method| -%>
21
+ describe '#<%= method[:method_name] %>' do
22
+ <% if method[:event].include?('completed') -%>
23
+ let(:completion_event) do
24
+ {
25
+ task_id: 'task-123',
26
+ task_name: 'test_task',
27
+ execution_duration: 45.2,
28
+ total_steps: 3,
29
+ completed_steps: 3,
30
+ failed_steps: 0,
31
+ started_at: 2.minutes.ago,
32
+ completed_at: Time.current,
33
+ timestamp: Time.current
34
+ }
35
+ end
36
+
37
+ it 'records completion metrics' do
38
+ # Expect timing metrics to be recorded
39
+ expect(subscriber).to receive(:record_histogram)
40
+ .with('tasker.execution.duration', 45.2, anything)
41
+
42
+ expect(subscriber).to receive(:record_counter)
43
+ .with('tasker.completed', 1, anything)
44
+
45
+ expect(subscriber).to receive(:record_gauge)
46
+ .with('tasker.workflow.step_count', 3, anything)
47
+
48
+ subscriber.<%= method[:method_name] %>(completion_event)
49
+ end
50
+
51
+ it 'extracts correct timing metrics' do
52
+ allow(subscriber).to receive(:record_histogram)
53
+ allow(subscriber).to receive(:record_counter)
54
+ allow(subscriber).to receive(:record_gauge)
55
+
56
+ # Mock the helper method to test data extraction
57
+ expect(subscriber).to receive(:extract_timing_metrics).with(completion_event)
58
+ .and_call_original
59
+
60
+ timing = subscriber.send(:extract_timing_metrics, completion_event)
61
+ expect(timing[:execution_duration]).to eq(45.2)
62
+ expect(timing[:step_count]).to eq(3)
63
+
64
+ subscriber.<%= method[:method_name] %>(completion_event)
65
+ end
66
+
67
+ it 'generates appropriate tags' do
68
+ expected_tags = include('task:test_task', "environment:#{Rails.env}")
69
+
70
+ expect(subscriber).to receive(:record_histogram)
71
+ .with(anything, anything, expected_tags)
72
+
73
+ subscriber.<%= method[:method_name] %>(completion_event)
74
+ end
75
+
76
+ <% elsif method[:event].include?('failed') -%>
77
+ let(:failure_event) do
78
+ {
79
+ task_id: 'task-456',
80
+ task_name: 'failed_task',
81
+ step_id: 'step-789',
82
+ step_name: 'failing_step',
83
+ error_message: 'Connection timeout',
84
+ exception_class: 'Net::TimeoutError',
85
+ attempt_number: 2,
86
+ retry_limit: 3,
87
+ retryable: true,
88
+ timestamp: Time.current
89
+ }
90
+ end
91
+
92
+ it 'records error metrics' do
93
+ # Expect error metrics to be recorded
94
+ expect(subscriber).to receive(:record_counter)
95
+ .with('tasker.errors', 1, include('error_type:timeout'))
96
+
97
+ expect(subscriber).to receive(:record_counter)
98
+ .with('tasker.retries', 1, include('attempt:2'))
99
+
100
+ expect(subscriber).to receive(:record_counter)
101
+ .with('tasker.error_types', 1, include('retryable:retryable'))
102
+
103
+ subscriber.<%= method[:method_name] %>(failure_event)
104
+ end
105
+
106
+ it 'categorizes error types correctly' do
107
+ allow(subscriber).to receive(:record_counter)
108
+
109
+ # Mock the helper method to test error categorization
110
+ expect(subscriber).to receive(:extract_error_metrics).with(failure_event)
111
+ .and_call_original
112
+
113
+ error = subscriber.send(:extract_error_metrics, failure_event)
114
+ expect(error[:error_type]).to eq('timeout')
115
+ expect(error[:is_retryable]).to be(true)
116
+ expect(error[:final_failure]).to be(false)
117
+
118
+ subscriber.<%= method[:method_name] %>(failure_event)
119
+ end
120
+
121
+ it 'tracks final failures when retries exhausted' do
122
+ final_failure_event = failure_event.merge(attempt_number: 3, retry_limit: 3)
123
+
124
+ expect(subscriber).to receive(:record_counter)
125
+ .with('tasker.final_failures', 1, anything)
126
+
127
+ subscriber.<%= method[:method_name] %>(final_failure_event)
128
+ end
129
+
130
+ <% else -%>
131
+ let(:sample_event) do
132
+ {
133
+ task_id: 'task-123',
134
+ task_name: 'test_task',
135
+ timestamp: Time.current
136
+ }
137
+ end
138
+
139
+ it 'handles <%= method[:event] %> events' do
140
+ # TODO: Test specific behavior for <%= method[:event] %> events
141
+ expect { subscriber.<%= method[:method_name] %>(sample_event) }.not_to raise_error
142
+ end
143
+
144
+ <% end -%>
145
+ it 'handles malformed events gracefully' do
146
+ malformed_event = { task_id: nil }
147
+
148
+ expect { subscriber.<%= method[:method_name] %>(malformed_event) }.not_to raise_error
149
+ end
150
+ end
151
+
152
+ <% end -%>
153
+ describe 'metrics recording methods' do
154
+ describe '#record_completion_metrics' do
155
+ let(:timing) do
156
+ {
157
+ execution_duration: 30.5,
158
+ step_count: 5,
159
+ completed_steps: 4,
160
+ failed_steps: 1
161
+ }
162
+ end
163
+ let(:tags) { ['task:test_task', 'environment:test'] }
164
+
165
+ it 'records all completion metrics' do
166
+ expect(subscriber).to receive(:record_histogram)
167
+ .with('tasker.execution.duration', 30.5, tags)
168
+
169
+ expect(subscriber).to receive(:record_counter)
170
+ .with('tasker.completed', 1, tags)
171
+
172
+ expect(subscriber).to receive(:record_gauge)
173
+ .with('tasker.workflow.step_count', 5, tags)
174
+
175
+ expect(subscriber).to receive(:record_gauge)
176
+ .with('tasker.workflow.failed_steps', 1, tags)
177
+
178
+ expect(subscriber).to receive(:record_gauge)
179
+ .with('tasker.workflow.success_rate', 80.0, tags)
180
+
181
+ subscriber.send(:record_completion_metrics, timing, tags)
182
+ end
183
+ end
184
+
185
+ describe '#record_error_metrics' do
186
+ let(:error) do
187
+ {
188
+ error_type: 'timeout',
189
+ attempt_number: 2,
190
+ is_retryable: true,
191
+ final_failure: false
192
+ }
193
+ end
194
+ let(:tags) { ['task:test_task'] }
195
+
196
+ it 'records all error metrics' do
197
+ expected_error_tags = tags + ['error_type:timeout']
198
+
199
+ expect(subscriber).to receive(:record_counter)
200
+ .with('tasker.errors', 1, expected_error_tags)
201
+
202
+ expect(subscriber).to receive(:record_counter)
203
+ .with('tasker.retries', 1, tags + ['attempt:2'])
204
+
205
+ expect(subscriber).to receive(:record_counter)
206
+ .with('tasker.error_types', 1, tags + ['retryable:retryable'])
207
+
208
+ subscriber.send(:record_error_metrics, error, tags)
209
+ end
210
+ end
211
+
212
+ describe '#calculate_success_rate' do
213
+ it 'calculates correct success rate' do
214
+ expect(subscriber.send(:calculate_success_rate, 8, 2)).to eq(80.0)
215
+ expect(subscriber.send(:calculate_success_rate, 10, 0)).to eq(100.0)
216
+ expect(subscriber.send(:calculate_success_rate, 0, 5)).to eq(0.0)
217
+ expect(subscriber.send(:calculate_success_rate, 0, 0)).to eq(100.0)
218
+ end
219
+ end
220
+ end
221
+
222
+ describe 'metrics backend integration' do
223
+ describe '#record_histogram' do
224
+ it 'logs metrics when no backend configured' do
225
+ expect(Rails.logger).to receive(:info)
226
+ .with(match(/METRIC\[histogram\] test\.metric: 42\.5/))
227
+
228
+ subscriber.send(:record_histogram, 'test.metric', 42.5, ['tag:value'])
229
+ end
230
+ end
231
+
232
+ describe '#record_counter' do
233
+ it 'logs metrics when no backend configured' do
234
+ expect(Rails.logger).to receive(:info)
235
+ .with(match(/METRIC\[counter\] test\.counter: \+1/))
236
+
237
+ subscriber.send(:record_counter, 'test.counter', 1, ['tag:value'])
238
+ end
239
+ end
240
+
241
+ describe '#record_gauge' do
242
+ it 'logs metrics when no backend configured' do
243
+ expect(Rails.logger).to receive(:info)
244
+ .with(match(/METRIC\[gauge\] test\.gauge: 100/))
245
+
246
+ subscriber.send(:record_gauge, 'test.gauge', 100, ['tag:value'])
247
+ end
248
+ end
249
+
250
+ describe '#tags_to_labels' do
251
+ it 'converts tags to Prometheus labels' do
252
+ tags = ['environment:production', 'task:order_process', 'status:completed']
253
+ labels = subscriber.send(:tags_to_labels, tags)
254
+
255
+ expect(labels).to eq({
256
+ environment: 'production',
257
+ task: 'order_process',
258
+ status: 'completed'
259
+ })
260
+ end
261
+
262
+ it 'handles malformed tags gracefully' do
263
+ tags = ['malformed_tag', 'good:tag', '']
264
+ labels = subscriber.send(:tags_to_labels, tags)
265
+
266
+ expect(labels).to eq({ good: 'tag' })
267
+ end
268
+ end
269
+ end
270
+
271
+ describe 'BaseSubscriber helper integration' do
272
+ let(:event) do
273
+ {
274
+ task_id: 'task-123',
275
+ task_name: 'integration_test',
276
+ execution_duration: 25.7,
277
+ exception_class: 'Net::ReadTimeout',
278
+ attempt_number: 1,
279
+ retryable: true,
280
+ timestamp: Time.current
281
+ }
282
+ end
283
+
284
+ it 'uses extract_timing_metrics helper' do
285
+ timing = subscriber.send(:extract_timing_metrics, event)
286
+
287
+ expect(timing[:execution_duration]).to eq(25.7)
288
+ expect(timing).to have_key(:started_at)
289
+ expect(timing).to have_key(:step_count)
290
+ end
291
+
292
+ it 'uses extract_error_metrics helper' do
293
+ error = subscriber.send(:extract_error_metrics, event)
294
+
295
+ expect(error[:error_type]).to eq('timeout')
296
+ expect(error[:attempt_number]).to eq(1)
297
+ expect(error[:is_retryable]).to be(true)
298
+ end
299
+
300
+ it 'uses extract_metric_tags helper' do
301
+ tags = subscriber.send(:extract_metric_tags, event)
302
+
303
+ expect(tags).to include('task:integration_test')
304
+ expect(tags).to include("environment:#{Rails.env}")
305
+ expect(tags).to include('retryable:true')
306
+ end
307
+ end
308
+ end
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ # OmniAuth authenticator for <%= class_name %>
4
+ # Generated by: rails generate tasker:authenticator <%= file_name %> --type=omniauth
5
+ #
6
+ # This authenticator integrates with OmniAuth for OAuth/OpenID authentication.
7
+ # Supports multiple authentication providers and session-based authentication.
8
+ #
9
+ # Configuration example:
10
+ # Tasker.configuration do |config|
11
+ # config.auth do |auth|
12
+ # auth.strategy = :custom
13
+ # auth.options = {
14
+ # authenticator_class: '<%= class_name %>Authenticator',
15
+ # user_finder_method: :find_by_provider_uid,
16
+ # user_class: '<%= user_model_class %>',
17
+ # failure_path: '/auth/failure'
18
+ # }
19
+ # end
20
+ # end
21
+
22
+ class <%= class_name %>Authenticator
23
+ include Tasker::Authentication::Interface
24
+
25
+ def initialize(options = {})
26
+ @user_finder_method = options[:user_finder_method] || :find_by_provider_uid
27
+ @user_class = options[:user_class] || '<%= user_model_class %>'
28
+ @failure_path = options[:failure_path] || '/auth/failure'
29
+ @options = options
30
+ end
31
+
32
+ # Required: Authenticate the request, raise exception if fails
33
+ def authenticate!(controller)
34
+ unless authenticated?(controller)
35
+ # For HTML requests, redirect to auth provider
36
+ if controller.request.format.html?
37
+ controller.redirect_to(@failure_path)
38
+ return
39
+ else
40
+ # For API requests, raise authentication error
41
+ raise Tasker::Authentication::AuthenticationError,
42
+ 'Authentication required. Please authenticate via OAuth provider.'
43
+ end
44
+ end
45
+ true
46
+ end
47
+
48
+ # Required: Get the current authenticated user
49
+ def current_user(controller)
50
+ return @current_user if defined?(@current_user)
51
+
52
+ @current_user = begin
53
+ # Try session-based user lookup first
54
+ if controller.session[:user_id]
55
+ find_user_by_id(controller.session[:user_id])
56
+ elsif controller.session[:omniauth_auth]
57
+ # If we have fresh OmniAuth data, use it
58
+ auth_data = controller.session[:omniauth_auth]
59
+ find_user_by_provider_data(auth_data)
60
+ else
61
+ nil
62
+ end
63
+ rescue StandardError => e
64
+ Rails.logger.debug "OmniAuth authentication failed: #{e.message}"
65
+ nil
66
+ end
67
+ end
68
+
69
+ # Optional: Check if user is authenticated
70
+ def authenticated?(controller)
71
+ current_user(controller).present?
72
+ end
73
+
74
+ # Optional: Configuration validation
75
+ def validate_configuration(options = {})
76
+ errors = []
77
+
78
+ # Check if OmniAuth is available
79
+ unless defined?(OmniAuth)
80
+ errors << 'OmniAuth gem is required for OmniauthAuthenticator'
81
+ end
82
+
83
+ # Validate user class
84
+ user_class = options[:user_class] || '<%= user_model_class %>'
85
+ begin
86
+ model = user_class.constantize
87
+
88
+ # Check if user finder method exists
89
+ finder_method = options[:user_finder_method] || :find_by_provider_uid
90
+ unless model.respond_to?(finder_method)
91
+ errors << "User model '#{user_class}' does not have '#{finder_method}' method"
92
+ end
93
+ rescue NameError
94
+ errors << "User class '#{user_class}' not found"
95
+ end
96
+
97
+ # Validate failure path
98
+ failure_path = options[:failure_path]
99
+ if failure_path.present? && !failure_path.is_a?(String)
100
+ errors << 'Failure path must be a string'
101
+ end
102
+
103
+ errors
104
+ end
105
+
106
+ private
107
+
108
+ attr_reader :user_finder_method, :user_class, :failure_path, :options
109
+
110
+ def find_user_by_id(user_id)
111
+ return nil unless user_id
112
+
113
+ user_model = @user_class.constantize
114
+ user_model.find_by(id: user_id)
115
+ rescue ActiveRecord::RecordNotFound, NoMethodError
116
+ nil
117
+ end
118
+
119
+ def find_user_by_provider_data(auth_data)
120
+ return nil unless auth_data
121
+
122
+ provider = auth_data['provider']
123
+ uid = auth_data['uid']
124
+ return nil unless provider && uid
125
+
126
+ user_model = @user_class.constantize
127
+ user_model.send(@user_finder_method, provider, uid)
128
+ rescue StandardError
129
+ nil
130
+ end
131
+
132
+ def user_model
133
+ @user_model ||= @user_class.constantize
134
+ end
135
+ end
@@ -0,0 +1,196 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ RSpec.describe <%= class_name %>Authenticator, type: :model do
6
+ let(:options) do
7
+ {
8
+ user_finder_method: :find_by_provider_uid,
9
+ user_class: '<%= user_model_class %>',
10
+ failure_path: '/auth/failure'
11
+ }
12
+ end
13
+
14
+ let(:authenticator) { described_class.new(options) }
15
+ let(:controller) { instance_double('ActionController::Base') }
16
+ let(:session) { {} }
17
+
18
+ before do
19
+ allow(controller).to receive(:session).and_return(session)
20
+ end
21
+
22
+ describe '#initialize' do
23
+ it 'sets configuration options' do
24
+ expect(authenticator.send(:user_finder_method)).to eq(:find_by_provider_uid)
25
+ expect(authenticator.send(:user_class)).to eq('<%= user_model_class %>')
26
+ expect(authenticator.send(:failure_path)).to eq('/auth/failure')
27
+ end
28
+
29
+ it 'uses default values when options are not provided' do
30
+ authenticator = described_class.new
31
+ expect(authenticator.send(:user_finder_method)).to eq(:find_by_provider_uid)
32
+ expect(authenticator.send(:user_class)).to eq('<%= user_model_class %>')
33
+ expect(authenticator.send(:failure_path)).to eq('/auth/failure')
34
+ end
35
+ end
36
+
37
+ describe '#current_user' do
38
+ let(:user_id) { 1 }
39
+ let(:user) { double('User', id: user_id) }
40
+
41
+ before do
42
+ # Mock the user model
43
+ user_model = double('UserModel')
44
+ allow('<%= user_model_class %>').to receive(:constantize).and_return(user_model)
45
+ allow(user_model).to receive(:find_by).with(id: user_id).and_return(user)
46
+ allow(user_model).to receive(:find_by_provider_uid).with('github', '12345').and_return(user)
47
+ end
48
+
49
+ context 'with user_id in session' do
50
+ before do
51
+ session[:user_id] = user_id
52
+ end
53
+
54
+ it 'returns the authenticated user' do
55
+ expect(authenticator.current_user(controller)).to eq(user)
56
+ end
57
+ end
58
+
59
+ context 'with omniauth_auth data in session' do
60
+ before do
61
+ session[:omniauth_auth] = {
62
+ 'provider' => 'github',
63
+ 'uid' => '12345'
64
+ }
65
+ end
66
+
67
+ it 'returns the authenticated user' do
68
+ expect(authenticator.current_user(controller)).to eq(user)
69
+ end
70
+ end
71
+
72
+ context 'with no authentication data' do
73
+ it 'returns nil' do
74
+ expect(authenticator.current_user(controller)).to be_nil
75
+ end
76
+ end
77
+
78
+ context 'when user lookup raises an error' do
79
+ before do
80
+ session[:user_id] = user_id
81
+ allow('<%= user_model_class %>').to receive(:constantize).and_raise(NameError, 'User class not found')
82
+ end
83
+
84
+ it 'returns nil' do
85
+ expect(authenticator.current_user(controller)).to be_nil
86
+ end
87
+ end
88
+ end
89
+
90
+ describe '#authenticate!' do
91
+ let(:request) { instance_double('ActionDispatch::Request') }
92
+
93
+ before do
94
+ allow(controller).to receive(:request).and_return(request)
95
+ end
96
+
97
+ context 'when user is authenticated' do
98
+ before do
99
+ allow(authenticator).to receive(:authenticated?).with(controller).and_return(true)
100
+ end
101
+
102
+ it 'returns true' do
103
+ expect(authenticator.authenticate!(controller)).to be true
104
+ end
105
+ end
106
+
107
+ context 'when user is not authenticated' do
108
+ before do
109
+ allow(authenticator).to receive(:authenticated?).with(controller).and_return(false)
110
+ end
111
+
112
+ context 'for HTML requests' do
113
+ before do
114
+ allow(request).to receive(:format).and_return(double('format', html?: true))
115
+ allow(controller).to receive(:redirect_to)
116
+ end
117
+
118
+ it 'redirects to failure path' do
119
+ expect(controller).to receive(:redirect_to).with('/auth/failure')
120
+ authenticator.authenticate!(controller)
121
+ end
122
+ end
123
+
124
+ context 'for API requests' do
125
+ before do
126
+ allow(request).to receive(:format).and_return(double('format', html?: false))
127
+ end
128
+
129
+ it 'raises AuthenticationError' do
130
+ expect do
131
+ authenticator.authenticate!(controller)
132
+ end.to raise_error(Tasker::Authentication::AuthenticationError, /Authentication required/)
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ describe '#validate_configuration' do
139
+ context 'with valid configuration' do
140
+ before do
141
+ stub_const('OmniAuth', double('OmniAuth'))
142
+ user_model = double('UserModel')
143
+ allow('<%= user_model_class %>').to receive(:constantize).and_return(user_model)
144
+ allow(user_model).to receive(:respond_to?).with(:find_by_provider_uid).and_return(true)
145
+ end
146
+
147
+ it 'returns no errors' do
148
+ errors = authenticator.validate_configuration(options)
149
+ expect(errors).to be_empty
150
+ end
151
+ end
152
+
153
+ context 'when OmniAuth is not available' do
154
+ before do
155
+ hide_const('OmniAuth')
156
+ end
157
+
158
+ it 'returns validation error' do
159
+ errors = authenticator.validate_configuration(options)
160
+ expect(errors).to include('OmniAuth gem is required for OmniauthAuthenticator')
161
+ end
162
+ end
163
+
164
+ context 'with invalid user class' do
165
+ let(:invalid_options) { options.merge(user_class: 'NonExistentUser') }
166
+
167
+ it 'returns validation error' do
168
+ errors = authenticator.validate_configuration(invalid_options)
169
+ expect(errors).to include(/not found/)
170
+ end
171
+ end
172
+
173
+ context 'when user model is missing finder method' do
174
+ before do
175
+ stub_const('OmniAuth', double('OmniAuth'))
176
+ user_model = double('UserModel')
177
+ allow('<%= user_model_class %>').to receive(:constantize).and_return(user_model)
178
+ allow(user_model).to receive(:respond_to?).with(:find_by_provider_uid).and_return(false)
179
+ end
180
+
181
+ it 'returns validation error' do
182
+ errors = authenticator.validate_configuration(options)
183
+ expect(errors).to include(/does not have 'find_by_provider_uid' method/)
184
+ end
185
+ end
186
+
187
+ context 'with invalid failure path type' do
188
+ let(:invalid_options) { options.merge(failure_path: 123) }
189
+
190
+ it 'returns validation error' do
191
+ errors = authenticator.validate_configuration(invalid_options)
192
+ expect(errors).to include('Failure path must be a string')
193
+ end
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is an example initializer showing how to set up OpenTelemetry with Tasker
4
+ # Copy this file to config/initializers/opentelemetry.rb and customize as needed
5
+
6
+ require 'opentelemetry/sdk'
7
+ require 'opentelemetry-exporter-otlp'
8
+ require 'opentelemetry/instrumentation/all'
9
+
10
+ # Configure OpenTelemetry
11
+ OpenTelemetry::SDK.configure do |c|
12
+ c.service_name = Tasker.configuration.telemetry.service_name
13
+
14
+ # Service version must be configured for instrumentation to work properly
15
+ c.service_version = 'v1.0.0'
16
+
17
+ # Configure OTLP exporter to send to local Jaeger
18
+ otlp_exporter = OpenTelemetry::Exporter::OTLP::Exporter.new(
19
+ endpoint: 'http://localhost:4318/v1/traces'
20
+ )
21
+
22
+ # Add the OTLP exporter
23
+ c.add_span_processor(
24
+ OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(otlp_exporter)
25
+ )
26
+
27
+ # Resource configuration
28
+ c.resource = OpenTelemetry::SDK::Resources::Resource.create({
29
+ # Core service identification
30
+ 'service.name' => Tasker.configuration.telemetry.service_name,
31
+ 'service.version' => Tasker.configuration.telemetry.service_version,
32
+ 'service.framework' => 'tasker'
33
+ })
34
+
35
+ # ✅ ENHANCED: PG instrumentation re-enabled after memory and connection management improvements
36
+ # Tasker v1.6+ includes fixes for:
37
+ # - Database connection pooling with ActiveRecord::Base.connection_pool.with_connection
38
+ # - Memory leak prevention with explicit futures.clear() calls
39
+ # - Batched concurrent processing (MAX_CONCURRENT_STEPS = 3) to prevent connection exhaustion
40
+ # - Proper error persistence ensuring no dangling database connections
41
+
42
+ # Use all auto-instrumentations except Faraday (which has a known bug)
43
+ # The Faraday instrumentation incorrectly passes Faraday::Response objects instead of status codes
44
+ # causing "undefined method `to_i' for #<Faraday::Response>" errors
45
+ #
46
+ # If you want to enable Faraday instrumentation, use:
47
+ # c.use_all
48
+ #
49
+ # For now, we exclude it to prevent API step handler failures:
50
+ faraday_config = { 'OpenTelemetry::Instrumentation::Faraday' => { enabled: false } }
51
+ c.use_all(faraday_config)
52
+ end