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,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ # typed: false
4
+
5
+ module Tasker
6
+ class ApplicationController < ActionController::API
7
+ include Tasker::Concerns::Authenticatable
8
+ include Tasker::Concerns::ControllerAuthorizable
9
+
10
+ # Handle authentication errors with proper HTTP status codes
11
+ rescue_from Tasker::Authentication::AuthenticationError do |exception|
12
+ render json: { error: 'Unauthorized', message: exception.message }, status: :unauthorized
13
+ end
14
+
15
+ rescue_from Tasker::Authentication::ConfigurationError do |exception|
16
+ render json: { error: 'Authentication Configuration Error', message: exception.message },
17
+ status: :internal_server_error
18
+ end
19
+
20
+ rescue_from Tasker::Authentication::InterfaceError do |exception|
21
+ render json: { error: 'Authentication Interface Error', message: exception.message },
22
+ status: :internal_server_error
23
+ end
24
+
25
+ # Handle authorization errors with proper HTTP status codes
26
+ rescue_from Tasker::Authorization::UnauthorizedError do |exception|
27
+ render json: { error: 'Forbidden', message: exception.message }, status: :forbidden
28
+ end
29
+
30
+ rescue_from Tasker::Authorization::ConfigurationError do |exception|
31
+ render json: { error: 'Authorization Configuration Error', message: exception.message },
32
+ status: :internal_server_error
33
+ end
34
+
35
+ # Handle interface errors where coordinators don't implement required methods
36
+ rescue_from NoMethodError do |exception|
37
+ raise exception unless exception.message.include?('authorize!')
38
+
39
+ render json: {
40
+ error: 'Authorization Interface Error',
41
+ message: 'Coordinator does not implement required authorize! method'
42
+ }, status: :internal_server_error
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,193 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ require_dependency 'tasker/application_controller'
5
+
6
+ module Tasker
7
+ class GraphqlController < ApplicationController
8
+ # If accessing from outside this domain, nullify the session
9
+ # This allows for outside API access while preventing CSRF attacks,
10
+ # but you'll have to authenticate your user separately
11
+ # protect_from_forgery with: :null_session
12
+
13
+ # Skip the standard controller authorization - we handle GraphQL authorization manually
14
+ skip_before_action :authorize_tasker_action!, if: :authorization_enabled?
15
+
16
+ def execute
17
+ variables = prepare_variables(params[:variables])
18
+ query = params[:query]
19
+ operation_name = params[:operationName]
20
+
21
+ # Authorize GraphQL operations before execution
22
+ authorize_graphql_operations!(query, operation_name) if authorization_enabled?
23
+
24
+ context = {
25
+ # Query context goes here, for example:
26
+ current_user: current_tasker_user,
27
+ authenticated: tasker_user_authenticated?
28
+ }
29
+ result = Tasker::TaskerRailsSchema.execute(query, variables: variables, context: context,
30
+ operation_name: operation_name)
31
+ render(json: result)
32
+ rescue StandardError => e
33
+ raise(e) unless Rails.env.development?
34
+
35
+ handle_error_in_development(e)
36
+ end
37
+
38
+ private
39
+
40
+ # Handle variables in form data, JSON body, or a blank value
41
+ def prepare_variables(variables_param)
42
+ case variables_param
43
+ when String
44
+ if variables_param.present?
45
+ JSON.parse(variables_param) || {}
46
+ else
47
+ {}
48
+ end
49
+ when Hash
50
+ variables_param
51
+ when ActionController::Parameters
52
+ variables_param.to_unsafe_hash # GraphQL-Ruby will validate name and type of incoming variables.
53
+ when nil
54
+ {}
55
+ else
56
+ raise(ArgumentError, "Unexpected parameter: #{variables_param}")
57
+ end
58
+ end
59
+
60
+ def handle_error_in_development(error)
61
+ logger.error(error.message)
62
+ logger.error(error.backtrace.join("\n"))
63
+
64
+ render(json: { errors: [{ message: error.message, backtrace: error.backtrace }], data: {} },
65
+ status: :internal_server_error)
66
+ end
67
+
68
+ # Authorization methods for GraphQL operations
69
+
70
+ def authorization_enabled?
71
+ Tasker.configuration.auth.authorization_enabled
72
+ end
73
+
74
+ def authorize_graphql_operations!(query_string, operation_name)
75
+ return if query_string.blank?
76
+
77
+ # Parse the GraphQL query to extract operations
78
+ operations = extract_graphql_operations(query_string, operation_name)
79
+
80
+ # Check authorization for each operation
81
+ operations.each do |operation|
82
+ resource, action = map_graphql_operation_to_permission(operation)
83
+ next unless resource && action
84
+
85
+ authorization_coordinator.authorize!(resource, action, graphql_authorization_context(operation))
86
+ end
87
+ end
88
+
89
+ def extract_graphql_operations(query_string, _operation_name)
90
+ # Simple regex-based extraction of GraphQL operations for Tasker's current use case.
91
+ # This approach is sufficient for Tasker's limited, well-defined operations without aliases,
92
+ # fragments, or complex nesting. Consider upgrading to GraphQL-Ruby's parser if you add:
93
+ # - Field aliases (e.g., { taskList: tasks { ... } })
94
+ # - GraphQL fragments (e.g., { ...TaskFields })
95
+ # - Multiple operations in a single query
96
+ # - Operations with comments or complex string literals
97
+ operations = []
98
+
99
+ # Clean the query string
100
+ query_string = query_string.strip
101
+
102
+ # Determine if this is a query or mutation
103
+ field_matches = query_string.scan(/{\s*(\w+)(?:\s*\([^)]*\))?\s*{/)
104
+ if /^\s*mutation/i.match?(query_string)
105
+ # Extract mutation fields
106
+ # Pattern: mutation { mutationName(args) { ... } }
107
+ field_matches.flatten.each do |field|
108
+ operations << { type: :mutation, name: field.strip }
109
+ end
110
+ else
111
+ # Default to query - extract query fields
112
+ # Pattern: query { fieldName(args) { ... } } or { fieldName(args) { ... } }
113
+ field_matches.flatten.each do |field|
114
+ operations << { type: :query, name: field.strip }
115
+ end
116
+ end
117
+
118
+ # Debug logging
119
+ Rails.logger.debug { "GraphQL Query: #{query_string}" }
120
+ Rails.logger.debug { "Extracted Operations: #{operations.inspect}" }
121
+
122
+ operations
123
+ end
124
+
125
+ def map_graphql_operation_to_permission(operation)
126
+ case operation[:type]
127
+ when :query
128
+ map_query_to_permission(operation[:name])
129
+ when :mutation
130
+ map_mutation_to_permission(operation[:name])
131
+ else
132
+ [nil, nil]
133
+ end
134
+ end
135
+
136
+ def map_query_to_permission(query_name)
137
+ case query_name
138
+ when 'tasks', 'tasksByStatus', 'tasksByAnnotation'
139
+ ['tasker.task', :index]
140
+ when 'task'
141
+ ['tasker.task', :show]
142
+ when 'step'
143
+ ['tasker.workflow_step', :show]
144
+ when 'annotationTypes'
145
+ # This might be a system-level query that doesn't need authorization
146
+ [nil, nil]
147
+ else
148
+ # Unknown query - deny by default
149
+ ['unknown.resource', :unknown]
150
+ end
151
+ end
152
+
153
+ def map_mutation_to_permission(mutation_name)
154
+ case mutation_name
155
+ when 'createTask'
156
+ ['tasker.task', :create]
157
+ when 'updateTask'
158
+ ['tasker.task', :update]
159
+ when 'cancelTask'
160
+ ['tasker.task', :cancel]
161
+ when 'updateStep'
162
+ ['tasker.workflow_step', :update]
163
+ when 'cancelStep'
164
+ ['tasker.workflow_step', :cancel]
165
+ else
166
+ # Unknown mutation - deny by default
167
+ ['unknown.resource', :unknown]
168
+ end
169
+ end
170
+
171
+ def authorization_coordinator
172
+ @authorization_coordinator ||= build_authorization_coordinator
173
+ end
174
+
175
+ def build_authorization_coordinator
176
+ coordinator_class = Tasker.configuration.auth.authorization_coordinator_class.constantize
177
+ coordinator_class.new(current_tasker_user)
178
+ rescue NameError => e
179
+ coordinator_class_name = Tasker.configuration.auth.authorization_coordinator_class
180
+ raise Tasker::Authorization::ConfigurationError,
181
+ "Authorization coordinator class '#{coordinator_class_name}' not found: #{e.message}"
182
+ end
183
+
184
+ def graphql_authorization_context(operation)
185
+ {
186
+ controller: self,
187
+ params: params,
188
+ graphql_operation: operation,
189
+ user: current_tasker_user
190
+ }
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,217 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'application_controller'
5
+
6
+ module Tasker
7
+ class HandlersController < ApplicationController
8
+ before_action :set_handler_factory
9
+ before_action :set_intelligent_cache
10
+
11
+ # GET /handlers - List all namespaces with intelligent caching
12
+ def index
13
+ cache_key = "tasker:handlers:namespaces:#{handler_registry_version}"
14
+
15
+ cached_data = @intelligent_cache.intelligent_fetch(cache_key, base_ttl: 2.minutes) do
16
+ {
17
+ namespaces: @handler_factory.registered_namespaces.map do |namespace|
18
+ {
19
+ name: namespace.to_s,
20
+ handler_count: count_handlers_in_namespace(namespace)
21
+ }
22
+ end,
23
+ total_namespaces: @handler_factory.registered_namespaces.size,
24
+ generated_at: Time.current
25
+ }
26
+ end
27
+
28
+ render json: cached_data, status: :ok
29
+ end
30
+
31
+ # GET /handlers/:namespace - List handlers in a specific namespace
32
+ def show_namespace
33
+ namespace_name = params[:namespace]
34
+
35
+ unless @handler_factory.registered_namespaces.include?(namespace_name.to_sym)
36
+ render json: { error: 'Namespace not found' }, status: :not_found
37
+ return
38
+ end
39
+
40
+ namespace_handlers = @handler_factory.list_handlers(namespace: namespace_name)
41
+
42
+ handlers_data = namespace_handlers.map do |handler_name, versions|
43
+ {
44
+ name: handler_name,
45
+ namespace: namespace_name,
46
+ versions: versions.keys.sort,
47
+ latest_version: versions.keys.max,
48
+ handler_count: versions.size
49
+ }
50
+ end
51
+
52
+ render json: {
53
+ namespace: namespace_name,
54
+ handlers: handlers_data,
55
+ total_handlers: handlers_data.size
56
+ }, status: :ok
57
+ end
58
+
59
+ # GET /handlers/:namespace/:name - Show specific handler with dependency graph (cached)
60
+ def show
61
+ namespace_name = params[:namespace]
62
+ handler_name = params[:name]
63
+ version = params[:version] || '0.1.0'
64
+
65
+ unless @handler_factory.registered_namespaces.include?(namespace_name.to_sym)
66
+ render json: { error: 'Namespace not found' }, status: :not_found
67
+ return
68
+ end
69
+
70
+ # Use intelligent caching for expensive handler discovery and dependency graph building
71
+ cache_key = "tasker:handlers:show:#{namespace_name}:#{handler_name}:#{version}:#{handler_registry_version}"
72
+
73
+ cached_result = @intelligent_cache.intelligent_fetch(cache_key, base_ttl: 2.minutes) do
74
+ handler_data = find_handler_data(namespace_name, handler_name, version)
75
+
76
+ if handler_data
77
+ # Add dependency graph information (expensive operation)
78
+ handler_data[:dependency_graph] = build_dependency_graph(handler_data[:step_templates])
79
+ {
80
+ handler: handler_data,
81
+ generated_at: Time.current,
82
+ cache_key: cache_key
83
+ }
84
+ else
85
+ {
86
+ error: 'Handler not found in namespace',
87
+ generated_at: Time.current
88
+ }
89
+ end
90
+ end
91
+
92
+ if cached_result[:error]
93
+ render json: { error: cached_result[:error] }, status: :not_found
94
+ else
95
+ render json: cached_result, status: :ok
96
+ end
97
+ end
98
+
99
+ private
100
+
101
+ def set_handler_factory
102
+ @handler_factory = Tasker::HandlerFactory.instance
103
+ end
104
+
105
+ def set_intelligent_cache
106
+ @intelligent_cache = Tasker::Telemetry::IntelligentCacheManager.new
107
+ end
108
+
109
+ # Generate cache version based on handler registry state
110
+ #
111
+ # @return [String] Cache version that changes when handlers are registered/updated
112
+ def handler_registry_version
113
+ # Use handler factory statistics for cache invalidation
114
+ namespace_count = @handler_factory.registered_namespaces.size
115
+ total_handlers = @handler_factory.registered_namespaces.sum do |namespace|
116
+ @handler_factory.list_handlers(namespace: namespace).size
117
+ end
118
+
119
+ "v1:#{namespace_count}:#{total_handlers}"
120
+ end
121
+
122
+ def count_handlers_in_namespace(namespace)
123
+ namespace_handlers = @handler_factory.list_handlers(namespace: namespace)
124
+ namespace_handlers.size
125
+ end
126
+
127
+ def find_handler_data(namespace_name, handler_name, version)
128
+ # Get all versions for this handler in the namespace
129
+ namespace_handlers = @handler_factory.list_handlers(namespace: namespace_name)
130
+ handler_versions = namespace_handlers[handler_name.to_sym]
131
+
132
+ return nil unless handler_versions
133
+
134
+ # Determine the actual version to use
135
+ actual_version = if version == 'latest'
136
+ handler_versions.keys.max
137
+ elsif version == '0.1.0' && !handler_versions.key?('0.1.0')
138
+ # Fall back to lowest available version if 0.1.0 doesn't exist
139
+ handler_versions.keys.min
140
+ else
141
+ version
142
+ end
143
+
144
+ # Get the handler class for the specific version
145
+ handler_class = handler_versions[actual_version]
146
+ return nil unless handler_class
147
+
148
+ # Use the HandlerSerializer to get consistent data structure
149
+ serializer = Tasker::HandlerSerializer.new(
150
+ handler_class,
151
+ handler_name: handler_name,
152
+ namespace: namespace_name,
153
+ version: actual_version
154
+ )
155
+ serializer.serializable_hash
156
+ end
157
+
158
+ def build_dependency_graph(step_templates)
159
+ return { nodes: [], edges: [] } unless step_templates.is_a?(Array)
160
+
161
+ nodes = []
162
+ edges = []
163
+
164
+ step_templates.each do |step|
165
+ # Add node for this step
166
+ nodes << {
167
+ id: step[:name],
168
+ name: step[:name],
169
+ type: 'step',
170
+ handler_class: step[:handler_class],
171
+ configuration: step[:configuration] || step[:handler_config] || {}
172
+ }
173
+
174
+ # Add edge if this step depends on another
175
+ next unless step[:depends_on_step]
176
+
177
+ edges << {
178
+ from: step[:depends_on_step],
179
+ to: step[:name],
180
+ type: 'dependency'
181
+ }
182
+ end
183
+
184
+ {
185
+ nodes: nodes,
186
+ edges: edges,
187
+ execution_order: calculate_execution_order(step_templates)
188
+ }
189
+ end
190
+
191
+ def calculate_execution_order(step_templates)
192
+ # Simple topological sort to determine execution order
193
+ steps_by_name = step_templates.index_by { |step| step[:name] }
194
+ visited = Set.new
195
+ order = []
196
+
197
+ def visit_step(step_name, steps_by_name, visited, order)
198
+ return if visited.include?(step_name)
199
+
200
+ step = steps_by_name[step_name]
201
+ return unless step
202
+
203
+ # Visit dependencies first
204
+ visit_step(step[:depends_on_step], steps_by_name, visited, order) if step[:depends_on_step]
205
+
206
+ visited.add(step_name)
207
+ order << step_name
208
+ end
209
+
210
+ steps_by_name.each_key do |step_name|
211
+ visit_step(step_name, steps_by_name, visited, order)
212
+ end
213
+
214
+ order
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,229 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency 'tasker/application_controller'
4
+
5
+ module Tasker
6
+ # Health check controller providing endpoints for system health monitoring.
7
+ #
8
+ # This controller provides three health check endpoints:
9
+ # - `/health/ready` - Readiness check (K8s probes, always unauthenticated)
10
+ # - `/health/live` - Liveness check (K8s probes, always unauthenticated)
11
+ # - `/health/status` - Detailed status (uses system_status.read authorization)
12
+ #
13
+ # The status endpoint uses the authorization system with the `system_status.read` permission.
14
+ # If authorization is disabled or no authorization coordinator is configured, access is allowed.
15
+ # If authorization is enabled, users need the `tasker.system_status:read` permission.
16
+ class HealthController < ApplicationController
17
+ # Skip authentication and authorization for K8s probe endpoints
18
+ skip_before_action :authenticate_tasker_user!, only: %i[ready live]
19
+ skip_before_action :authorize_tasker_action!, only: %i[ready live]
20
+
21
+ # Set cache headers to prevent caching of health data (except detailed status)
22
+ before_action :set_cache_headers, except: [:status]
23
+
24
+ # Initialize intelligent cache for expensive status operations
25
+ before_action :set_intelligent_cache, only: [:status]
26
+
27
+ # Readiness check endpoint for Kubernetes probes
28
+ # Always returns quickly and doesn't require authentication/authorization
29
+ #
30
+ # @return [JSON] Simple ready/not ready status
31
+ def ready
32
+ result = Tasker::Health::ReadinessChecker.ready?
33
+
34
+ if result[:ready]
35
+ render json: result, status: :ok
36
+ else
37
+ render json: result, status: :service_unavailable
38
+ end
39
+ rescue StandardError => e
40
+ render json: {
41
+ ready: false,
42
+ error: 'Health check failed',
43
+ message: e.message,
44
+ timestamp: Time.current.iso8601
45
+ }, status: :service_unavailable
46
+ end
47
+
48
+ # Liveness check endpoint for Kubernetes probes
49
+ # Always returns 200 OK and doesn't require authentication/authorization
50
+ #
51
+ # @return [JSON] Simple alive status
52
+ def live
53
+ render json: {
54
+ alive: true,
55
+ timestamp: Time.current.iso8601,
56
+ service: 'tasker'
57
+ }, status: :ok
58
+ end
59
+
60
+ # Detailed status endpoint with comprehensive system metrics (cached)
61
+ # Uses system_status.read authorization if authorization is enabled
62
+ # Results are cached using IntelligentCacheManager for performance
63
+ #
64
+ # @return [JSON] Detailed system status and metrics
65
+ def status
66
+ # Use intelligent caching for expensive system status analysis
67
+ cache_key = "tasker:health:detailed_status:#{system_status_cache_version}"
68
+
69
+ cached_result = @intelligent_cache.intelligent_fetch(cache_key, base_ttl: 60.seconds) do
70
+ status_result = Tasker::Health::StatusChecker.status
71
+
72
+ # Enhance with additional performance analytics
73
+ enhanced_result = enhance_status_with_analytics(status_result)
74
+
75
+ {
76
+ **enhanced_result,
77
+ generated_at: Time.current,
78
+ cache_info: {
79
+ cached: true,
80
+ cache_key: cache_key,
81
+ ttl_base: '5 minutes'
82
+ }
83
+ }
84
+ end
85
+
86
+ if cached_result[:healthy]
87
+ render json: cached_result, status: :ok
88
+ else
89
+ render json: cached_result, status: :service_unavailable
90
+ end
91
+ rescue StandardError => e
92
+ render json: {
93
+ healthy: false,
94
+ error: 'Status check failed',
95
+ message: e.message,
96
+ timestamp: Time.current.iso8601
97
+ }, status: :service_unavailable
98
+ end
99
+
100
+ private
101
+
102
+ def set_intelligent_cache
103
+ @intelligent_cache = Tasker::Telemetry::IntelligentCacheManager.new
104
+ end
105
+
106
+ # Generate cache version based on system state for intelligent cache invalidation
107
+ #
108
+ # @return [String] Cache version that changes when system state changes significantly
109
+ def system_status_cache_version
110
+ # Use current hour and basic system metrics for cache versioning
111
+ # This ensures cache invalidation every hour and when major system changes occur
112
+ current_hour = Time.current.strftime('%Y%m%d%H')
113
+
114
+ # Include basic system state indicators using scopes
115
+ active_tasks = Task.created_since(1.hour.ago).count
116
+ recent_errors = WorkflowStep.failed_since(1.hour.ago).count
117
+
118
+ "v1:#{current_hour}:#{active_tasks}:#{recent_errors}"
119
+ end
120
+
121
+ # Enhance basic status with additional performance analytics
122
+ #
123
+ # @param status_result [Hash] Basic status from StatusChecker
124
+ # @return [Hash] Enhanced status with performance insights
125
+ def enhance_status_with_analytics(status_result)
126
+ # Add performance trend analysis
127
+ performance_trends = calculate_performance_trends
128
+
129
+ # Add cache performance metrics
130
+ cache_performance = @intelligent_cache.export_performance_metrics
131
+
132
+ # Enhance the original status with analytics
133
+ status_result.merge(
134
+ performance_analytics: {
135
+ trends: performance_trends,
136
+ cache_performance: cache_performance,
137
+ analysis_period: '1 hour',
138
+ enhanced_at: Time.current
139
+ }
140
+ )
141
+ rescue StandardError => e
142
+ # If analytics enhancement fails, return original status with error note
143
+ status_result.merge(
144
+ performance_analytics: {
145
+ error: "Analytics enhancement failed: #{e.message}",
146
+ fallback_mode: true
147
+ }
148
+ )
149
+ end
150
+
151
+ # Calculate performance trends for the last hour
152
+ #
153
+ # @return [Hash] Performance trend analysis
154
+ def calculate_performance_trends
155
+ one_hour_ago = 1.hour.ago
156
+
157
+ {
158
+ task_creation_rate: Task.created_since(one_hour_ago).count,
159
+ completion_rate: Task.completed_since(one_hour_ago).count,
160
+ error_rate: Task.failed_since(one_hour_ago).count,
161
+ avg_step_duration: calculate_average_step_duration(one_hour_ago)
162
+ }
163
+ end
164
+
165
+ # Calculate average step duration for performance trending
166
+ #
167
+ # @param since [Time] Calculate duration since this time
168
+ # @return [Float] Average duration in seconds
169
+ def calculate_average_step_duration(since)
170
+ completed_steps = WorkflowStep.completed_since(since)
171
+
172
+ return 0.0 if completed_steps.empty?
173
+
174
+ durations = completed_steps.filter_map do |step|
175
+ next 0.0 unless step.created_at && step.updated_at
176
+
177
+ (step.updated_at - step.created_at).to_f
178
+ end
179
+
180
+ durations.empty? ? 0.0 : (durations.sum / durations.size).round(3)
181
+ end
182
+
183
+ # Override the resource name for authorization
184
+ # Maps status action to health_status resource instead of health resource
185
+ #
186
+ # @return [String] The resource name for authorization
187
+ def tasker_resource_name
188
+ case action_name
189
+ when 'status'
190
+ Tasker::Authorization::ResourceConstants::RESOURCES::HEALTH_STATUS
191
+ else
192
+ super
193
+ end
194
+ end
195
+
196
+ # Override the action name for authorization
197
+ # Maps status action to index action instead of status action
198
+ #
199
+ # @return [Symbol] The action name for authorization
200
+ def tasker_action_name
201
+ case action_name
202
+ when 'status'
203
+ Tasker::Authorization::ResourceConstants::ACTIONS::INDEX
204
+ else
205
+ super
206
+ end
207
+ end
208
+
209
+ # Override authentication check for status endpoint
210
+ # Uses health configuration instead of global auth configuration
211
+ #
212
+ # @return [Boolean] True if authentication should be skipped
213
+ def skip_authentication?
214
+ case action_name
215
+ when 'status'
216
+ !Tasker.configuration.health.status_requires_authentication
217
+ else
218
+ super
219
+ end
220
+ end
221
+
222
+ # Set appropriate cache control headers for health endpoints
223
+ def set_cache_headers
224
+ response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
225
+ response.headers['Pragma'] = 'no-cache'
226
+ response.headers['Expires'] = '0'
227
+ end
228
+ end
229
+ end