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,298 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ RSpec.describe <%= class_name %>Authenticator, type: :model do
6
+ let(:secret) { 'test-secret-key-32-characters-minimum!' }
7
+ let(:algorithm) { 'HS256' }
8
+ let(:user_class) { '<%= user_model_class %>' }
9
+
10
+ let(:options) do
11
+ {
12
+ secret: secret,
13
+ algorithm: algorithm,
14
+ header_name: 'Authorization',
15
+ user_class: user_class
16
+ }
17
+ end
18
+
19
+ let(:authenticator) { described_class.new(options) }
20
+ let(:controller) { instance_double('ActionController::Base') }
21
+ let(:request) { instance_double('ActionDispatch::Request') }
22
+ let(:headers) { {} }
23
+
24
+ before do
25
+ allow(controller).to receive(:request).and_return(request)
26
+ allow(request).to receive(:headers).and_return(headers)
27
+ end
28
+
29
+ describe '#initialize' do
30
+ it 'sets configuration options' do
31
+ expect(authenticator.send(:secret)).to eq(secret)
32
+ expect(authenticator.send(:algorithm)).to eq(algorithm)
33
+ expect(authenticator.send(:header_name)).to eq('Authorization')
34
+ expect(authenticator.send(:user_class)).to eq(user_class)
35
+ end
36
+
37
+ it 'uses default values when options are not provided' do
38
+ authenticator = described_class.new
39
+ expect(authenticator.send(:algorithm)).to eq('HS256')
40
+ expect(authenticator.send(:header_name)).to eq('Authorization')
41
+ expect(authenticator.send(:user_class)).to eq('<%= user_model_class %>')
42
+ end
43
+ end
44
+
45
+ describe '#authenticate!' do
46
+ context 'when user is authenticated' do
47
+ let(:user) { double('User', id: 1) }
48
+
49
+ before do
50
+ allow(authenticator).to receive(:current_user).with(controller).and_return(user)
51
+ end
52
+
53
+ it 'returns true' do
54
+ expect(authenticator.authenticate!(controller)).to be true
55
+ end
56
+ end
57
+
58
+ context 'when user is not authenticated' do
59
+ before do
60
+ allow(authenticator).to receive(:current_user).with(controller).and_return(nil)
61
+ end
62
+
63
+ it 'raises AuthenticationError' do
64
+ expect do
65
+ authenticator.authenticate!(controller)
66
+ end.to raise_error(Tasker::Authentication::AuthenticationError, 'Invalid or missing JWT token')
67
+ end
68
+ end
69
+ end
70
+
71
+ describe '#current_user' do
72
+ let(:user_id) { 1 }
73
+ let(:user) { double('User', id: user_id) }
74
+ let(:payload) { { 'user_id' => user_id, 'iat' => Time.current.to_i, 'exp' => 1.hour.from_now.to_i } }
75
+ let(:token) { JWT.encode(payload, secret, algorithm) }
76
+
77
+ before do
78
+ # Mock the user model
79
+ user_model = double('UserModel')
80
+ allow(user_class).to receive(:constantize).and_return(user_model)
81
+ allow(user_model).to receive(:find_by).with(id: user_id).and_return(user)
82
+ end
83
+
84
+ context 'with valid Bearer token' do
85
+ before do
86
+ headers['Authorization'] = "Bearer #{token}"
87
+ end
88
+
89
+ it 'returns the authenticated user' do
90
+ expect(authenticator.current_user(controller)).to eq(user)
91
+ end
92
+
93
+ it 'memoizes the result' do
94
+ expect(authenticator.current_user(controller)).to eq(user)
95
+ expect(authenticator.current_user(controller)).to eq(user) # Should not decode again
96
+ end
97
+ end
98
+
99
+ context 'with valid raw token' do
100
+ before do
101
+ headers['Authorization'] = token
102
+ end
103
+
104
+ it 'returns the authenticated user' do
105
+ expect(authenticator.current_user(controller)).to eq(user)
106
+ end
107
+ end
108
+
109
+ context 'with token using sub claim' do
110
+ let(:payload) { { 'sub' => user_id, 'iat' => Time.current.to_i, 'exp' => 1.hour.from_now.to_i } }
111
+
112
+ before do
113
+ headers['Authorization'] = "Bearer #{token}"
114
+ end
115
+
116
+ it 'returns the authenticated user' do
117
+ expect(authenticator.current_user(controller)).to eq(user)
118
+ end
119
+ end
120
+
121
+ context 'with missing Authorization header' do
122
+ it 'returns nil' do
123
+ expect(authenticator.current_user(controller)).to be_nil
124
+ end
125
+ end
126
+
127
+ context 'with empty Authorization header' do
128
+ before do
129
+ headers['Authorization'] = ''
130
+ end
131
+
132
+ it 'returns nil' do
133
+ expect(authenticator.current_user(controller)).to be_nil
134
+ end
135
+ end
136
+
137
+ context 'with expired token' do
138
+ let(:payload) { { 'user_id' => user_id, 'iat' => 2.hours.ago.to_i, 'exp' => 1.hour.ago.to_i } }
139
+
140
+ before do
141
+ headers['Authorization'] = "Bearer #{token}"
142
+ end
143
+
144
+ it 'returns nil' do
145
+ expect(authenticator.current_user(controller)).to be_nil
146
+ end
147
+ end
148
+
149
+ context 'with invalid signature' do
150
+ let(:wrong_secret) { 'wrong-secret-key' }
151
+ let(:token) { JWT.encode(payload, wrong_secret, algorithm) }
152
+
153
+ before do
154
+ headers['Authorization'] = "Bearer #{token}"
155
+ end
156
+
157
+ it 'returns nil' do
158
+ expect(authenticator.current_user(controller)).to be_nil
159
+ end
160
+ end
161
+
162
+ context 'with malformed token' do
163
+ before do
164
+ headers['Authorization'] = 'Bearer invalid.token.format'
165
+ end
166
+
167
+ it 'returns nil' do
168
+ expect(authenticator.current_user(controller)).to be_nil
169
+ end
170
+ end
171
+
172
+ context 'when user is not found' do
173
+ before do
174
+ headers['Authorization'] = "Bearer #{token}"
175
+ user_model = double('UserModel')
176
+ allow(user_class).to receive(:constantize).and_return(user_model)
177
+ allow(user_model).to receive(:find_by).with(id: user_id).and_return(nil)
178
+ end
179
+
180
+ it 'returns nil' do
181
+ expect(authenticator.current_user(controller)).to be_nil
182
+ end
183
+ end
184
+
185
+ context 'when user model raises an error' do
186
+ before do
187
+ headers['Authorization'] = "Bearer #{token}"
188
+ allow(user_class).to receive(:constantize).and_raise(NameError, 'User class not found')
189
+ end
190
+
191
+ it 'returns nil' do
192
+ expect(authenticator.current_user(controller)).to be_nil
193
+ end
194
+ end
195
+ end
196
+
197
+ describe '#authenticated?' do
198
+ context 'when current_user returns a user' do
199
+ before do
200
+ allow(authenticator).to receive(:current_user).with(controller).and_return(double('User'))
201
+ end
202
+
203
+ it 'returns true' do
204
+ expect(authenticator.authenticated?(controller)).to be true
205
+ end
206
+ end
207
+
208
+ context 'when current_user returns nil' do
209
+ before do
210
+ allow(authenticator).to receive(:current_user).with(controller).and_return(nil)
211
+ end
212
+
213
+ it 'returns false' do
214
+ expect(authenticator.authenticated?(controller)).to be false
215
+ end
216
+ end
217
+ end
218
+
219
+ describe '#validate_configuration' do
220
+ context 'with valid configuration' do
221
+ it 'returns no errors' do
222
+ errors = authenticator.validate_configuration(options)
223
+ expect(errors).to be_empty
224
+ end
225
+ end
226
+
227
+ context 'with missing secret' do
228
+ let(:invalid_options) { options.merge(secret: nil) }
229
+
230
+ it 'returns validation error' do
231
+ errors = authenticator.validate_configuration(invalid_options)
232
+ expect(errors).to include('JWT secret is required')
233
+ end
234
+ end
235
+
236
+ context 'with short secret' do
237
+ let(:invalid_options) { options.merge(secret: 'short') }
238
+
239
+ it 'returns validation error' do
240
+ errors = authenticator.validate_configuration(invalid_options)
241
+ expect(errors).to include('JWT secret should be at least 32 characters for security')
242
+ end
243
+ end
244
+
245
+ context 'with invalid algorithm' do
246
+ let(:invalid_options) { options.merge(algorithm: 'INVALID') }
247
+
248
+ it 'returns validation error' do
249
+ errors = authenticator.validate_configuration(invalid_options)
250
+ expect(errors).to include(/JWT algorithm must be one of/)
251
+ end
252
+ end
253
+
254
+ context 'with invalid user class' do
255
+ let(:invalid_options) { options.merge(user_class: 'NonExistentUser') }
256
+
257
+ it 'returns validation error' do
258
+ errors = authenticator.validate_configuration(invalid_options)
259
+ expect(errors).to include(/not found/)
260
+ end
261
+ end
262
+ end
263
+
264
+ describe '.generate_test_token' do
265
+ let(:payload) { { user_id: 1, name: 'Test User' } }
266
+
267
+ it 'generates a valid JWT token' do
268
+ token = described_class.generate_test_token(payload, secret: secret)
269
+
270
+ decoded_payload = JWT.decode(token, secret, true, { algorithm: 'HS256' }).first
271
+ expect(decoded_payload['user_id']).to eq(1)
272
+ expect(decoded_payload['name']).to eq('Test User')
273
+ expect(decoded_payload['iat']).to be_present
274
+ expect(decoded_payload['exp']).to be_present
275
+ end
276
+
277
+ it 'sets expiration to 1 hour from now' do
278
+ token = described_class.generate_test_token(payload, secret: secret)
279
+
280
+ decoded_payload = JWT.decode(token, secret, true, { algorithm: 'HS256' }).first
281
+ expected_exp = Time.current.to_i + 1.hour.to_i
282
+ expect(decoded_payload['exp']).to be_within(5).of(expected_exp)
283
+ end
284
+ end
285
+
286
+ describe 'interface compliance' do
287
+ it 'includes the authentication interface' do
288
+ expect(described_class.included_modules).to include(Tasker::Authentication::Interface)
289
+ end
290
+
291
+ it 'responds to required interface methods' do
292
+ expect(authenticator).to respond_to(:authenticate!)
293
+ expect(authenticator).to respond_to(:current_user)
294
+ expect(authenticator).to respond_to(:authenticated?)
295
+ expect(authenticator).to respond_to(:validate_configuration)
296
+ end
297
+ end
298
+ end
@@ -0,0 +1,258 @@
1
+ # frozen_string_literal: true
2
+
3
+ # <%= class_name %>Subscriber - Specialized Metrics Collection
4
+ #
5
+ # This subscriber collects metrics from Tasker workflow events for operational monitoring.
6
+ # It follows OpenTelemetry best practices by focusing on aggregated metrics for dashboards
7
+ # and alerting, while leaving detailed tracing to TelemetrySubscriber.
8
+ #
9
+ <% if subscribed_events.any? -%>
10
+ # Monitoring these events:
11
+ <% subscribed_events.each do |event| -%>
12
+ # - <%= event %>
13
+ <% end -%>
14
+ <% end -%>
15
+ #
16
+ # Architecture:
17
+ # - TelemetrySubscriber: Creates OpenTelemetry spans for debugging
18
+ # - <%= class_name %>Subscriber: Records metrics for operational monitoring
19
+ # - Custom Subscribers: Handle business logic integrations
20
+ #
21
+ # Usage:
22
+ # <%= class_name %>Subscriber.subscribe(Tasker::Events::Publisher.instance)
23
+ #
24
+ class <%= class_name %>Subscriber < Tasker::Events::Subscribers::BaseSubscriber
25
+ <% if subscribed_events.any? -%>
26
+ # Subscribe to metrics-relevant events
27
+ subscribe_to <%= subscribed_events.map { |e| "'#{e}'" }.join(', ') %>
28
+
29
+ <% handler_methods.each do |method| -%>
30
+ # Collect metrics from <%= method[:event] %> events
31
+ #
32
+ # @param event [Hash] Event payload containing event data
33
+ # @return [void]
34
+ def <%= method[:method_signature] %>
35
+ # Extract standardized metrics using BaseSubscriber helpers
36
+ <% if method[:event].include?('completed') -%>
37
+ timing = extract_timing_metrics(event)
38
+ tags = extract_metric_tags(event)
39
+
40
+ # Record completion metrics
41
+ record_completion_metrics(timing, tags)
42
+ <% elsif method[:event].include?('failed') -%>
43
+ error = extract_error_metrics(event)
44
+ tags = extract_metric_tags(event)
45
+
46
+ # Record error metrics
47
+ record_error_metrics(error, tags)
48
+ <% else -%>
49
+ # Extract relevant data for this event type
50
+ tags = extract_metric_tags(event)
51
+
52
+ # TODO: Implement specific metrics for <%= method[:event] %>
53
+ # record_custom_metrics(event, tags)
54
+ <% end -%>
55
+
56
+ # Log for debugging (remove in production)
57
+ Rails.logger.debug "Recorded metrics for <%= method[:event] %>: #{safe_get(event, :task_id)}"
58
+ end
59
+
60
+ <% end -%>
61
+ <% else -%>
62
+ # TODO: Add event subscriptions for metrics collection
63
+ # subscribe_to 'task.completed', 'task.failed', 'step.completed', 'step.failed'
64
+
65
+ # Example metrics handler:
66
+ # def handle_task_completed(event)
67
+ # timing = extract_timing_metrics(event)
68
+ # tags = extract_metric_tags(event)
69
+ # record_completion_metrics(timing, tags)
70
+ # end
71
+ <% end -%>
72
+ private
73
+
74
+ # Record completion metrics for tasks/steps
75
+ #
76
+ # @param timing [Hash] Timing metrics from extract_timing_metrics
77
+ # @param tags [Array<String>] Metric tags for categorization
78
+ # @return [void]
79
+ def record_completion_metrics(timing, tags)
80
+ # Duration histogram for percentile analysis
81
+ record_histogram('tasker.execution.duration', timing[:execution_duration], tags)
82
+
83
+ # Completion counter for rate calculations
84
+ record_counter('tasker.completed', 1, tags)
85
+
86
+ # Step count gauge for workflow complexity tracking
87
+ if timing[:step_count] > 0
88
+ record_gauge('tasker.workflow.step_count', timing[:step_count], tags)
89
+ end
90
+
91
+ # Success rate calculation data
92
+ if timing[:failed_steps] > 0
93
+ record_gauge('tasker.workflow.failed_steps', timing[:failed_steps], tags)
94
+ record_gauge('tasker.workflow.success_rate',
95
+ calculate_success_rate(timing[:completed_steps], timing[:failed_steps]), tags)
96
+ end
97
+ end
98
+
99
+ # Record error metrics for failed tasks/steps
100
+ #
101
+ # @param error [Hash] Error metrics from extract_error_metrics
102
+ # @param tags [Array<String>] Metric tags for categorization
103
+ # @return [void]
104
+ def record_error_metrics(error, tags)
105
+ # Error counter with type categorization
106
+ error_tags = tags + ["error_type:#{error[:error_type]}"]
107
+ record_counter('tasker.errors', 1, error_tags)
108
+
109
+ # Retry tracking
110
+ if error[:attempt_number] > 1
111
+ record_counter('tasker.retries', 1, tags + ["attempt:#{error[:attempt_number]}"])
112
+ end
113
+
114
+ # Final failure tracking (when retries exhausted)
115
+ if error[:final_failure]
116
+ record_counter('tasker.final_failures', 1, error_tags)
117
+ end
118
+
119
+ # Retryable vs non-retryable error breakdown
120
+ retryable_tag = error[:is_retryable] ? 'retryable' : 'non_retryable'
121
+ record_counter('tasker.error_types', 1, tags + ["retryable:#{retryable_tag}"])
122
+ end
123
+
124
+ # Calculate success rate percentage
125
+ #
126
+ # @param completed [Integer] Number of completed steps
127
+ # @param failed [Integer] Number of failed steps
128
+ # @return [Float] Success rate as percentage (0.0-100.0)
129
+ def calculate_success_rate(completed, failed)
130
+ total = completed + failed
131
+ return 100.0 if total == 0
132
+
133
+ (completed.to_f / total.to_f) * 100.0
134
+ end
135
+
136
+ # ===============================
137
+ # METRICS BACKEND INTEGRATION
138
+ # ===============================
139
+ # Customize these methods for your metrics system
140
+
141
+ # Record a histogram/timing metric
142
+ #
143
+ # @param name [String] Metric name
144
+ # @param value [Numeric] Metric value
145
+ # @param tags [Array<String>] Metric tags
146
+ # @return [void]
147
+ def record_histogram(name, value, tags = [])
148
+ # TODO: Replace with your metrics system
149
+ # Examples:
150
+
151
+ # StatsD/DataDog:
152
+ # StatsD.histogram(name, value, tags: tags)
153
+
154
+ # Prometheus (via prometheus-client gem):
155
+ # histogram = Prometheus::Client.registry.get(name.tr('.', '_').to_sym)
156
+ # histogram.observe(value, labels: tags_to_labels(tags))
157
+
158
+ # Custom HTTP metrics endpoint:
159
+ # MetricsClient.post('/metrics', { name: name, value: value, tags: tags, type: 'histogram' })
160
+
161
+ # For now, log the metric (replace this in production)
162
+ Rails.logger.info "METRIC[histogram] #{name}: #{value} #{tags.join(',')}"
163
+ end
164
+
165
+ # Record a counter metric
166
+ #
167
+ # @param name [String] Metric name
168
+ # @param value [Numeric] Increment value (usually 1)
169
+ # @param tags [Array<String>] Metric tags
170
+ # @return [void]
171
+ def record_counter(name, value, tags = [])
172
+ # TODO: Replace with your metrics system
173
+ # Examples:
174
+
175
+ # StatsD/DataDog:
176
+ # StatsD.increment(name, value, tags: tags)
177
+
178
+ # Prometheus:
179
+ # counter = Prometheus::Client.registry.get(name.tr('.', '_').to_sym)
180
+ # counter.increment(by: value, labels: tags_to_labels(tags))
181
+
182
+ # For now, log the metric (replace this in production)
183
+ Rails.logger.info "METRIC[counter] #{name}: +#{value} #{tags.join(',')}"
184
+ end
185
+
186
+ # Record a gauge metric
187
+ #
188
+ # @param name [String] Metric name
189
+ # @param value [Numeric] Current value
190
+ # @param tags [Array<String>] Metric tags
191
+ # @return [void]
192
+ def record_gauge(name, value, tags = [])
193
+ # TODO: Replace with your metrics system
194
+ # Examples:
195
+
196
+ # StatsD/DataDog:
197
+ # StatsD.gauge(name, value, tags: tags)
198
+
199
+ # Prometheus:
200
+ # gauge = Prometheus::Client.registry.get(name.tr('.', '_').to_sym)
201
+ # gauge.set(value, labels: tags_to_labels(tags))
202
+
203
+ # For now, log the metric (replace this in production)
204
+ Rails.logger.info "METRIC[gauge] #{name}: #{value} #{tags.join(',')}"
205
+ end
206
+
207
+ # Convert tags array to labels hash for Prometheus
208
+ #
209
+ # @param tags [Array<String>] Tags in "key:value" format
210
+ # @return [Hash] Labels hash for Prometheus
211
+ def tags_to_labels(tags)
212
+ labels = {}
213
+ tags.each do |tag|
214
+ key, value = tag.split(':', 2)
215
+ labels[key.to_sym] = value if key && value
216
+ end
217
+ labels
218
+ end
219
+ end
220
+
221
+ # Example integration patterns:
222
+ #
223
+ # 1. StatsD/DataDog Integration:
224
+ # ```ruby
225
+ # def record_histogram(name, value, tags = [])
226
+ # StatsD.histogram(name, value, tags: tags)
227
+ # end
228
+ # ```
229
+ #
230
+ # 2. Prometheus Integration:
231
+ # ```ruby
232
+ # def record_counter(name, value, tags = [])
233
+ # counter = Prometheus::Client.registry.get(name.tr('.', '_').to_sym)
234
+ # counter.increment(by: value, labels: tags_to_labels(tags))
235
+ # end
236
+ # ```
237
+ #
238
+ # 3. Custom HTTP Metrics:
239
+ # ```ruby
240
+ # def record_metric(type, name, value, tags)
241
+ # MetricsAPI.post('/metrics', {
242
+ # type: type,
243
+ # name: name,
244
+ # value: value,
245
+ # tags: tags,
246
+ # timestamp: Time.current.to_i
247
+ # })
248
+ # end
249
+ # ```
250
+ #
251
+ # 4. Multiple Backends:
252
+ # ```ruby
253
+ # def record_histogram(name, value, tags = [])
254
+ # StatsD.histogram(name, value, tags: tags) if defined?(StatsD)
255
+ # Prometheus.histogram(name, value, tags) if prometheus_enabled?
256
+ # CustomMetrics.track(name, value, tags) if custom_metrics_enabled?
257
+ # end
258
+ # ```