tasker-engine 0.1.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 (601) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +440 -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/tasks_controller.rb +123 -0
  13. data/app/controllers/tasker/workflow_steps_controller.rb +69 -0
  14. data/app/graphql/examples/all_tasks.graphql +22 -0
  15. data/app/graphql/examples/pending_tasks.graphql +23 -0
  16. data/app/graphql/tasker/graph_ql_types/annotation_type.rb +14 -0
  17. data/app/graphql/tasker/graph_ql_types/base_argument.rb +9 -0
  18. data/app/graphql/tasker/graph_ql_types/base_connection.rb +11 -0
  19. data/app/graphql/tasker/graph_ql_types/base_edge.rb +10 -0
  20. data/app/graphql/tasker/graph_ql_types/base_enum.rb +9 -0
  21. data/app/graphql/tasker/graph_ql_types/base_field.rb +10 -0
  22. data/app/graphql/tasker/graph_ql_types/base_input_object.rb +10 -0
  23. data/app/graphql/tasker/graph_ql_types/base_interface.rb +14 -0
  24. data/app/graphql/tasker/graph_ql_types/base_object.rb +10 -0
  25. data/app/graphql/tasker/graph_ql_types/base_scalar.rb +9 -0
  26. data/app/graphql/tasker/graph_ql_types/base_union.rb +11 -0
  27. data/app/graphql/tasker/graph_ql_types/dependent_system_object_map_type.rb +18 -0
  28. data/app/graphql/tasker/graph_ql_types/dependent_system_type.rb +13 -0
  29. data/app/graphql/tasker/graph_ql_types/mutation_type.rb +16 -0
  30. data/app/graphql/tasker/graph_ql_types/named_step_type.rb +16 -0
  31. data/app/graphql/tasker/graph_ql_types/named_task_type.rb +14 -0
  32. data/app/graphql/tasker/graph_ql_types/named_tasks_named_step_type.rb +19 -0
  33. data/app/graphql/tasker/graph_ql_types/node_type.rb +12 -0
  34. data/app/graphql/tasker/graph_ql_types/query_type.rb +20 -0
  35. data/app/graphql/tasker/graph_ql_types/task_annotation_type.rb +17 -0
  36. data/app/graphql/tasker/graph_ql_types/task_interface.rb +17 -0
  37. data/app/graphql/tasker/graph_ql_types/task_type.rb +26 -0
  38. data/app/graphql/tasker/graph_ql_types/workflow_step_type.rb +154 -0
  39. data/app/graphql/tasker/graph_ql_types.rb +42 -0
  40. data/app/graphql/tasker/mutations/base_mutation.rb +13 -0
  41. data/app/graphql/tasker/mutations/cancel_step.rb +29 -0
  42. data/app/graphql/tasker/mutations/cancel_task.rb +29 -0
  43. data/app/graphql/tasker/mutations/create_task.rb +52 -0
  44. data/app/graphql/tasker/mutations/update_step.rb +36 -0
  45. data/app/graphql/tasker/mutations/update_task.rb +41 -0
  46. data/app/graphql/tasker/queries/all_annotation_types.rb +17 -0
  47. data/app/graphql/tasker/queries/all_tasks.rb +23 -0
  48. data/app/graphql/tasker/queries/base_query.rb +9 -0
  49. data/app/graphql/tasker/queries/helpers.rb +16 -0
  50. data/app/graphql/tasker/queries/one_step.rb +24 -0
  51. data/app/graphql/tasker/queries/one_task.rb +18 -0
  52. data/app/graphql/tasker/queries/tasks_by_annotation.rb +31 -0
  53. data/app/graphql/tasker/queries/tasks_by_status.rb +30 -0
  54. data/app/graphql/tasker/tasker_rails_schema.rb +52 -0
  55. data/app/jobs/tasker/application_job.rb +8 -0
  56. data/app/jobs/tasker/metrics_export_job.rb +252 -0
  57. data/app/jobs/tasker/task_runner_job.rb +224 -0
  58. data/app/models/tasker/annotation_type.rb +26 -0
  59. data/app/models/tasker/application_record.rb +70 -0
  60. data/app/models/tasker/dependent_system.rb +26 -0
  61. data/app/models/tasker/dependent_system_object_map.rb +64 -0
  62. data/app/models/tasker/named_step.rb +41 -0
  63. data/app/models/tasker/named_task.rb +121 -0
  64. data/app/models/tasker/named_tasks_named_step.rb +82 -0
  65. data/app/models/tasker/step_dag_relationship.rb +65 -0
  66. data/app/models/tasker/step_readiness_status.rb +59 -0
  67. data/app/models/tasker/task.rb +414 -0
  68. data/app/models/tasker/task_annotation.rb +36 -0
  69. data/app/models/tasker/task_execution_context.rb +29 -0
  70. data/app/models/tasker/task_namespace.rb +41 -0
  71. data/app/models/tasker/task_transition.rb +235 -0
  72. data/app/models/tasker/workflow_step.rb +461 -0
  73. data/app/models/tasker/workflow_step_edge.rb +95 -0
  74. data/app/models/tasker/workflow_step_transition.rb +434 -0
  75. data/app/serializers/tasker/annotation_type_serializer.rb +8 -0
  76. data/app/serializers/tasker/handler_serializer.rb +109 -0
  77. data/app/serializers/tasker/task_annotation_serializer.rb +32 -0
  78. data/app/serializers/tasker/task_serializer.rb +168 -0
  79. data/app/serializers/tasker/workflow_step_serializer.rb +27 -0
  80. data/app/services/tasker/analytics_service.rb +409 -0
  81. data/config/initializers/dry_struct.rb +11 -0
  82. data/config/initializers/statesman.rb +6 -0
  83. data/config/initializers/tasker_orchestration.rb +17 -0
  84. data/config/initializers/time_formats.rb +4 -0
  85. data/config/routes.rb +34 -0
  86. data/config/tasker/subscriptions/example_integrations.yml +67 -0
  87. data/config/tasker/system_events.yml +305 -0
  88. data/db/functions/calculate_dependency_levels_v01.sql +45 -0
  89. data/db/functions/get_analytics_metrics_v01.sql +137 -0
  90. data/db/functions/get_slowest_steps_v01.sql +82 -0
  91. data/db/functions/get_slowest_tasks_v01.sql +96 -0
  92. data/db/functions/get_step_readiness_status_batch_v01.sql +140 -0
  93. data/db/functions/get_step_readiness_status_single_and_batch_v02.sql +223 -0
  94. data/db/functions/get_step_readiness_status_v01.sql +139 -0
  95. data/db/functions/get_system_health_counts_v01.sql +108 -0
  96. data/db/functions/get_task_execution_context_v01.sql +108 -0
  97. data/db/functions/get_task_execution_contexts_batch_v01.sql +104 -0
  98. data/db/init/schema.sql +2254 -0
  99. data/db/migrate/20250701165431_initial_tasker_schema.rb +116 -0
  100. data/db/migrate/20250710110830_step_readiness_sql_functions_v02.rb +39 -0
  101. data/db/views/tasker_step_dag_relationships_v01.sql +69 -0
  102. data/docs/APPLICATION_GENERATOR.md +384 -0
  103. data/docs/AUTH.md +1741 -0
  104. data/docs/CIRCUIT_BREAKER.md +224 -0
  105. data/docs/DEVELOPER_GUIDE.md +2664 -0
  106. data/docs/EVENT_SYSTEM.md +637 -0
  107. data/docs/EXECUTION_CONFIGURATION.md +341 -0
  108. data/docs/FLOW_CHART.md +149 -0
  109. data/docs/HEALTH.md +542 -0
  110. data/docs/METRICS.md +731 -0
  111. data/docs/OPTIMIZATION_PLAN.md +1479 -0
  112. data/docs/OVERVIEW.md +548 -0
  113. data/docs/QUICK_START.md +270 -0
  114. data/docs/REGISTRY_SYSTEMS.md +373 -0
  115. data/docs/REST_API.md +632 -0
  116. data/docs/REVERSIONING.md +404 -0
  117. data/docs/ROADMAP.md +221 -0
  118. data/docs/SQL_FUNCTIONS.md +1408 -0
  119. data/docs/TASK_EXECUTION_CONTROL_FLOW.md +237 -0
  120. data/docs/TELEMETRY.md +795 -0
  121. data/docs/TROUBLESHOOTING.md +756 -0
  122. data/docs/TaskHandlerGenerator.html +255 -0
  123. data/docs/Tasker/Analysis/RuntimeGraphAnalyzer.html +907 -0
  124. data/docs/Tasker/Analysis/TemplateGraphAnalyzer.html +1236 -0
  125. data/docs/Tasker/Analysis.html +117 -0
  126. data/docs/Tasker/AnalyticsController.html +450 -0
  127. data/docs/Tasker/AnalyticsService/BottleneckAnalytics.html +816 -0
  128. data/docs/Tasker/AnalyticsService/PerformanceAnalytics.html +586 -0
  129. data/docs/Tasker/AnalyticsService.html +2221 -0
  130. data/docs/Tasker/AnnotationType.html +137 -0
  131. data/docs/Tasker/AnnotationTypeSerializer.html +124 -0
  132. data/docs/Tasker/ApplicationController.html +147 -0
  133. data/docs/Tasker/ApplicationJob.html +128 -0
  134. data/docs/Tasker/ApplicationRecord.html +378 -0
  135. data/docs/Tasker/Authentication/AuthenticationError.html +124 -0
  136. data/docs/Tasker/Authentication/ConfigurationError.html +124 -0
  137. data/docs/Tasker/Authentication/Coordinator.html +242 -0
  138. data/docs/Tasker/Authentication/Interface.html +560 -0
  139. data/docs/Tasker/Authentication/InterfaceError.html +124 -0
  140. data/docs/Tasker/Authentication/NoneAuthenticator.html +338 -0
  141. data/docs/Tasker/Authentication.html +119 -0
  142. data/docs/Tasker/Authorization/AuthorizationError.html +139 -0
  143. data/docs/Tasker/Authorization/BaseCoordinator.html +927 -0
  144. data/docs/Tasker/Authorization/ConfigurationError.html +153 -0
  145. data/docs/Tasker/Authorization/ResourceConstants/ACTIONS.html +428 -0
  146. data/docs/Tasker/Authorization/ResourceConstants/RESOURCES.html +360 -0
  147. data/docs/Tasker/Authorization/ResourceConstants.html +146 -0
  148. data/docs/Tasker/Authorization/ResourceRegistry.html +875 -0
  149. data/docs/Tasker/Authorization/UnauthorizedError.html +153 -0
  150. data/docs/Tasker/Authorization.html +582 -0
  151. data/docs/Tasker/CacheCapabilities.html +167 -0
  152. data/docs/Tasker/CacheStrategy.html +1297 -0
  153. data/docs/Tasker/Concerns/Authenticatable.html +116 -0
  154. data/docs/Tasker/Concerns/Authorizable/AdminStatusChecker.html +256 -0
  155. data/docs/Tasker/Concerns/Authorizable.html +816 -0
  156. data/docs/Tasker/Concerns/ControllerAuthorizable.html +157 -0
  157. data/docs/Tasker/Concerns/EventPublisher.html +4023 -0
  158. data/docs/Tasker/Concerns/IdempotentStateTransitions.html +806 -0
  159. data/docs/Tasker/Concerns/LifecycleEventHelpers.html +129 -0
  160. data/docs/Tasker/Concerns/OrchestrationPublisher.html +129 -0
  161. data/docs/Tasker/Concerns/StateMachineBase/ClassMethods.html +1075 -0
  162. data/docs/Tasker/Concerns/StateMachineBase/StateMachineBase/ClassMethods.html +191 -0
  163. data/docs/Tasker/Concerns/StateMachineBase/StateMachineBase.html +126 -0
  164. data/docs/Tasker/Concerns/StateMachineBase.html +153 -0
  165. data/docs/Tasker/Concerns/StructuredLogging.html +1413 -0
  166. data/docs/Tasker/Concerns.html +117 -0
  167. data/docs/Tasker/Configuration/AuthConfiguration.html +1023 -0
  168. data/docs/Tasker/Configuration/ConfigurationProxy.html +581 -0
  169. data/docs/Tasker/Configuration/DatabaseConfiguration.html +475 -0
  170. data/docs/Tasker/Configuration/EngineConfiguration.html +1265 -0
  171. data/docs/Tasker/Configuration/HealthConfiguration.html +791 -0
  172. data/docs/Tasker/Configuration/TelemetryConfiguration.html +1308 -0
  173. data/docs/Tasker/Configuration/TelemetryConfigurationProxy.html +388 -0
  174. data/docs/Tasker/Configuration.html +1669 -0
  175. data/docs/Tasker/ConfigurationError.html +143 -0
  176. data/docs/Tasker/ConfiguredTask.html +514 -0
  177. data/docs/Tasker/Constants/EventDefinitions.html +590 -0
  178. data/docs/Tasker/Constants/LifecycleEvents.html +137 -0
  179. data/docs/Tasker/Constants/ObservabilityEvents/Step.html +152 -0
  180. data/docs/Tasker/Constants/ObservabilityEvents/Task.html +142 -0
  181. data/docs/Tasker/Constants/ObservabilityEvents.html +126 -0
  182. data/docs/Tasker/Constants/RegistryEvents.html +285 -0
  183. data/docs/Tasker/Constants/StepEvents.html +177 -0
  184. data/docs/Tasker/Constants/TaskEvents.html +167 -0
  185. data/docs/Tasker/Constants/TaskExecution/ExecutionStatus.html +207 -0
  186. data/docs/Tasker/Constants/TaskExecution/HealthStatus.html +191 -0
  187. data/docs/Tasker/Constants/TaskExecution/RecommendedAction.html +207 -0
  188. data/docs/Tasker/Constants/TaskExecution.html +126 -0
  189. data/docs/Tasker/Constants/TaskFinalization/ErrorMessages.html +132 -0
  190. data/docs/Tasker/Constants/TaskFinalization/PendingReasons.html +207 -0
  191. data/docs/Tasker/Constants/TaskFinalization/ReenqueueReasons.html +239 -0
  192. data/docs/Tasker/Constants/TaskFinalization.html +126 -0
  193. data/docs/Tasker/Constants/TaskStatuses.html +223 -0
  194. data/docs/Tasker/Constants/TestEvents.html +163 -0
  195. data/docs/Tasker/Constants/WorkflowEvents.html +222 -0
  196. data/docs/Tasker/Constants/WorkflowStepStatuses.html +223 -0
  197. data/docs/Tasker/Constants.html +561 -0
  198. data/docs/Tasker/DependentSystem.html +137 -0
  199. data/docs/Tasker/DependentSystemObjectMap.html +250 -0
  200. data/docs/Tasker/DetectorRegistry.html +598 -0
  201. data/docs/Tasker/Diagram/Edge.html +1191 -0
  202. data/docs/Tasker/Diagram/Flowchart.html +1539 -0
  203. data/docs/Tasker/Diagram/Node.html +1165 -0
  204. data/docs/Tasker/Diagram.html +117 -0
  205. data/docs/Tasker/Engine.html +215 -0
  206. data/docs/Tasker/Error.html +139 -0
  207. data/docs/Tasker/Events/Bus.html +1226 -0
  208. data/docs/Tasker/Events/Catalog/CatalogPrinter.html +258 -0
  209. data/docs/Tasker/Events/Catalog/CustomEventRegistrar.html +276 -0
  210. data/docs/Tasker/Events/Catalog/ExamplePayloadGenerator.html +294 -0
  211. data/docs/Tasker/Events/Catalog.html +1291 -0
  212. data/docs/Tasker/Events/CustomRegistry.html +943 -0
  213. data/docs/Tasker/Events/DefinitionLoader.html +575 -0
  214. data/docs/Tasker/Events/EventPayloadBuilder/ErrorInfoExtractor.html +286 -0
  215. data/docs/Tasker/Events/EventPayloadBuilder/StepPayloadBuilder.html +312 -0
  216. data/docs/Tasker/Events/EventPayloadBuilder.html +664 -0
  217. data/docs/Tasker/Events/Publisher.html +365 -0
  218. data/docs/Tasker/Events/Subscribers/BaseSubscriber/ErrorCategorizer/ErrorTypeClassifier.html +1128 -0
  219. data/docs/Tasker/Events/Subscribers/BaseSubscriber/ErrorCategorizer.html +270 -0
  220. data/docs/Tasker/Events/Subscribers/BaseSubscriber/MetricTagsExtractor.html +266 -0
  221. data/docs/Tasker/Events/Subscribers/BaseSubscriber.html +2556 -0
  222. data/docs/Tasker/Events/Subscribers/MetricsSubscriber.html +723 -0
  223. data/docs/Tasker/Events/Subscribers/TelemetrySubscriber.html +2251 -0
  224. data/docs/Tasker/Events/Subscribers.html +117 -0
  225. data/docs/Tasker/Events/SubscriptionLoader.html +493 -0
  226. data/docs/Tasker/Events.html +294 -0
  227. data/docs/Tasker/EventsGenerator.html +459 -0
  228. data/docs/Tasker/Functions/FunctionBasedAnalyticsMetrics/AnalyticsMetrics.html +135 -0
  229. data/docs/Tasker/Functions/FunctionBasedAnalyticsMetrics.html +412 -0
  230. data/docs/Tasker/Functions/FunctionBasedDependencyLevels.html +598 -0
  231. data/docs/Tasker/Functions/FunctionBasedSlowestSteps/SlowestStep.html +135 -0
  232. data/docs/Tasker/Functions/FunctionBasedSlowestSteps.html +453 -0
  233. data/docs/Tasker/Functions/FunctionBasedSlowestTasks/SlowestTask.html +135 -0
  234. data/docs/Tasker/Functions/FunctionBasedSlowestTasks.html +453 -0
  235. data/docs/Tasker/Functions/FunctionBasedStepReadinessStatus.html +1457 -0
  236. data/docs/Tasker/Functions/FunctionBasedSystemHealthCounts/HealthMetrics.html +135 -0
  237. data/docs/Tasker/Functions/FunctionBasedSystemHealthCounts.html +370 -0
  238. data/docs/Tasker/Functions/FunctionBasedTaskExecutionContext.html +1250 -0
  239. data/docs/Tasker/Functions/FunctionWrapper.html +479 -0
  240. data/docs/Tasker/Functions.html +117 -0
  241. data/docs/Tasker/Generators/AuthenticatorGenerator/UsageInstructionsFormatter.html +244 -0
  242. data/docs/Tasker/Generators/AuthenticatorGenerator.html +373 -0
  243. data/docs/Tasker/Generators/AuthorizationCoordinatorGenerator.html +430 -0
  244. data/docs/Tasker/Generators/SubscriberGenerator.html +377 -0
  245. data/docs/Tasker/Generators/TaskHandlerGenerator.html +263 -0
  246. data/docs/Tasker/Generators.html +117 -0
  247. data/docs/Tasker/GraphQLTypes/AnnotationType.html +132 -0
  248. data/docs/Tasker/GraphQLTypes/BaseArgument.html +124 -0
  249. data/docs/Tasker/GraphQLTypes/BaseConnection.html +124 -0
  250. data/docs/Tasker/GraphQLTypes/BaseEdge.html +130 -0
  251. data/docs/Tasker/GraphQLTypes/BaseEnum.html +124 -0
  252. data/docs/Tasker/GraphQLTypes/BaseField.html +124 -0
  253. data/docs/Tasker/GraphQLTypes/BaseInputObject.html +124 -0
  254. data/docs/Tasker/GraphQLTypes/BaseInterface.html +116 -0
  255. data/docs/Tasker/GraphQLTypes/BaseObject.html +128 -0
  256. data/docs/Tasker/GraphQLTypes/BaseScalar.html +124 -0
  257. data/docs/Tasker/GraphQLTypes/BaseUnion.html +124 -0
  258. data/docs/Tasker/GraphQLTypes/DependentSystemObjectMapType.html +132 -0
  259. data/docs/Tasker/GraphQLTypes/DependentSystemType.html +132 -0
  260. data/docs/Tasker/GraphQLTypes/MutationType.html +132 -0
  261. data/docs/Tasker/GraphQLTypes/NamedStepType.html +132 -0
  262. data/docs/Tasker/GraphQLTypes/NamedTaskType.html +132 -0
  263. data/docs/Tasker/GraphQLTypes/NamedTasksNamedStepType.html +132 -0
  264. data/docs/Tasker/GraphQLTypes/NodeType.html +118 -0
  265. data/docs/Tasker/GraphQLTypes/QueryType.html +139 -0
  266. data/docs/Tasker/GraphQLTypes/TaskAnnotationType.html +132 -0
  267. data/docs/Tasker/GraphQLTypes/TaskInterface.html +111 -0
  268. data/docs/Tasker/GraphQLTypes/TaskType.html +201 -0
  269. data/docs/Tasker/GraphQLTypes/WorkflowStepType.html +694 -0
  270. data/docs/Tasker/GraphQLTypes.html +130 -0
  271. data/docs/Tasker/GraphqlController.html +251 -0
  272. data/docs/Tasker/HandlerFactory.html +1528 -0
  273. data/docs/Tasker/HandlerSerializer.html +682 -0
  274. data/docs/Tasker/HandlersController.html +574 -0
  275. data/docs/Tasker/HashIdentityStrategy.html +278 -0
  276. data/docs/Tasker/Health/ReadinessChecker.html +712 -0
  277. data/docs/Tasker/Health/StatusChecker.html +653 -0
  278. data/docs/Tasker/Health.html +117 -0
  279. data/docs/Tasker/HealthController.html +523 -0
  280. data/docs/Tasker/IdentityStrategy.html +276 -0
  281. data/docs/Tasker/InvalidTaskHandlerConfig.html +135 -0
  282. data/docs/Tasker/LifecycleEvents/Events/Step.html +162 -0
  283. data/docs/Tasker/LifecycleEvents/Events/Task.html +162 -0
  284. data/docs/Tasker/LifecycleEvents/Events.html +204 -0
  285. data/docs/Tasker/LifecycleEvents/Publisher.html +132 -0
  286. data/docs/Tasker/LifecycleEvents.html +799 -0
  287. data/docs/Tasker/Logging/CorrelationIdGenerator.html +688 -0
  288. data/docs/Tasker/Logging.html +115 -0
  289. data/docs/Tasker/MetricsController.html +293 -0
  290. data/docs/Tasker/MetricsExportJob.html +414 -0
  291. data/docs/Tasker/Mutations/BaseMutation.html +128 -0
  292. data/docs/Tasker/Mutations/CancelStep.html +219 -0
  293. data/docs/Tasker/Mutations/CancelTask.html +221 -0
  294. data/docs/Tasker/Mutations/CreateTask.html +243 -0
  295. data/docs/Tasker/Mutations/UpdateStep.html +243 -0
  296. data/docs/Tasker/Mutations/UpdateTask.html +243 -0
  297. data/docs/Tasker/Mutations.html +117 -0
  298. data/docs/Tasker/NamedStep.html +216 -0
  299. data/docs/Tasker/NamedTask.html +910 -0
  300. data/docs/Tasker/NamedTasksNamedStep.html +435 -0
  301. data/docs/Tasker/Orchestration/BackoffCalculator.html +404 -0
  302. data/docs/Tasker/Orchestration/ConnectionBuilder/ConfigValidator.html +258 -0
  303. data/docs/Tasker/Orchestration/ConnectionBuilder.html +435 -0
  304. data/docs/Tasker/Orchestration/ConnectionPoolIntelligence.html +513 -0
  305. data/docs/Tasker/Orchestration/Coordinator.html +641 -0
  306. data/docs/Tasker/Orchestration/FutureStateAnalyzer.html +1045 -0
  307. data/docs/Tasker/Orchestration/Orchestrator.html +679 -0
  308. data/docs/Tasker/Orchestration/PluginIntegration.html +1127 -0
  309. data/docs/Tasker/Orchestration/ResponseProcessor.html +504 -0
  310. data/docs/Tasker/Orchestration/RetryHeaderParser.html +304 -0
  311. data/docs/Tasker/Orchestration/StepExecutor.html +995 -0
  312. data/docs/Tasker/Orchestration/StepSequenceFactory.html +644 -0
  313. data/docs/Tasker/Orchestration/TaskFinalizer/BlockageChecker.html +264 -0
  314. data/docs/Tasker/Orchestration/TaskFinalizer/ContextManager.html +254 -0
  315. data/docs/Tasker/Orchestration/TaskFinalizer/DelayCalculator.html +556 -0
  316. data/docs/Tasker/Orchestration/TaskFinalizer/FinalizationDecisionMaker.html +348 -0
  317. data/docs/Tasker/Orchestration/TaskFinalizer/FinalizationProcessor.html +286 -0
  318. data/docs/Tasker/Orchestration/TaskFinalizer/ReasonDeterminer.html +432 -0
  319. data/docs/Tasker/Orchestration/TaskFinalizer/ReenqueueManager.html +296 -0
  320. data/docs/Tasker/Orchestration/TaskFinalizer/UnclearStateHandler.html +314 -0
  321. data/docs/Tasker/Orchestration/TaskFinalizer.html +1212 -0
  322. data/docs/Tasker/Orchestration/TaskInitializer.html +766 -0
  323. data/docs/Tasker/Orchestration/TaskReenqueuer.html +506 -0
  324. data/docs/Tasker/Orchestration/ViableStepDiscovery.html +442 -0
  325. data/docs/Tasker/Orchestration/WorkflowCoordinator.html +510 -0
  326. data/docs/Tasker/Orchestration.html +130 -0
  327. data/docs/Tasker/PageSort/PageSortParamsBuilder.html +296 -0
  328. data/docs/Tasker/PageSort.html +247 -0
  329. data/docs/Tasker/PermanentError.html +518 -0
  330. data/docs/Tasker/ProceduralError.html +147 -0
  331. data/docs/Tasker/Queries/AllAnnotationTypes.html +217 -0
  332. data/docs/Tasker/Queries/AllTasks.html +221 -0
  333. data/docs/Tasker/Queries/BaseQuery.html +128 -0
  334. data/docs/Tasker/Queries/Helpers.html +187 -0
  335. data/docs/Tasker/Queries/OneStep.html +225 -0
  336. data/docs/Tasker/Queries/OneTask.html +217 -0
  337. data/docs/Tasker/Queries/TasksByAnnotation.html +231 -0
  338. data/docs/Tasker/Queries/TasksByStatus.html +233 -0
  339. data/docs/Tasker/Queries.html +119 -0
  340. data/docs/Tasker/Railtie.html +124 -0
  341. data/docs/Tasker/Registry/BaseRegistry.html +1690 -0
  342. data/docs/Tasker/Registry/EventPublisher.html +667 -0
  343. data/docs/Tasker/Registry/InterfaceValidator.html +569 -0
  344. data/docs/Tasker/Registry/RegistrationError.html +132 -0
  345. data/docs/Tasker/Registry/RegistryError.html +139 -0
  346. data/docs/Tasker/Registry/StatisticsCollector.html +841 -0
  347. data/docs/Tasker/Registry/SubscriberRegistry.html +1504 -0
  348. data/docs/Tasker/Registry/ValidationError.html +132 -0
  349. data/docs/Tasker/Registry.html +119 -0
  350. data/docs/Tasker/RetryableError.html +515 -0
  351. data/docs/Tasker/StateMachine/Compatibility.html +282 -0
  352. data/docs/Tasker/StateMachine/InvalidStateTransition.html +135 -0
  353. data/docs/Tasker/StateMachine/StepStateMachine/StandardizedPayloadBuilder.html +260 -0
  354. data/docs/Tasker/StateMachine/StepStateMachine.html +2215 -0
  355. data/docs/Tasker/StateMachine/TaskStateMachine.html +734 -0
  356. data/docs/Tasker/StateMachine.html +602 -0
  357. data/docs/Tasker/StepDagRelationship.html +657 -0
  358. data/docs/Tasker/StepHandler/Api/Config.html +1091 -0
  359. data/docs/Tasker/StepHandler/Api.html +884 -0
  360. data/docs/Tasker/StepHandler/AutomaticEventPublishing.html +321 -0
  361. data/docs/Tasker/StepHandler/Base.html +970 -0
  362. data/docs/Tasker/StepHandler.html +119 -0
  363. data/docs/Tasker/StepReadinessStatus.html +836 -0
  364. data/docs/Tasker/Task.html +2478 -0
  365. data/docs/Tasker/TaskAnnotation.html +137 -0
  366. data/docs/Tasker/TaskAnnotationSerializer.html +124 -0
  367. data/docs/Tasker/TaskBuilder/StepNameValidator.html +264 -0
  368. data/docs/Tasker/TaskBuilder/StepTemplateDefiner.html +264 -0
  369. data/docs/Tasker/TaskBuilder.html +764 -0
  370. data/docs/Tasker/TaskDiagram/StepToStepEdgeBuilder.html +260 -0
  371. data/docs/Tasker/TaskDiagram/TaskToRootStepEdgeBuilder.html +290 -0
  372. data/docs/Tasker/TaskDiagram.html +548 -0
  373. data/docs/Tasker/TaskDiagramsController.html +240 -0
  374. data/docs/Tasker/TaskExecutionContext.html +469 -0
  375. data/docs/Tasker/TaskHandler/ClassMethods/StepTemplateDefiner/ClassBasedEventRegistrar.html +238 -0
  376. data/docs/Tasker/TaskHandler/ClassMethods/StepTemplateDefiner/YamlEventRegistrar.html +254 -0
  377. data/docs/Tasker/TaskHandler/ClassMethods/StepTemplateDefiner.html +988 -0
  378. data/docs/Tasker/TaskHandler/ClassMethods.html +395 -0
  379. data/docs/Tasker/TaskHandler/InstanceMethods.html +1396 -0
  380. data/docs/Tasker/TaskHandler/StepGroup.html +1748 -0
  381. data/docs/Tasker/TaskHandler.html +271 -0
  382. data/docs/Tasker/TaskNamespace.html +312 -0
  383. data/docs/Tasker/TaskRunnerJob.html +406 -0
  384. data/docs/Tasker/TaskSerializer.html +474 -0
  385. data/docs/Tasker/TaskTransition.html +1517 -0
  386. data/docs/Tasker/TaskWorkflowSummary.html +988 -0
  387. data/docs/Tasker/TaskerRailsSchema/InvalidObjectTypeError.html +132 -0
  388. data/docs/Tasker/TaskerRailsSchema/TypeResolutionError.html +139 -0
  389. data/docs/Tasker/TaskerRailsSchema/UnknownInterfaceError.html +132 -0
  390. data/docs/Tasker/TaskerRailsSchema.html +384 -0
  391. data/docs/Tasker/TasksController.html +595 -0
  392. data/docs/Tasker/Telemetry/EventMapping.html +1307 -0
  393. data/docs/Tasker/Telemetry/EventRouter.html +2178 -0
  394. data/docs/Tasker/Telemetry/Events/ExportEvents.html +246 -0
  395. data/docs/Tasker/Telemetry/Events.html +115 -0
  396. data/docs/Tasker/Telemetry/ExportCoordinator/DistributedLockTimeoutError.html +135 -0
  397. data/docs/Tasker/Telemetry/ExportCoordinator.html +2137 -0
  398. data/docs/Tasker/Telemetry/IntelligentCacheManager.html +1083 -0
  399. data/docs/Tasker/Telemetry/LogBackend.html +1088 -0
  400. data/docs/Tasker/Telemetry/MetricTypes/Counter.html +1054 -0
  401. data/docs/Tasker/Telemetry/MetricTypes/Gauge.html +1270 -0
  402. data/docs/Tasker/Telemetry/MetricTypes/Histogram.html +1492 -0
  403. data/docs/Tasker/Telemetry/MetricTypes.html +153 -0
  404. data/docs/Tasker/Telemetry/MetricsBackend.html +2510 -0
  405. data/docs/Tasker/Telemetry/MetricsExportService.html +578 -0
  406. data/docs/Tasker/Telemetry/PluginRegistry.html +1774 -0
  407. data/docs/Tasker/Telemetry/Plugins/BaseExporter.html +1835 -0
  408. data/docs/Tasker/Telemetry/Plugins/CsvExporter.html +768 -0
  409. data/docs/Tasker/Telemetry/Plugins/JsonExporter.html +747 -0
  410. data/docs/Tasker/Telemetry/Plugins.html +117 -0
  411. data/docs/Tasker/Telemetry/PrometheusExporter.html +481 -0
  412. data/docs/Tasker/Telemetry/TraceBackend.html +891 -0
  413. data/docs/Tasker/Telemetry.html +130 -0
  414. data/docs/Tasker/Types/AuthConfig.html +886 -0
  415. data/docs/Tasker/Types/BackoffConfig.html +1063 -0
  416. data/docs/Tasker/Types/BaseConfig.html +227 -0
  417. data/docs/Tasker/Types/CacheConfig.html +1731 -0
  418. data/docs/Tasker/Types/DatabaseConfig.html +388 -0
  419. data/docs/Tasker/Types/DependencyGraph.html +526 -0
  420. data/docs/Tasker/Types/DependencyGraphConfig.html +753 -0
  421. data/docs/Tasker/Types/EngineConfig.html +1181 -0
  422. data/docs/Tasker/Types/ExecutionConfig.html +1963 -0
  423. data/docs/Tasker/Types/GraphEdge.html +517 -0
  424. data/docs/Tasker/Types/GraphMetadata.html +781 -0
  425. data/docs/Tasker/Types/GraphNode.html +694 -0
  426. data/docs/Tasker/Types/HealthConfig.html +784 -0
  427. data/docs/Tasker/Types/StepSequence.html +353 -0
  428. data/docs/Tasker/Types/StepTemplate.html +1193 -0
  429. data/docs/Tasker/Types/TaskRequest.html +1179 -0
  430. data/docs/Tasker/Types/TelemetryConfig.html +2746 -0
  431. data/docs/Tasker/Types.html +154 -0
  432. data/docs/Tasker/WorkflowStep/StepFinder.html +282 -0
  433. data/docs/Tasker/WorkflowStep.html +2724 -0
  434. data/docs/Tasker/WorkflowStepEdge.html +306 -0
  435. data/docs/Tasker/WorkflowStepSerializer.html +305 -0
  436. data/docs/Tasker/WorkflowStepTransition/TransitionDescriptionFormatter.html +282 -0
  437. data/docs/Tasker/WorkflowStepTransition.html +2201 -0
  438. data/docs/Tasker/WorkflowStepsController.html +462 -0
  439. data/docs/Tasker.html +468 -0
  440. data/docs/VISION.md +584 -0
  441. data/docs/WHY.md +21 -0
  442. data/docs/_index.html +2319 -0
  443. data/docs/class_list.html +54 -0
  444. data/docs/css/common.css +1 -0
  445. data/docs/css/full_list.css +58 -0
  446. data/docs/css/style.css +503 -0
  447. data/docs/events/migration_plan_outcomes.md +80 -0
  448. data/docs/file.README.html +537 -0
  449. data/docs/file_list.html +59 -0
  450. data/docs/frames.html +22 -0
  451. data/docs/index.html +537 -0
  452. data/docs/js/app.js +344 -0
  453. data/docs/js/full_list.js +242 -0
  454. data/docs/js/jquery.js +4 -0
  455. data/docs/method_list.html +8854 -0
  456. data/docs/top-level-namespace.html +110 -0
  457. data/lib/generators/tasker/authenticator_generator.rb +301 -0
  458. data/lib/generators/tasker/authorization_coordinator_generator.rb +139 -0
  459. data/lib/generators/tasker/events_generator.rb +91 -0
  460. data/lib/generators/tasker/subscriber_generator.rb +107 -0
  461. data/lib/generators/tasker/task_handler_generator.rb +138 -0
  462. data/lib/generators/tasker/templates/api_token_authenticator.rb.erb +113 -0
  463. data/lib/generators/tasker/templates/api_token_authenticator_spec.rb.erb +144 -0
  464. data/lib/generators/tasker/templates/authorization_coordinator.rb.erb +82 -0
  465. data/lib/generators/tasker/templates/authorization_coordinator_spec.rb.erb +136 -0
  466. data/lib/generators/tasker/templates/custom_authenticator.rb.erb +108 -0
  467. data/lib/generators/tasker/templates/custom_authenticator_spec.rb.erb +162 -0
  468. data/lib/generators/tasker/templates/custom_events.yml.erb +62 -0
  469. data/lib/generators/tasker/templates/custom_subscriber.rb.erb +72 -0
  470. data/lib/generators/tasker/templates/devise_authenticator.rb.erb +101 -0
  471. data/lib/generators/tasker/templates/devise_authenticator_spec.rb.erb +126 -0
  472. data/lib/generators/tasker/templates/initialize.rb.erb +202 -0
  473. data/lib/generators/tasker/templates/jwt_authenticator.rb.erb +144 -0
  474. data/lib/generators/tasker/templates/jwt_authenticator_spec.rb.erb +298 -0
  475. data/lib/generators/tasker/templates/metrics_subscriber.rb.erb +258 -0
  476. data/lib/generators/tasker/templates/metrics_subscriber_spec.rb.erb +308 -0
  477. data/lib/generators/tasker/templates/omniauth_authenticator.rb.erb +135 -0
  478. data/lib/generators/tasker/templates/omniauth_authenticator_spec.rb.erb +196 -0
  479. data/lib/generators/tasker/templates/opentelemetry_initializer.rb +52 -0
  480. data/lib/generators/tasker/templates/subscriber.rb.erb +64 -0
  481. data/lib/generators/tasker/templates/subscriber_spec.rb.erb +80 -0
  482. data/lib/generators/tasker/templates/task_config.yaml.erb +117 -0
  483. data/lib/generators/tasker/templates/task_handler.rb.erb +60 -0
  484. data/lib/generators/tasker/templates/task_handler_spec.rb.erb +165 -0
  485. data/lib/tasker/analysis/runtime_graph_analyzer.rb +1168 -0
  486. data/lib/tasker/analysis/template_graph_analyzer.rb +328 -0
  487. data/lib/tasker/authentication/coordinator.rb +78 -0
  488. data/lib/tasker/authentication/errors.rb +9 -0
  489. data/lib/tasker/authentication/interface.rb +36 -0
  490. data/lib/tasker/authentication/none_authenticator.rb +26 -0
  491. data/lib/tasker/authorization/base_coordinator.rb +112 -0
  492. data/lib/tasker/authorization/errors.rb +26 -0
  493. data/lib/tasker/authorization/resource_constants.rb +73 -0
  494. data/lib/tasker/authorization/resource_registry.rb +136 -0
  495. data/lib/tasker/authorization.rb +75 -0
  496. data/lib/tasker/cache_capabilities.rb +131 -0
  497. data/lib/tasker/cache_strategy.rb +469 -0
  498. data/lib/tasker/concerns/authenticatable.rb +41 -0
  499. data/lib/tasker/concerns/authorizable.rb +204 -0
  500. data/lib/tasker/concerns/controller_authorizable.rb +124 -0
  501. data/lib/tasker/concerns/event_publisher.rb +716 -0
  502. data/lib/tasker/concerns/idempotent_state_transitions.rb +128 -0
  503. data/lib/tasker/concerns/state_machine_base.rb +218 -0
  504. data/lib/tasker/concerns/structured_logging.rb +387 -0
  505. data/lib/tasker/configuration.rb +325 -0
  506. data/lib/tasker/constants/event_definitions.rb +147 -0
  507. data/lib/tasker/constants/registry_events.rb +54 -0
  508. data/lib/tasker/constants.rb +417 -0
  509. data/lib/tasker/engine.rb +90 -0
  510. data/lib/tasker/errors.rb +90 -0
  511. data/lib/tasker/events/catalog.rb +432 -0
  512. data/lib/tasker/events/custom_registry.rb +175 -0
  513. data/lib/tasker/events/definition_loader.rb +199 -0
  514. data/lib/tasker/events/event_payload_builder.rb +461 -0
  515. data/lib/tasker/events/publisher.rb +149 -0
  516. data/lib/tasker/events/subscribers/base_subscriber.rb +601 -0
  517. data/lib/tasker/events/subscribers/metrics_subscriber.rb +120 -0
  518. data/lib/tasker/events/subscribers/telemetry_subscriber.rb +462 -0
  519. data/lib/tasker/events/subscription_loader.rb +161 -0
  520. data/lib/tasker/events.rb +37 -0
  521. data/lib/tasker/functions/function_based_analytics_metrics.rb +103 -0
  522. data/lib/tasker/functions/function_based_dependency_levels.rb +54 -0
  523. data/lib/tasker/functions/function_based_slowest_steps.rb +84 -0
  524. data/lib/tasker/functions/function_based_slowest_tasks.rb +84 -0
  525. data/lib/tasker/functions/function_based_step_readiness_status.rb +183 -0
  526. data/lib/tasker/functions/function_based_system_health_counts.rb +94 -0
  527. data/lib/tasker/functions/function_based_task_execution_context.rb +148 -0
  528. data/lib/tasker/functions/function_wrapper.rb +42 -0
  529. data/lib/tasker/functions.rb +12 -0
  530. data/lib/tasker/handler_factory.rb +327 -0
  531. data/lib/tasker/health/readiness_checker.rb +186 -0
  532. data/lib/tasker/health/status_checker.rb +203 -0
  533. data/lib/tasker/identity_strategy.rb +38 -0
  534. data/lib/tasker/logging/correlation_id_generator.rb +120 -0
  535. data/lib/tasker/orchestration/backoff_calculator.rb +184 -0
  536. data/lib/tasker/orchestration/connection_builder.rb +122 -0
  537. data/lib/tasker/orchestration/connection_pool_intelligence.rb +177 -0
  538. data/lib/tasker/orchestration/coordinator.rb +119 -0
  539. data/lib/tasker/orchestration/future_state_analyzer.rb +137 -0
  540. data/lib/tasker/orchestration/plugin_integration.rb +124 -0
  541. data/lib/tasker/orchestration/response_processor.rb +168 -0
  542. data/lib/tasker/orchestration/retry_header_parser.rb +78 -0
  543. data/lib/tasker/orchestration/step_executor.rb +941 -0
  544. data/lib/tasker/orchestration/step_sequence_factory.rb +67 -0
  545. data/lib/tasker/orchestration/task_finalizer.rb +564 -0
  546. data/lib/tasker/orchestration/task_initializer.rb +140 -0
  547. data/lib/tasker/orchestration/task_reenqueuer.rb +71 -0
  548. data/lib/tasker/orchestration/viable_step_discovery.rb +65 -0
  549. data/lib/tasker/orchestration/workflow_coordinator.rb +294 -0
  550. data/lib/tasker/orchestration.rb +45 -0
  551. data/lib/tasker/railtie.rb +9 -0
  552. data/lib/tasker/registry/base_registry.rb +177 -0
  553. data/lib/tasker/registry/event_publisher.rb +91 -0
  554. data/lib/tasker/registry/interface_validator.rb +140 -0
  555. data/lib/tasker/registry/statistics_collector.rb +381 -0
  556. data/lib/tasker/registry/subscriber_registry.rb +285 -0
  557. data/lib/tasker/registry.rb +22 -0
  558. data/lib/tasker/state_machine/step_state_machine.rb +508 -0
  559. data/lib/tasker/state_machine/task_state_machine.rb +192 -0
  560. data/lib/tasker/state_machine.rb +83 -0
  561. data/lib/tasker/step_handler/api.rb +410 -0
  562. data/lib/tasker/step_handler/base.rb +206 -0
  563. data/lib/tasker/task_builder.rb +432 -0
  564. data/lib/tasker/task_handler/class_methods.rb +327 -0
  565. data/lib/tasker/task_handler/instance_methods.rb +293 -0
  566. data/lib/tasker/task_handler/step_group.rb +182 -0
  567. data/lib/tasker/task_handler.rb +43 -0
  568. data/lib/tasker/telemetry/event_mapping.rb +126 -0
  569. data/lib/tasker/telemetry/event_router.rb +318 -0
  570. data/lib/tasker/telemetry/events/export_events.rb +38 -0
  571. data/lib/tasker/telemetry/export_coordinator.rb +497 -0
  572. data/lib/tasker/telemetry/intelligent_cache_manager.rb +508 -0
  573. data/lib/tasker/telemetry/log_backend.rb +224 -0
  574. data/lib/tasker/telemetry/metric_types.rb +416 -0
  575. data/lib/tasker/telemetry/metrics_backend.rb +1227 -0
  576. data/lib/tasker/telemetry/metrics_export_service.rb +392 -0
  577. data/lib/tasker/telemetry/plugin_registry.rb +333 -0
  578. data/lib/tasker/telemetry/plugins/base_exporter.rb +246 -0
  579. data/lib/tasker/telemetry/plugins/csv_exporter.rb +198 -0
  580. data/lib/tasker/telemetry/plugins/json_exporter.rb +141 -0
  581. data/lib/tasker/telemetry/prometheus_exporter.rb +249 -0
  582. data/lib/tasker/telemetry/trace_backend.rb +186 -0
  583. data/lib/tasker/telemetry.rb +59 -0
  584. data/lib/tasker/types/auth_config.rb +81 -0
  585. data/lib/tasker/types/backoff_config.rb +142 -0
  586. data/lib/tasker/types/cache_config.rb +257 -0
  587. data/lib/tasker/types/database_config.rb +39 -0
  588. data/lib/tasker/types/dependency_graph.rb +225 -0
  589. data/lib/tasker/types/dependency_graph_config.rb +149 -0
  590. data/lib/tasker/types/engine_config.rb +131 -0
  591. data/lib/tasker/types/execution_config.rb +289 -0
  592. data/lib/tasker/types/health_config.rb +84 -0
  593. data/lib/tasker/types/step_sequence.rb +24 -0
  594. data/lib/tasker/types/step_template.rb +63 -0
  595. data/lib/tasker/types/task_request.rb +60 -0
  596. data/lib/tasker/types/telemetry_config.rb +273 -0
  597. data/lib/tasker/types.rb +64 -0
  598. data/lib/tasker/version.rb +8 -0
  599. data/lib/tasker.rb +82 -0
  600. data/lib/tasks/tasker_tasks.rake +383 -0
  601. metadata +954 -0
@@ -0,0 +1,96 @@
1
+ -- Slowest Tasks Analysis Function
2
+ -- Returns the slowest tasks within a specified time period with performance metrics
3
+ -- Input: since_timestamp, limit_count, and optional namespace/name/version filters
4
+ -- Output: Ranked list of slowest tasks with duration and context
5
+
6
+ CREATE OR REPLACE FUNCTION get_slowest_tasks_v01(
7
+ since_timestamp TIMESTAMPTZ DEFAULT NULL,
8
+ limit_count INTEGER DEFAULT 10,
9
+ namespace_filter TEXT DEFAULT NULL,
10
+ task_name_filter TEXT DEFAULT NULL,
11
+ version_filter TEXT DEFAULT NULL
12
+ )
13
+ RETURNS TABLE (
14
+ task_id BIGINT,
15
+ task_name VARCHAR(64),
16
+ namespace_name VARCHAR(64),
17
+ version VARCHAR(64),
18
+ duration_seconds NUMERIC(10,3),
19
+ step_count BIGINT,
20
+ completed_steps BIGINT,
21
+ error_steps BIGINT,
22
+ created_at TIMESTAMPTZ,
23
+ completed_at TIMESTAMPTZ,
24
+ initiator VARCHAR(128),
25
+ source_system VARCHAR(128)
26
+ ) LANGUAGE plpgsql STABLE AS $$
27
+ DECLARE
28
+ analysis_start TIMESTAMPTZ;
29
+ BEGIN
30
+ -- Set analysis start time (default to 24 hours ago if not provided)
31
+ analysis_start := COALESCE(since_timestamp, NOW() - INTERVAL '24 hours');
32
+
33
+ RETURN QUERY
34
+ WITH task_durations AS (
35
+ SELECT
36
+ t.task_id,
37
+ nt.name as task_name,
38
+ tn.name as namespace_name,
39
+ nt.version,
40
+ t.created_at,
41
+ t.initiator,
42
+ t.source_system,
43
+ -- Find the latest completion time across all steps
44
+ MAX(wst.created_at) FILTER (
45
+ WHERE wst.to_state IN ('complete', 'error') AND wst.most_recent = true
46
+ ) as latest_completion,
47
+ -- Calculate duration from task creation to latest step completion
48
+ EXTRACT(EPOCH FROM (
49
+ MAX(wst.created_at) FILTER (
50
+ WHERE wst.to_state IN ('complete', 'error') AND wst.most_recent = true
51
+ ) - t.created_at
52
+ )) as duration_seconds,
53
+ COUNT(ws.workflow_step_id) as total_steps,
54
+ COUNT(ws.workflow_step_id) FILTER (
55
+ WHERE complete_wst.to_state = 'complete' AND complete_wst.most_recent = true
56
+ ) as completed_step_count,
57
+ COUNT(ws.workflow_step_id) FILTER (
58
+ WHERE error_wst.to_state = 'error' AND error_wst.most_recent = true
59
+ ) as error_step_count
60
+ FROM tasker_tasks t
61
+ INNER JOIN tasker_named_tasks nt ON nt.named_task_id = t.named_task_id
62
+ INNER JOIN tasker_task_namespaces tn ON tn.task_namespace_id = nt.task_namespace_id
63
+ INNER JOIN tasker_workflow_steps ws ON ws.task_id = t.task_id
64
+ LEFT JOIN tasker_workflow_step_transitions wst ON wst.workflow_step_id = ws.workflow_step_id
65
+ LEFT JOIN tasker_workflow_step_transitions complete_wst ON complete_wst.workflow_step_id = ws.workflow_step_id
66
+ AND complete_wst.to_state = 'complete' AND complete_wst.most_recent = true
67
+ LEFT JOIN tasker_workflow_step_transitions error_wst ON error_wst.workflow_step_id = ws.workflow_step_id
68
+ AND error_wst.to_state = 'error' AND error_wst.most_recent = true
69
+ WHERE t.created_at > analysis_start
70
+ AND (namespace_filter IS NULL OR tn.name = namespace_filter)
71
+ AND (task_name_filter IS NULL OR nt.name = task_name_filter)
72
+ AND (version_filter IS NULL OR nt.version = version_filter)
73
+ GROUP BY t.task_id, nt.name, tn.name, nt.version, t.created_at, t.initiator, t.source_system
74
+ HAVING MAX(wst.created_at) FILTER (
75
+ WHERE wst.to_state IN ('complete', 'error') AND wst.most_recent = true
76
+ ) IS NOT NULL -- Only include tasks that have at least one completed/failed step
77
+ )
78
+ SELECT
79
+ td.task_id,
80
+ td.task_name,
81
+ td.namespace_name,
82
+ td.version,
83
+ ROUND(td.duration_seconds, 3),
84
+ td.total_steps,
85
+ td.completed_step_count,
86
+ td.error_step_count,
87
+ td.created_at,
88
+ td.latest_completion,
89
+ td.initiator,
90
+ td.source_system
91
+ FROM task_durations td
92
+ WHERE td.duration_seconds IS NOT NULL
93
+ ORDER BY td.duration_seconds DESC
94
+ LIMIT limit_count;
95
+ END;
96
+ $$;
@@ -0,0 +1,140 @@
1
+ -- Batch Step Readiness Status Function
2
+ -- Gets step readiness data for multiple tasks in a single query
3
+ -- Input: Array of task_ids (gets all steps for each task)
4
+ -- Output: Multiple rows with step readiness data, properly grouped by task
5
+
6
+ CREATE OR REPLACE FUNCTION get_step_readiness_status_batch(input_task_ids BIGINT[])
7
+ RETURNS TABLE(
8
+ workflow_step_id BIGINT,
9
+ task_id BIGINT,
10
+ named_step_id INTEGER,
11
+ name TEXT,
12
+ current_state TEXT,
13
+ dependencies_satisfied BOOLEAN,
14
+ retry_eligible BOOLEAN,
15
+ ready_for_execution BOOLEAN,
16
+ last_failure_at TIMESTAMP,
17
+ next_retry_at TIMESTAMP,
18
+ total_parents INTEGER,
19
+ completed_parents INTEGER,
20
+ attempts INTEGER,
21
+ retry_limit INTEGER,
22
+ backoff_request_seconds INTEGER,
23
+ last_attempted_at TIMESTAMP
24
+ ) LANGUAGE plpgsql STABLE AS $$
25
+ BEGIN
26
+ RETURN QUERY
27
+ SELECT
28
+ ws.workflow_step_id,
29
+ ws.task_id,
30
+ ws.named_step_id,
31
+ ns.name::TEXT,
32
+
33
+ -- Current State Information (optimized using most_recent flag)
34
+ COALESCE(current_state.to_state, 'pending')::TEXT as current_state,
35
+
36
+ -- Dependency Analysis (calculated from direct joins)
37
+ CASE
38
+ WHEN dep_edges.to_step_id IS NULL THEN true -- Root steps (no parents)
39
+ WHEN COUNT(dep_edges.from_step_id) = 0 THEN true -- Steps with zero dependencies
40
+ WHEN COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END) = COUNT(dep_edges.from_step_id) THEN true
41
+ ELSE false
42
+ END as dependencies_satisfied,
43
+
44
+ -- Simplified Retry & Backoff Analysis
45
+ CASE
46
+ WHEN ws.attempts >= COALESCE(ws.retry_limit, 3) THEN false
47
+ WHEN ws.attempts > 0 AND COALESCE(ws.retryable, true) = false THEN false
48
+ WHEN last_failure.created_at IS NULL THEN true
49
+ WHEN ws.backoff_request_seconds IS NOT NULL AND ws.last_attempted_at IS NOT NULL THEN
50
+ ws.last_attempted_at + (ws.backoff_request_seconds * interval '1 second') <= NOW()
51
+ WHEN last_failure.created_at IS NOT NULL THEN
52
+ last_failure.created_at + (
53
+ LEAST(power(2, COALESCE(ws.attempts, 1)) * interval '1 second', interval '30 seconds')
54
+ ) <= NOW()
55
+ ELSE true
56
+ END as retry_eligible,
57
+
58
+ -- Simplified Final Readiness Calculation
59
+ CASE
60
+ WHEN COALESCE(current_state.to_state, 'pending') IN ('pending', 'error')
61
+ AND (ws.processed = false OR ws.processed IS NULL) -- CRITICAL: Only unprocessed steps can be ready
62
+ AND (dep_edges.to_step_id IS NULL OR
63
+ COUNT(dep_edges.from_step_id) = 0 OR
64
+ COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END) = COUNT(dep_edges.from_step_id))
65
+ AND (ws.attempts < COALESCE(ws.retry_limit, 3))
66
+ AND (COALESCE(ws.retryable, true) = true)
67
+ AND (ws.in_process = false OR ws.in_process IS NULL)
68
+ AND (
69
+ -- Check explicit backoff timing (most restrictive)
70
+ -- If backoff is set, the backoff period must have expired
71
+ CASE
72
+ WHEN ws.backoff_request_seconds IS NOT NULL AND ws.last_attempted_at IS NOT NULL THEN
73
+ ws.last_attempted_at + (ws.backoff_request_seconds * interval '1 second') <= NOW()
74
+ ELSE true -- No explicit backoff set
75
+ END
76
+ AND
77
+ -- Then check failure-based backoff
78
+ (last_failure.created_at IS NULL OR
79
+ last_failure.created_at + (LEAST(power(2, COALESCE(ws.attempts, 1)) * interval '1 second', interval '30 seconds')) <= NOW())
80
+ )
81
+ THEN true
82
+ ELSE false
83
+ END as ready_for_execution,
84
+
85
+ -- Timing Information
86
+ last_failure.created_at as last_failure_at,
87
+ CASE
88
+ WHEN ws.backoff_request_seconds IS NOT NULL AND ws.last_attempted_at IS NOT NULL THEN
89
+ ws.last_attempted_at + (ws.backoff_request_seconds * interval '1 second')
90
+ WHEN last_failure.created_at IS NOT NULL THEN
91
+ last_failure.created_at + (LEAST(power(2, COALESCE(ws.attempts, 1)) * interval '1 second', interval '30 seconds'))
92
+ ELSE NULL
93
+ END as next_retry_at,
94
+
95
+ -- Dependency Context (calculated from joins)
96
+ COALESCE(COUNT(dep_edges.from_step_id), 0)::INTEGER as total_parents,
97
+ COALESCE(COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END), 0)::INTEGER as completed_parents,
98
+
99
+ -- Retry Context
100
+ ws.attempts,
101
+ COALESCE(ws.retry_limit, 3) as retry_limit,
102
+ ws.backoff_request_seconds,
103
+ ws.last_attempted_at
104
+
105
+ FROM tasker_workflow_steps ws
106
+ JOIN tasker_named_steps ns ON ns.named_step_id = ws.named_step_id
107
+
108
+ -- OPTIMIZED: Current State using most_recent flag instead of DISTINCT ON
109
+ LEFT JOIN tasker_workflow_step_transitions current_state
110
+ ON current_state.workflow_step_id = ws.workflow_step_id
111
+ AND current_state.most_recent = true
112
+
113
+ -- OPTIMIZED: Dependency check using direct joins (no subquery)
114
+ LEFT JOIN tasker_workflow_step_edges dep_edges
115
+ ON dep_edges.to_step_id = ws.workflow_step_id
116
+ LEFT JOIN tasker_workflow_step_transitions parent_states
117
+ ON parent_states.workflow_step_id = dep_edges.from_step_id
118
+ AND parent_states.most_recent = true
119
+
120
+ -- OPTIMIZED: Last failure using index-optimized approach
121
+ LEFT JOIN tasker_workflow_step_transitions last_failure
122
+ ON last_failure.workflow_step_id = ws.workflow_step_id
123
+ AND last_failure.to_state = 'error'
124
+ AND last_failure.most_recent = true
125
+
126
+ -- KEY PERFORMANCE IMPROVEMENT: Filter by multiple tasks at once
127
+ -- CRITICAL FIX: Include ALL steps for task execution context calculation
128
+ -- Only filter by processed status when specifically querying for ready steps
129
+ WHERE ws.task_id = ANY(input_task_ids)
130
+
131
+ GROUP BY
132
+ ws.workflow_step_id, ws.task_id, ws.named_step_id, ns.name,
133
+ current_state.to_state, last_failure.created_at,
134
+ ws.attempts, ws.retry_limit, ws.backoff_request_seconds, ws.last_attempted_at,
135
+ ws.in_process, ws.processed, ws.retryable, dep_edges.to_step_id
136
+
137
+ -- IMPORTANT: Order by task_id, then workflow_step_id for consistent grouping
138
+ ORDER BY ws.task_id, ws.workflow_step_id;
139
+ END;
140
+ $$;
@@ -0,0 +1,223 @@
1
+ -- Fix step readiness logic for NULL attempts
2
+ -- When attempts is NULL, it should be treated as 0 for comparison purposes
3
+
4
+ -- Update get_step_readiness_status function
5
+ CREATE OR REPLACE FUNCTION get_step_readiness_status(input_task_id bigint, step_ids bigint[] DEFAULT NULL::bigint[]) RETURNS TABLE(workflow_step_id bigint, task_id bigint, named_step_id integer, name text, current_state text, dependencies_satisfied boolean, retry_eligible boolean, ready_for_execution boolean, last_failure_at timestamp without time zone, next_retry_at timestamp without time zone, total_parents integer, completed_parents integer, attempts integer, retry_limit integer, backoff_request_seconds integer, last_attempted_at timestamp without time zone)
6
+ LANGUAGE plpgsql STABLE
7
+ AS $$
8
+ BEGIN
9
+ RETURN QUERY
10
+ SELECT
11
+ ws.workflow_step_id,
12
+ ws.task_id,
13
+ ws.named_step_id,
14
+ ns.name::TEXT,
15
+
16
+ -- Current State Information (optimized using most_recent flag)
17
+ COALESCE(current_state.to_state, 'pending')::TEXT as current_state,
18
+
19
+ -- Dependency Satisfaction Analysis
20
+ CASE
21
+ WHEN dep_edges.to_step_id IS NULL OR
22
+ COUNT(dep_edges.from_step_id) = 0 THEN true
23
+ ELSE
24
+ COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END) = COUNT(dep_edges.from_step_id)
25
+ END as dependencies_satisfied,
26
+
27
+ -- Retry Eligibility
28
+ CASE
29
+ WHEN COALESCE(ws.attempts, 0) < COALESCE(ws.retry_limit, 3) THEN true
30
+ ELSE false
31
+ END as retry_eligible,
32
+
33
+ -- Overall Ready for Execution (complex business logic)
34
+ CASE
35
+ WHEN COALESCE(current_state.to_state, 'pending') IN ('pending', 'error')
36
+ AND (ws.processed = false OR ws.processed IS NULL) -- CRITICAL: Only unprocessed steps can be ready
37
+ AND (dep_edges.to_step_id IS NULL OR
38
+ COUNT(dep_edges.from_step_id) = 0 OR
39
+ COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END) = COUNT(dep_edges.from_step_id))
40
+ AND (COALESCE(ws.attempts, 0) < COALESCE(ws.retry_limit, 3)) -- FIXED: Handle NULL attempts
41
+ AND (COALESCE(ws.retryable, true) = true)
42
+ AND (ws.in_process = false OR ws.in_process IS NULL)
43
+ AND (
44
+ -- Check explicit backoff timing (most restrictive)
45
+ -- If backoff is set, the backoff period must have expired
46
+ CASE
47
+ WHEN ws.backoff_request_seconds IS NOT NULL AND ws.last_attempted_at IS NOT NULL THEN
48
+ ws.last_attempted_at + (ws.backoff_request_seconds * interval '1 second') <= NOW()
49
+ ELSE true -- No explicit backoff set
50
+ END
51
+ AND
52
+ -- Then check failure-based backoff
53
+ (last_failure.created_at IS NULL OR
54
+ last_failure.created_at + (LEAST(power(2, COALESCE(ws.attempts, 1)) * interval '1 second', interval '30 seconds')) <= NOW())
55
+ )
56
+ THEN true
57
+ ELSE false
58
+ END as ready_for_execution,
59
+
60
+ -- Timing Information
61
+ last_failure.created_at as last_failure_at,
62
+ CASE
63
+ WHEN ws.backoff_request_seconds IS NOT NULL AND ws.last_attempted_at IS NOT NULL THEN
64
+ ws.last_attempted_at + (ws.backoff_request_seconds * interval '1 second')
65
+ WHEN last_failure.created_at IS NOT NULL THEN
66
+ last_failure.created_at + (LEAST(power(2, COALESCE(ws.attempts, 1)) * interval '1 second', interval '30 seconds'))
67
+ ELSE NULL
68
+ END as next_retry_at,
69
+
70
+ -- Dependency Context (calculated from joins)
71
+ COALESCE(COUNT(dep_edges.from_step_id), 0)::INTEGER as total_parents,
72
+ COALESCE(COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END), 0)::INTEGER as completed_parents,
73
+
74
+ -- Retry Context
75
+ COALESCE(ws.attempts, 0)::INTEGER as attempts, -- FIXED: Return 0 instead of NULL
76
+ COALESCE(ws.retry_limit, 3) as retry_limit,
77
+ ws.backoff_request_seconds,
78
+ ws.last_attempted_at
79
+
80
+ FROM tasker_workflow_steps ws
81
+ JOIN tasker_named_steps ns ON ns.named_step_id = ws.named_step_id
82
+
83
+ -- OPTIMIZED: Current State using most_recent flag instead of DISTINCT ON
84
+ LEFT JOIN tasker_workflow_step_transitions current_state
85
+ ON current_state.workflow_step_id = ws.workflow_step_id
86
+ AND current_state.most_recent = true
87
+
88
+ -- OPTIMIZED: Dependency check using direct joins (no subquery)
89
+ LEFT JOIN tasker_workflow_step_edges dep_edges
90
+ ON dep_edges.to_step_id = ws.workflow_step_id
91
+ LEFT JOIN tasker_workflow_step_transitions parent_states
92
+ ON parent_states.workflow_step_id = dep_edges.from_step_id
93
+ AND parent_states.most_recent = true
94
+
95
+ -- OPTIMIZED: Last failure using index-optimized approach
96
+ LEFT JOIN tasker_workflow_step_transitions last_failure
97
+ ON last_failure.workflow_step_id = ws.workflow_step_id
98
+ AND last_failure.to_state = 'error'
99
+ AND last_failure.most_recent = true
100
+
101
+ -- KEY PERFORMANCE IMPROVEMENT: Filter by task first, then optionally by step IDs
102
+ -- CRITICAL FIX: Include ALL steps for task execution context calculation
103
+ -- Only filter by processed status when specifically querying for ready steps
104
+ WHERE ws.task_id = input_task_id
105
+ AND (step_ids IS NULL OR ws.workflow_step_id = ANY(step_ids))
106
+
107
+ GROUP BY
108
+ ws.workflow_step_id, ws.task_id, ws.named_step_id, ns.name,
109
+ current_state.to_state, last_failure.created_at,
110
+ ws.attempts, ws.retry_limit, ws.backoff_request_seconds, ws.last_attempted_at,
111
+ ws.in_process, ws.processed, ws.retryable, dep_edges.to_step_id,
112
+ current_state.workflow_step_id, last_failure.workflow_step_id;
113
+ END;
114
+ $$;
115
+
116
+ -- Also update the batch version
117
+ CREATE OR REPLACE FUNCTION get_step_readiness_status_batch(input_task_ids bigint[]) RETURNS TABLE(workflow_step_id bigint, task_id bigint, named_step_id integer, name text, current_state text, dependencies_satisfied boolean, retry_eligible boolean, ready_for_execution boolean, last_failure_at timestamp without time zone, next_retry_at timestamp without time zone, total_parents integer, completed_parents integer, attempts integer, retry_limit integer, backoff_request_seconds integer, last_attempted_at timestamp without time zone)
118
+ LANGUAGE plpgsql STABLE
119
+ AS $$
120
+ BEGIN
121
+ RETURN QUERY
122
+ SELECT
123
+ ws.workflow_step_id,
124
+ ws.task_id,
125
+ ws.named_step_id,
126
+ ns.name::TEXT,
127
+
128
+ -- Current State Information (optimized using most_recent flag)
129
+ COALESCE(current_state.to_state, 'pending')::TEXT as current_state,
130
+
131
+ -- Dependency Satisfaction Analysis
132
+ CASE
133
+ WHEN dep_edges.to_step_id IS NULL OR
134
+ COUNT(dep_edges.from_step_id) = 0 THEN true
135
+ ELSE
136
+ COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END) = COUNT(dep_edges.from_step_id)
137
+ END as dependencies_satisfied,
138
+
139
+ -- Retry Eligibility
140
+ CASE
141
+ WHEN COALESCE(ws.attempts, 0) < COALESCE(ws.retry_limit, 3) THEN true
142
+ ELSE false
143
+ END as retry_eligible,
144
+
145
+ -- Overall Ready for Execution (complex business logic)
146
+ CASE
147
+ WHEN COALESCE(current_state.to_state, 'pending') IN ('pending', 'error')
148
+ AND (ws.processed = false OR ws.processed IS NULL)
149
+ AND (dep_edges.to_step_id IS NULL OR
150
+ COUNT(dep_edges.from_step_id) = 0 OR
151
+ COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END) = COUNT(dep_edges.from_step_id))
152
+ AND (COALESCE(ws.attempts, 0) < COALESCE(ws.retry_limit, 3)) -- FIXED: Handle NULL attempts
153
+ AND (COALESCE(ws.retryable, true) = true)
154
+ AND (ws.in_process = false OR ws.in_process IS NULL)
155
+ AND (
156
+ -- Check explicit backoff timing (most restrictive)
157
+ -- If backoff is set, the backoff period must have expired
158
+ CASE
159
+ WHEN ws.backoff_request_seconds IS NOT NULL AND ws.last_attempted_at IS NOT NULL THEN
160
+ ws.last_attempted_at + (ws.backoff_request_seconds * interval '1 second') <= NOW()
161
+ ELSE true -- No explicit backoff set
162
+ END
163
+ AND
164
+ -- Then check failure-based backoff
165
+ (last_failure.created_at IS NULL OR
166
+ last_failure.created_at + (LEAST(power(2, COALESCE(ws.attempts, 1)) * interval '1 second', interval '30 seconds')) <= NOW())
167
+ )
168
+ THEN true
169
+ ELSE false
170
+ END as ready_for_execution,
171
+
172
+ -- Timing Information
173
+ last_failure.created_at as last_failure_at,
174
+ CASE
175
+ WHEN ws.backoff_request_seconds IS NOT NULL AND ws.last_attempted_at IS NOT NULL THEN
176
+ ws.last_attempted_at + (ws.backoff_request_seconds * interval '1 second')
177
+ WHEN last_failure.created_at IS NOT NULL THEN
178
+ last_failure.created_at + (LEAST(power(2, COALESCE(ws.attempts, 1)) * interval '1 second', interval '30 seconds'))
179
+ ELSE NULL
180
+ END as next_retry_at,
181
+
182
+ -- Dependency Context (calculated from joins)
183
+ COALESCE(COUNT(dep_edges.from_step_id), 0)::INTEGER as total_parents,
184
+ COALESCE(COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END), 0)::INTEGER as completed_parents,
185
+
186
+ -- Retry Context
187
+ COALESCE(ws.attempts, 0)::INTEGER as attempts, -- FIXED: Return 0 instead of NULL
188
+ COALESCE(ws.retry_limit, 3) as retry_limit,
189
+ ws.backoff_request_seconds,
190
+ ws.last_attempted_at
191
+
192
+ FROM tasker_workflow_steps ws
193
+ JOIN tasker_named_steps ns ON ns.named_step_id = ws.named_step_id
194
+
195
+ -- OPTIMIZED: Current State using most_recent flag instead of DISTINCT ON
196
+ LEFT JOIN tasker_workflow_step_transitions current_state
197
+ ON current_state.workflow_step_id = ws.workflow_step_id
198
+ AND current_state.most_recent = true
199
+
200
+ -- OPTIMIZED: Dependency check using direct joins (no subquery)
201
+ LEFT JOIN tasker_workflow_step_edges dep_edges
202
+ ON dep_edges.to_step_id = ws.workflow_step_id
203
+ LEFT JOIN tasker_workflow_step_transitions parent_states
204
+ ON parent_states.workflow_step_id = dep_edges.from_step_id
205
+ AND parent_states.most_recent = true
206
+
207
+ -- OPTIMIZED: Last failure using index-optimized approach
208
+ LEFT JOIN tasker_workflow_step_transitions last_failure
209
+ ON last_failure.workflow_step_id = ws.workflow_step_id
210
+ AND last_failure.to_state = 'error'
211
+ AND last_failure.most_recent = true
212
+
213
+ -- KEY PERFORMANCE IMPROVEMENT: Filter by task first, then optionally by step IDs
214
+ WHERE ws.task_id = ANY(input_task_ids)
215
+
216
+ GROUP BY
217
+ ws.workflow_step_id, ws.task_id, ws.named_step_id, ns.name,
218
+ current_state.to_state, last_failure.created_at,
219
+ ws.attempts, ws.retry_limit, ws.backoff_request_seconds, ws.last_attempted_at,
220
+ ws.in_process, ws.processed, ws.retryable, dep_edges.to_step_id,
221
+ current_state.workflow_step_id, last_failure.workflow_step_id;
222
+ END;
223
+ $$;
@@ -0,0 +1,139 @@
1
+ -- Step Readiness Status Function
2
+ -- Converts the view logic to a parameterized function for targeted queries
3
+ -- Input: Array of workflow_step_ids
4
+ -- Output: Readiness data for specified steps only
5
+
6
+ CREATE OR REPLACE FUNCTION get_step_readiness_status(input_task_id BIGINT, step_ids BIGINT[] DEFAULT NULL)
7
+ RETURNS TABLE(
8
+ workflow_step_id BIGINT,
9
+ task_id BIGINT,
10
+ named_step_id INTEGER,
11
+ name TEXT,
12
+ current_state TEXT,
13
+ dependencies_satisfied BOOLEAN,
14
+ retry_eligible BOOLEAN,
15
+ ready_for_execution BOOLEAN,
16
+ last_failure_at TIMESTAMP,
17
+ next_retry_at TIMESTAMP,
18
+ total_parents INTEGER,
19
+ completed_parents INTEGER,
20
+ attempts INTEGER,
21
+ retry_limit INTEGER,
22
+ backoff_request_seconds INTEGER,
23
+ last_attempted_at TIMESTAMP
24
+ ) LANGUAGE plpgsql STABLE AS $$
25
+ BEGIN
26
+ RETURN QUERY
27
+ SELECT
28
+ ws.workflow_step_id,
29
+ ws.task_id,
30
+ ws.named_step_id,
31
+ ns.name::TEXT,
32
+
33
+ -- Current State Information (optimized using most_recent flag)
34
+ COALESCE(current_state.to_state, 'pending')::TEXT as current_state,
35
+
36
+ -- Dependency Analysis (calculated from direct joins)
37
+ CASE
38
+ WHEN dep_edges.to_step_id IS NULL THEN true -- Root steps (no parents)
39
+ WHEN COUNT(dep_edges.from_step_id) = 0 THEN true -- Steps with zero dependencies
40
+ WHEN COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END) = COUNT(dep_edges.from_step_id) THEN true
41
+ ELSE false
42
+ END as dependencies_satisfied,
43
+
44
+ -- Simplified Retry & Backoff Analysis
45
+ CASE
46
+ WHEN ws.attempts >= COALESCE(ws.retry_limit, 3) THEN false
47
+ WHEN ws.attempts > 0 AND COALESCE(ws.retryable, true) = false THEN false
48
+ WHEN last_failure.created_at IS NULL THEN true
49
+ WHEN ws.backoff_request_seconds IS NOT NULL AND ws.last_attempted_at IS NOT NULL THEN
50
+ ws.last_attempted_at + (ws.backoff_request_seconds * interval '1 second') <= NOW()
51
+ WHEN last_failure.created_at IS NOT NULL THEN
52
+ last_failure.created_at + (
53
+ LEAST(power(2, COALESCE(ws.attempts, 1)) * interval '1 second', interval '30 seconds')
54
+ ) <= NOW()
55
+ ELSE true
56
+ END as retry_eligible,
57
+
58
+ -- Simplified Final Readiness Calculation
59
+ CASE
60
+ WHEN COALESCE(current_state.to_state, 'pending') IN ('pending', 'error')
61
+ AND (ws.processed = false OR ws.processed IS NULL) -- CRITICAL: Only unprocessed steps can be ready
62
+ AND (dep_edges.to_step_id IS NULL OR
63
+ COUNT(dep_edges.from_step_id) = 0 OR
64
+ COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END) = COUNT(dep_edges.from_step_id))
65
+ AND (ws.attempts < COALESCE(ws.retry_limit, 3))
66
+ AND (COALESCE(ws.retryable, true) = true)
67
+ AND (ws.in_process = false OR ws.in_process IS NULL)
68
+ AND (
69
+ -- Check explicit backoff timing (most restrictive)
70
+ -- If backoff is set, the backoff period must have expired
71
+ CASE
72
+ WHEN ws.backoff_request_seconds IS NOT NULL AND ws.last_attempted_at IS NOT NULL THEN
73
+ ws.last_attempted_at + (ws.backoff_request_seconds * interval '1 second') <= NOW()
74
+ ELSE true -- No explicit backoff set
75
+ END
76
+ AND
77
+ -- Then check failure-based backoff
78
+ (last_failure.created_at IS NULL OR
79
+ last_failure.created_at + (LEAST(power(2, COALESCE(ws.attempts, 1)) * interval '1 second', interval '30 seconds')) <= NOW())
80
+ )
81
+ THEN true
82
+ ELSE false
83
+ END as ready_for_execution,
84
+
85
+ -- Timing Information
86
+ last_failure.created_at as last_failure_at,
87
+ CASE
88
+ WHEN ws.backoff_request_seconds IS NOT NULL AND ws.last_attempted_at IS NOT NULL THEN
89
+ ws.last_attempted_at + (ws.backoff_request_seconds * interval '1 second')
90
+ WHEN last_failure.created_at IS NOT NULL THEN
91
+ last_failure.created_at + (LEAST(power(2, COALESCE(ws.attempts, 1)) * interval '1 second', interval '30 seconds'))
92
+ ELSE NULL
93
+ END as next_retry_at,
94
+
95
+ -- Dependency Context (calculated from joins)
96
+ COALESCE(COUNT(dep_edges.from_step_id), 0)::INTEGER as total_parents,
97
+ COALESCE(COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END), 0)::INTEGER as completed_parents,
98
+
99
+ -- Retry Context
100
+ ws.attempts,
101
+ COALESCE(ws.retry_limit, 3) as retry_limit,
102
+ ws.backoff_request_seconds,
103
+ ws.last_attempted_at
104
+
105
+ FROM tasker_workflow_steps ws
106
+ JOIN tasker_named_steps ns ON ns.named_step_id = ws.named_step_id
107
+
108
+ -- OPTIMIZED: Current State using most_recent flag instead of DISTINCT ON
109
+ LEFT JOIN tasker_workflow_step_transitions current_state
110
+ ON current_state.workflow_step_id = ws.workflow_step_id
111
+ AND current_state.most_recent = true
112
+
113
+ -- OPTIMIZED: Dependency check using direct joins (no subquery)
114
+ LEFT JOIN tasker_workflow_step_edges dep_edges
115
+ ON dep_edges.to_step_id = ws.workflow_step_id
116
+ LEFT JOIN tasker_workflow_step_transitions parent_states
117
+ ON parent_states.workflow_step_id = dep_edges.from_step_id
118
+ AND parent_states.most_recent = true
119
+
120
+ -- OPTIMIZED: Last failure using index-optimized approach
121
+ LEFT JOIN tasker_workflow_step_transitions last_failure
122
+ ON last_failure.workflow_step_id = ws.workflow_step_id
123
+ AND last_failure.to_state = 'error'
124
+ AND last_failure.most_recent = true
125
+
126
+ -- KEY PERFORMANCE IMPROVEMENT: Filter by task first, then optionally by step IDs
127
+ -- CRITICAL FIX: Include ALL steps for task execution context calculation
128
+ -- Only filter by processed status when specifically querying for ready steps
129
+ WHERE ws.task_id = input_task_id
130
+ AND (step_ids IS NULL OR ws.workflow_step_id = ANY(step_ids))
131
+
132
+ GROUP BY
133
+ ws.workflow_step_id, ws.task_id, ws.named_step_id, ns.name,
134
+ current_state.to_state, last_failure.created_at,
135
+ ws.attempts, ws.retry_limit, ws.backoff_request_seconds, ws.last_attempted_at,
136
+ ws.in_process, ws.processed, ws.retryable, dep_edges.to_step_id,
137
+ current_state.workflow_step_id, last_failure.workflow_step_id;
138
+ END;
139
+ $$;