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,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tasker
4
+ module Orchestration
5
+ # StepSequenceFactory handles creation and management of step sequences
6
+ #
7
+ # This component is responsible for:
8
+ # - Getting workflow steps for tasks
9
+ # - Establishing step dependencies and defaults
10
+ # - Creating StepSequence objects
11
+ class StepSequenceFactory
12
+ class << self
13
+ # Get the step sequence for a task
14
+ #
15
+ # Retrieves all workflow steps for the task and establishes their dependencies.
16
+ #
17
+ # @param task [Tasker::Task] The task to get the sequence for
18
+ # @param task_handler [Object] The task handler instance
19
+ # @return [Tasker::Types::StepSequence] The sequence of workflow steps
20
+ delegate :get_sequence, to: :new
21
+
22
+ # Create sequence for a task (used during task initialization)
23
+ #
24
+ # @param task [Tasker::Task] The task to create sequence for
25
+ # @param task_handler [Object] The task handler instance
26
+ # @return [Tasker::Types::StepSequence] The created sequence
27
+ delegate :create_sequence_for_task!, to: :new
28
+ end
29
+
30
+ # Get the step sequence for a task
31
+ #
32
+ # @param task [Tasker::Task] The task to get the sequence for
33
+ # @param task_handler [Object] The task handler instance
34
+ # @return [Tasker::Types::StepSequence] The sequence of workflow steps
35
+ def get_sequence(task, task_handler)
36
+ steps = Tasker::WorkflowStep.get_steps_for_task(task, task_handler.step_templates)
37
+ establish_step_dependencies_and_defaults(task, steps, task_handler)
38
+ Tasker::Types::StepSequence.new(steps: steps)
39
+ end
40
+
41
+ # Create sequence for a task (used during task initialization)
42
+ #
43
+ # @param task [Tasker::Task] The task to create sequence for
44
+ # @param task_handler [Object] The task handler instance
45
+ # @return [Tasker::Types::StepSequence] The created sequence
46
+ def create_sequence_for_task!(task, task_handler)
47
+ steps = Tasker::WorkflowStep.get_steps_for_task(task, task_handler.step_templates)
48
+ establish_step_dependencies_and_defaults(task, steps, task_handler)
49
+ Tasker::Types::StepSequence.new(steps: steps)
50
+ end
51
+
52
+ private
53
+
54
+ # Establish step dependencies and defaults using task handler hook
55
+ #
56
+ # @param task [Tasker::Task] The task being processed
57
+ # @param steps [Array<Tasker::WorkflowStep>] The steps to establish dependencies for
58
+ # @param task_handler [Object] The task handler instance
59
+ def establish_step_dependencies_and_defaults(task, steps, task_handler)
60
+ # Call the task handler's hook method if it exists
61
+ return unless task_handler.respond_to?(:establish_step_dependencies_and_defaults)
62
+
63
+ task_handler.establish_step_dependencies_and_defaults(task, steps)
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,564 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../concerns/idempotent_state_transitions'
4
+ require_relative '../concerns/event_publisher'
5
+ require_relative '../task_handler/step_group'
6
+ require_relative 'task_reenqueuer'
7
+ require_relative '../functions/function_based_task_execution_context'
8
+
9
+ module Tasker
10
+ module Orchestration
11
+ # TaskFinalizer handles task completion and finalization logic
12
+ #
13
+ # This class provides implementation for task finalization while firing
14
+ # lifecycle events for observability. Enhanced with TaskExecutionContext
15
+ # integration for intelligent decision making.
16
+ class TaskFinalizer
17
+ include Tasker::Concerns::IdempotentStateTransitions
18
+ include Tasker::Concerns::EventPublisher
19
+
20
+ # Check if the task is blocked by errors
21
+ #
22
+ # @param task [Tasker::Task] The task to check
23
+ # @param _sequence [Tasker::Types::StepSequence] The step sequence (unused)
24
+ # @param _processed_steps [Array<Tasker::WorkflowStep>] Recently processed steps (unused)
25
+ # @return [Boolean] True if task is blocked by errors
26
+ def blocked_by_errors?(task, _sequence, _processed_steps)
27
+ BlockageChecker.blocked_by_errors?(task)
28
+ end
29
+
30
+ # Finalize a task with processed steps
31
+ #
32
+ # @param task [Tasker::Task] The task to finalize
33
+ # @param _sequence [Tasker::Types::StepSequence] The step sequence (unused)
34
+ # @param processed_steps [Array<Tasker::WorkflowStep>] All processed steps
35
+ def finalize_task_with_steps(task, _sequence, processed_steps)
36
+ FinalizationProcessor.finalize_with_steps(task, processed_steps, self)
37
+ end
38
+
39
+ # Finalize a task based on its current state using TaskExecutionContext
40
+ #
41
+ # @param task_id [Integer] The task ID to finalize
42
+ # @param synchronous [Boolean] Whether this is synchronous processing (default: false)
43
+ def finalize_task(task_id, synchronous: false)
44
+ task = Tasker::Task.find(task_id)
45
+ context = ContextManager.get_task_execution_context(task_id)
46
+
47
+ FinalizationDecisionMaker.make_finalization_decision(task, context, synchronous, self)
48
+ end
49
+
50
+ # Handle no viable steps event
51
+ #
52
+ # Convenience method for event-driven workflows when no viable steps are found.
53
+ # This triggers task finalization to determine next action.
54
+ #
55
+ # @param event [Hash] Event payload with task_id
56
+ def handle_no_viable_steps(event)
57
+ task_id = event[:task_id] || event
58
+ finalize_task(task_id)
59
+ end
60
+
61
+ # Service method exposed for FinalizationDecisionMaker
62
+ def complete_task(task, context)
63
+ payload = {
64
+ task: task,
65
+ completed_at: Time.current,
66
+ completion_percentage: context&.completion_percentage,
67
+ total_steps: context&.total_steps,
68
+ health_status: context&.health_status
69
+ }
70
+
71
+ # Ensure task is in in_progress state before transitioning to complete
72
+ current_state = task.state_machine.current_state || Constants::TaskStatuses::PENDING
73
+
74
+ Rails.logger.debug { "TaskFinalizer: Task #{task.task_id} current state is #{current_state}" }
75
+ # If task is already complete, just publish the event
76
+ if current_state == Constants::TaskStatuses::COMPLETE
77
+ return unless task.update({ complete: true })
78
+
79
+ publish_task_completed(**payload)
80
+ return
81
+ end
82
+
83
+ # Handle task in error state - must go through pending first
84
+ if current_state == Constants::TaskStatuses::ERROR
85
+ return unless safe_transition_to(task, Constants::TaskStatuses::PENDING)
86
+
87
+ Rails.logger.debug { "TaskFinalizer: Task #{task.task_id} transitioning from error to pending" }
88
+ # Reset current state to pending for next transition
89
+ # This is necessary because the state machine might not allow direct transition from error to complete
90
+ # without going through pending first
91
+ current_state = Constants::TaskStatuses::PENDING
92
+ end
93
+
94
+ # Ensure task is in in_progress state (transition only if not already there)
95
+ if current_state != Constants::TaskStatuses::IN_PROGRESS && !safe_transition_to(task,
96
+ Constants::TaskStatuses::IN_PROGRESS)
97
+ return
98
+ end
99
+
100
+ # Now transition to complete - always attempt this transition
101
+ Rails.logger.debug { "TaskFinalizer: Task #{task.task_id} transitioning to complete" }
102
+ ActiveRecord::Base.transaction do
103
+ task.update!({ complete: true })
104
+ unless safe_transition_to(task, Constants::TaskStatuses::COMPLETE)
105
+ raise ActiveRecord::Rollback, "Failed to transition task #{task.task_id} to complete state"
106
+ end
107
+ end
108
+ publish_task_completed(task, **payload)
109
+ Rails.logger.info("TaskFinalizer: Task #{task.task_id} completed successfully (#{context&.total_steps} steps,
110
+ #{context&.completion_percentage}% complete)")
111
+ end
112
+
113
+ # Service method exposed for FinalizationDecisionMaker
114
+ def error_task(task, context)
115
+ return unless safe_transition_to(task, Constants::TaskStatuses::ERROR)
116
+
117
+ publish_task_failed(
118
+ task,
119
+ error_message: Constants::TaskFinalization::ErrorMessages::STEPS_IN_ERROR_STATE,
120
+ failed_steps_count: context&.failed_steps,
121
+ completion_percentage: context&.completion_percentage,
122
+ health_status: context&.health_status,
123
+ total_steps: context&.total_steps
124
+ )
125
+
126
+ Rails.logger.info("TaskFinalizer: Task #{task.task_id} failed - #{context&.failed_steps} failed steps, #{context&.health_status} health")
127
+ end
128
+
129
+ # Service method exposed for FinalizationDecisionMaker
130
+ def pending_task(task, context, reason: nil)
131
+ return unless safe_transition_to(task, Constants::TaskStatuses::PENDING)
132
+
133
+ reason ||= ReasonDeterminer.determine_pending_reason(context)
134
+
135
+ publish_task_pending_transition(
136
+ task,
137
+ reason: reason,
138
+ ready_steps: context&.ready_steps,
139
+ in_progress_steps: context&.in_progress_steps,
140
+ completion_percentage: context&.completion_percentage,
141
+ health_status: context&.health_status
142
+ )
143
+
144
+ Rails.logger.info("TaskFinalizer: Task #{task.task_id} set to pending - #{reason} (ready_steps: #{context&.ready_steps}, in_progress: #{context&.in_progress_steps})")
145
+ end
146
+
147
+ # Service method exposed for FinalizationDecisionMaker
148
+ def reenqueue_task_with_context(task, context, reason: nil)
149
+ ReenqueueManager.reenqueue_with_context(task, context, reason)
150
+ end
151
+
152
+ # Service method exposed for event publishing
153
+ def publish_finalization_started(task, processed_steps, context)
154
+ publish_task_finalization_started(
155
+ task,
156
+ processed_steps_count: processed_steps.size,
157
+ execution_status: context&.execution_status,
158
+ health_status: context&.health_status,
159
+ completion_percentage: context&.completion_percentage,
160
+ total_steps: context&.total_steps,
161
+ ready_steps: context&.ready_steps,
162
+ failed_steps: context&.failed_steps,
163
+ recommended_action: context&.recommended_action
164
+ )
165
+ end
166
+
167
+ # Service method exposed for event publishing
168
+ def publish_finalization_completed(task, processed_steps, context)
169
+ publish_task_finalization_completed(
170
+ task,
171
+ processed_steps_count: processed_steps.size,
172
+ execution_status: context&.execution_status,
173
+ health_status: context&.health_status,
174
+ completion_percentage: context&.completion_percentage,
175
+ total_steps: context&.total_steps,
176
+ ready_steps: context&.ready_steps,
177
+ failed_steps: context&.failed_steps,
178
+ recommended_action: context&.recommended_action
179
+ )
180
+ end
181
+
182
+ # Service class to check task blockage by errors
183
+ # Uses function-based implementation for reliable performance
184
+ class BlockageChecker
185
+ class << self
186
+ # Check if the task is blocked by errors
187
+ #
188
+ # @param task [Tasker::Task] The task to check
189
+ # @return [Boolean] True if task is blocked by errors
190
+ def blocked_by_errors?(task)
191
+ context = ContextManager.get_task_execution_context(task.task_id)
192
+
193
+ # If no context is available, the task has no steps or doesn't exist
194
+ # In either case, it's not blocked by errors
195
+ return false unless context
196
+
197
+ context.execution_status == Constants::TaskExecution::ExecutionStatus::BLOCKED_BY_FAILURES
198
+ end
199
+ end
200
+ end
201
+
202
+ # Service class to manage task execution context
203
+ # Uses the new function-based implementations for reliable performance
204
+ class ContextManager
205
+ class << self
206
+ # Get TaskExecutionContext using function-based implementation
207
+ #
208
+ # @param task_id [Integer] The task ID
209
+ # @return [Tasker::Functions::FunctionBasedTaskExecutionContext, nil] The execution context or nil
210
+ def get_task_execution_context(task_id)
211
+ # Use our new function-based implementation - it should always return data or nil
212
+ Tasker::Functions::FunctionBasedTaskExecutionContext.find(task_id)
213
+ end
214
+ end
215
+ end
216
+
217
+ # Service class to process finalization with steps
218
+ # Reduces complexity by organizing step processing logic
219
+ class FinalizationProcessor
220
+ class << self
221
+ # Finalize task with processed steps
222
+ #
223
+ # @param task [Tasker::Task] The task to finalize
224
+ # @param processed_steps [Array<Tasker::WorkflowStep>] All processed steps
225
+ # @param finalizer [TaskFinalizer] The finalizer instance for callbacks
226
+ def finalize_with_steps(task, processed_steps, finalizer)
227
+ context = ContextManager.get_task_execution_context(task.task_id)
228
+
229
+ # Fire finalization started event
230
+ finalizer.publish_finalization_started(task, processed_steps, context)
231
+
232
+ # Use context-enhanced finalization logic with synchronous flag
233
+ finalizer.finalize_task(task.task_id, synchronous: true)
234
+
235
+ # Fire finalization completed event
236
+ final_context = ContextManager.get_task_execution_context(task.task_id)
237
+ finalizer.publish_finalization_completed(task, processed_steps, final_context)
238
+ end
239
+ end
240
+ end
241
+
242
+ # Service class to make finalization decisions
243
+ # Reduces complexity by organizing decision-making logic
244
+ class FinalizationDecisionMaker
245
+ class << self
246
+ # Make finalization decision based on task state
247
+ #
248
+ # @param task [Tasker::Task] The task to finalize
249
+ # @param context [Tasker::TaskExecutionContext] The execution context
250
+ # @param synchronous [Boolean] Whether this is synchronous processing
251
+ # @param finalizer [TaskFinalizer] The finalizer instance for callbacks
252
+ def make_finalization_decision(task, context, synchronous, finalizer)
253
+ Rails.logger.info("TaskFinalizer: Making decision for task #{task.task_id} with execution_status: #{context&.execution_status}")
254
+
255
+ # DEBUG: Log detailed context information
256
+ if context
257
+ Rails.logger.info("TaskFinalizer: Task #{task.task_id} context details - ready_steps: #{context.ready_steps}, total_steps: #{context.total_steps}, pending_steps: #{context.pending_steps}, in_progress_steps: #{context.in_progress_steps}, completed_steps: #{context.completed_steps}, failed_steps: #{context.failed_steps}")
258
+ end
259
+
260
+ # Handle nil context case
261
+ unless context
262
+ Rails.logger.info("TaskFinalizer: Task #{task.task_id} - no context available, handling as unclear state")
263
+ UnclearStateHandler.handle(task, context, finalizer)
264
+ return
265
+ end
266
+
267
+ case context.execution_status
268
+ when Constants::TaskExecution::ExecutionStatus::ALL_COMPLETE
269
+ Rails.logger.info("TaskFinalizer: Task #{task.task_id} - calling complete_task")
270
+ finalizer.complete_task(task, context)
271
+ when Constants::TaskExecution::ExecutionStatus::BLOCKED_BY_FAILURES
272
+ Rails.logger.info("TaskFinalizer: Task #{task.task_id} - calling error_task")
273
+ finalizer.error_task(task, context)
274
+ when Constants::TaskExecution::ExecutionStatus::HAS_READY_STEPS
275
+ Rails.logger.info("TaskFinalizer: Task #{task.task_id} - has ready steps, should execute them")
276
+ handle_ready_steps_state(task, context, synchronous, finalizer)
277
+ when Constants::TaskExecution::ExecutionStatus::WAITING_FOR_DEPENDENCIES
278
+ Rails.logger.info("TaskFinalizer: Task #{task.task_id} - waiting for dependencies")
279
+ handle_waiting_state(task, context, synchronous, finalizer)
280
+ when Constants::TaskExecution::ExecutionStatus::PROCESSING
281
+ Rails.logger.info("TaskFinalizer: Task #{task.task_id} - handling processing state")
282
+ handle_processing_state(task, context, synchronous, finalizer)
283
+ else
284
+ Rails.logger.info("TaskFinalizer: Task #{task.task_id} - handling unclear state")
285
+ UnclearStateHandler.handle(task, context, finalizer)
286
+ end
287
+ end
288
+
289
+ private
290
+
291
+ # Handle ready steps state - should execute the ready steps
292
+ #
293
+ # @param task [Tasker::Task] The task
294
+ # @param context [Tasker::TaskExecutionContext] The execution context
295
+ # @param synchronous [Boolean] Whether this is synchronous processing
296
+ # @param finalizer [TaskFinalizer] The finalizer instance
297
+ def handle_ready_steps_state(task, context, synchronous, finalizer)
298
+ # When we have ready steps, we should execute them, not just wait
299
+ # For now, transition task to in_progress and reenqueue for step execution
300
+ Rails.logger.info("TaskFinalizer: Task #{task.task_id} has #{context.ready_steps} ready steps - transitioning to in_progress")
301
+
302
+ # Transition task to in_progress to indicate work is happening
303
+ current_state = task.state_machine.current_state
304
+ unless [Constants::TaskStatuses::IN_PROGRESS, Constants::TaskStatuses::COMPLETE].include?(current_state)
305
+ finalizer.safe_transition_to(task, Constants::TaskStatuses::IN_PROGRESS)
306
+ end
307
+
308
+ if synchronous
309
+ # In synchronous mode, we can't actually execute steps here
310
+ # The calling code should handle step execution
311
+ Rails.logger.info("TaskFinalizer: Task #{task.task_id} ready for synchronous step execution")
312
+ else
313
+ # In asynchronous mode, reenqueue immediately for step execution
314
+ finalizer.reenqueue_task_with_context(task, context,
315
+ reason: Constants::TaskFinalization::ReenqueueReasons::READY_STEPS_AVAILABLE)
316
+ end
317
+ end
318
+
319
+ # Handle waiting for dependencies state
320
+ #
321
+ # @param task [Tasker::Task] The task
322
+ # @param context [Tasker::TaskExecutionContext] The execution context
323
+ # @param synchronous [Boolean] Whether this is synchronous processing
324
+ # @param finalizer [TaskFinalizer] The finalizer instance
325
+ def handle_waiting_state(task, context, synchronous, finalizer)
326
+ if synchronous
327
+ finalizer.pending_task(task, context,
328
+ reason: Constants::TaskFinalization::PendingReasons::WAITING_FOR_DEPENDENCIES)
329
+ else
330
+ finalizer.reenqueue_task_with_context(task, context,
331
+ reason: Constants::TaskFinalization::ReenqueueReasons::AWAITING_DEPENDENCIES)
332
+ end
333
+ end
334
+
335
+ # Handle processing state
336
+ #
337
+ # @param task [Tasker::Task] The task
338
+ # @param context [Tasker::TaskExecutionContext] The execution context
339
+ # @param synchronous [Boolean] Whether this is synchronous processing
340
+ # @param finalizer [TaskFinalizer] The finalizer instance
341
+ def handle_processing_state(task, context, synchronous, finalizer)
342
+ if synchronous
343
+ finalizer.pending_task(task, context,
344
+ reason: Constants::TaskFinalization::PendingReasons::WAITING_FOR_STEP_COMPLETION)
345
+ else
346
+ finalizer.reenqueue_task_with_context(task, context,
347
+ reason: Constants::TaskFinalization::ReenqueueReasons::STEPS_IN_PROGRESS)
348
+ end
349
+ end
350
+ end
351
+ end
352
+
353
+ # Service class to determine reasons for pending/reenqueue
354
+ # Reduces complexity by organizing reason determination logic
355
+ class ReasonDeterminer
356
+ # Frozen hash for O(1) pending reason lookups
357
+ PENDING_REASON_MAP = {
358
+ Constants::TaskExecution::ExecutionStatus::HAS_READY_STEPS =>
359
+ Constants::TaskFinalization::PendingReasons::READY_FOR_PROCESSING,
360
+ Constants::TaskExecution::ExecutionStatus::WAITING_FOR_DEPENDENCIES =>
361
+ Constants::TaskFinalization::PendingReasons::WAITING_FOR_DEPENDENCIES,
362
+ Constants::TaskExecution::ExecutionStatus::PROCESSING =>
363
+ Constants::TaskFinalization::PendingReasons::WAITING_FOR_STEP_COMPLETION
364
+ }.freeze
365
+
366
+ # Frozen hash for O(1) reenqueue reason lookups
367
+ REENQUEUE_REASON_MAP = {
368
+ Constants::TaskExecution::ExecutionStatus::HAS_READY_STEPS =>
369
+ Constants::TaskFinalization::ReenqueueReasons::READY_STEPS_AVAILABLE,
370
+ Constants::TaskExecution::ExecutionStatus::WAITING_FOR_DEPENDENCIES =>
371
+ Constants::TaskFinalization::ReenqueueReasons::AWAITING_DEPENDENCIES,
372
+ Constants::TaskExecution::ExecutionStatus::PROCESSING =>
373
+ Constants::TaskFinalization::ReenqueueReasons::STEPS_IN_PROGRESS
374
+ }.freeze
375
+
376
+ class << self
377
+ # Determine reason for pending state
378
+ #
379
+ # @param context [Tasker::TaskExecutionContext] The execution context
380
+ # @return [String] The pending reason
381
+ def determine_pending_reason(context)
382
+ return Constants::TaskFinalization::PendingReasons::CONTEXT_UNAVAILABLE unless context
383
+
384
+ PENDING_REASON_MAP.fetch(
385
+ context.execution_status,
386
+ Constants::TaskFinalization::PendingReasons::WORKFLOW_PAUSED
387
+ )
388
+ end
389
+
390
+ # Determine reason for reenqueue
391
+ #
392
+ # @param context [Tasker::TaskExecutionContext] The execution context
393
+ # @return [String] The reenqueue reason
394
+ def determine_reenqueue_reason(context)
395
+ return Constants::TaskFinalization::ReenqueueReasons::CONTEXT_UNAVAILABLE unless context
396
+
397
+ REENQUEUE_REASON_MAP.fetch(
398
+ context.execution_status,
399
+ Constants::TaskFinalization::ReenqueueReasons::CONTINUING_WORKFLOW
400
+ )
401
+ end
402
+ end
403
+ end
404
+
405
+ # Service class to manage task reenqueuing
406
+ # Reduces complexity by organizing reenqueue logic
407
+ class ReenqueueManager
408
+ class << self
409
+ # Re-enqueue task with context intelligence
410
+ #
411
+ # @param task [Tasker::Task] The task to re-enqueue
412
+ # @param context [Tasker::TaskExecutionContext] The execution context
413
+ # @param reason [String] Optional reason override
414
+ def reenqueue_with_context(task, context, reason)
415
+ delay_seconds = DelayCalculator.calculate_reenqueue_delay(context)
416
+ reason ||= ReasonDeterminer.determine_reenqueue_reason(context)
417
+
418
+ task_reenqueuer = Tasker::Orchestration::TaskReenqueuer.new
419
+
420
+ if delay_seconds.positive?
421
+ task_reenqueuer.reenqueue_task_delayed(
422
+ task,
423
+ delay_seconds: delay_seconds,
424
+ reason: reason
425
+ )
426
+ else
427
+ task_reenqueuer.reenqueue_task(task, reason: reason)
428
+ end
429
+
430
+ Rails.logger.info("TaskFinalizer: Task #{task.task_id} re-enqueued - #{reason} (delay: #{delay_seconds}s, ready_steps: #{context&.ready_steps})")
431
+ end
432
+ end
433
+ end
434
+
435
+ # Service class to calculate delays
436
+ # Reduces complexity by organizing delay calculation logic
437
+ class DelayCalculator
438
+ class << self
439
+ # Get backoff configuration with memoization
440
+ #
441
+ # @return [Tasker::Types::BackoffConfig] The backoff configuration
442
+ def backoff_config
443
+ @backoff_config ||= Tasker.configuration.backoff
444
+ end
445
+
446
+ # Frozen hash for O(1) delay lookups with descriptive comments
447
+ # Values now use configurable backoff progression
448
+ def delay_map
449
+ @delay_map ||= {
450
+ Constants::TaskExecution::ExecutionStatus::HAS_READY_STEPS => backoff_config.reenqueue_delays[:has_ready_steps],
451
+ Constants::TaskExecution::ExecutionStatus::WAITING_FOR_DEPENDENCIES => backoff_config.reenqueue_delays[:waiting_for_dependencies],
452
+ Constants::TaskExecution::ExecutionStatus::PROCESSING => backoff_config.reenqueue_delays[:processing]
453
+ }.freeze
454
+ end
455
+
456
+ # Default delay for unclear states or no context
457
+ def default_delay
458
+ backoff_config.default_reenqueue_delay
459
+ end
460
+
461
+ # Maximum delay cap
462
+ def maximum_delay
463
+ backoff_config.max_backoff_seconds
464
+ end
465
+
466
+ # Calculate intelligent re-enqueue delay based on execution context and step backoff timing
467
+ #
468
+ # This method considers the actual backoff timing of failed steps to avoid
469
+ # reenqueuing tasks before any steps are ready for retry.
470
+ #
471
+ # @param context [Tasker::TaskExecutionContext] The execution context
472
+ # @return [Integer] Delay in seconds
473
+ def calculate_reenqueue_delay(context)
474
+ return default_delay unless context
475
+
476
+ # For waiting_for_dependencies status, check if we have failed steps with backoff timing
477
+ if context.execution_status == Constants::TaskExecution::ExecutionStatus::WAITING_FOR_DEPENDENCIES
478
+ optimal_delay = calculate_optimal_backoff_delay(context.task_id)
479
+ return optimal_delay if optimal_delay.positive?
480
+ end
481
+
482
+ delay_map.fetch(context.execution_status, default_delay)
483
+ end
484
+
485
+ private
486
+
487
+ # Calculate optimal delay based on step backoff timing
488
+ #
489
+ # Finds the step with the longest remaining backoff time and schedules
490
+ # the task to be reenqueued when that step becomes ready for retry.
491
+ #
492
+ # @param task_id [Integer] The task ID
493
+ # @return [Integer] Optimal delay in seconds, or 0 if no backoff needed
494
+ def calculate_optimal_backoff_delay(task_id)
495
+ # Get step readiness status for all steps in the task
496
+ step_statuses = Tasker::StepReadinessStatus.for_task(task_id)
497
+
498
+ # Find failed steps that have backoff timing, regardless of retry_eligible status
499
+ # This is because retry_eligible can be false due to timing, but we still want
500
+ # to schedule based on when the step will become retry-eligible
501
+ failed_steps_with_backoff = step_statuses.select do |step_status|
502
+ step_status.current_state == 'error' &&
503
+ !step_status.ready_for_execution &&
504
+ step_status.next_retry_at.present?
505
+ end
506
+
507
+ return 0 if failed_steps_with_backoff.empty?
508
+
509
+ # Find the step with the longest remaining backoff time
510
+ now = Time.current
511
+ max_delay = failed_steps_with_backoff.map do |step_status|
512
+ next_retry_time = step_status.next_retry_at
513
+ next_retry_time > now ? (next_retry_time - now).to_i : 0
514
+ end.max
515
+
516
+ # Add a configurable buffer time to ensure the step is definitely ready
517
+ # Cap the maximum delay to prevent excessive delays
518
+ buffer_time = backoff_config.buffer_seconds
519
+ [(max_delay || 0) + buffer_time, maximum_delay].min
520
+ end
521
+ end
522
+ end
523
+
524
+ # Service class to handle unclear task states
525
+ # Reduces complexity by organizing unclear state handling logic
526
+ class UnclearStateHandler
527
+ class << self
528
+ # Handle unclear task state
529
+ #
530
+ # @param task [Tasker::Task] The task
531
+ # @param context [Tasker::TaskExecutionContext] The execution context
532
+ # @param finalizer [TaskFinalizer] The finalizer instance
533
+ def handle(task, context, finalizer)
534
+ if context
535
+ Rails.logger.warn do
536
+ "TaskFinalizer: Task #{task.task_id} in unclear state: " \
537
+ "execution_status=#{context.execution_status}, " \
538
+ "health_status=#{context.health_status}, " \
539
+ "ready_steps=#{context.ready_steps}, " \
540
+ "failed_steps=#{context.failed_steps}, " \
541
+ "in_progress_steps=#{context.in_progress_steps}"
542
+ end
543
+
544
+ # Default to re-enqueuing with a longer delay for unclear states
545
+ finalizer.reenqueue_task_with_context(
546
+ task,
547
+ context,
548
+ reason: Constants::TaskFinalization::ReenqueueReasons::CONTINUING_WORKFLOW
549
+ )
550
+ else
551
+ Rails.logger.error("TaskFinalizer: Task #{task.task_id} has no execution context and unclear state")
552
+
553
+ # Without context, attempt to transition to error state
554
+ finalizer.error_task(
555
+ task,
556
+ nil # No context available
557
+ )
558
+ end
559
+ end
560
+ end
561
+ end
562
+ end
563
+ end
564
+ end