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.
- checksums.yaml +7 -0
- data/LICENSE +22 -0
- data/README.md +443 -0
- data/Rakefile +10 -0
- data/app/controllers/tasker/analytics_controller.rb +179 -0
- data/app/controllers/tasker/application_controller.rb +45 -0
- data/app/controllers/tasker/graphql_controller.rb +193 -0
- data/app/controllers/tasker/handlers_controller.rb +217 -0
- data/app/controllers/tasker/health_controller.rb +229 -0
- data/app/controllers/tasker/metrics_controller.rb +111 -0
- data/app/controllers/tasker/page_sort.rb +97 -0
- data/app/controllers/tasker/task_diagrams_controller.rb +30 -0
- data/app/controllers/tasker/tasks_controller.rb +123 -0
- data/app/controllers/tasker/workflow_steps_controller.rb +69 -0
- data/app/graphql/examples/all_tasks.graphql +22 -0
- data/app/graphql/examples/pending_tasks.graphql +23 -0
- data/app/graphql/tasker/graph_ql_types/annotation_type.rb +14 -0
- data/app/graphql/tasker/graph_ql_types/base_argument.rb +9 -0
- data/app/graphql/tasker/graph_ql_types/base_connection.rb +11 -0
- data/app/graphql/tasker/graph_ql_types/base_edge.rb +10 -0
- data/app/graphql/tasker/graph_ql_types/base_enum.rb +9 -0
- data/app/graphql/tasker/graph_ql_types/base_field.rb +10 -0
- data/app/graphql/tasker/graph_ql_types/base_input_object.rb +10 -0
- data/app/graphql/tasker/graph_ql_types/base_interface.rb +14 -0
- data/app/graphql/tasker/graph_ql_types/base_object.rb +10 -0
- data/app/graphql/tasker/graph_ql_types/base_scalar.rb +9 -0
- data/app/graphql/tasker/graph_ql_types/base_union.rb +11 -0
- data/app/graphql/tasker/graph_ql_types/dependent_system_object_map_type.rb +18 -0
- data/app/graphql/tasker/graph_ql_types/dependent_system_type.rb +13 -0
- data/app/graphql/tasker/graph_ql_types/mutation_type.rb +16 -0
- data/app/graphql/tasker/graph_ql_types/named_step_type.rb +16 -0
- data/app/graphql/tasker/graph_ql_types/named_task_type.rb +14 -0
- data/app/graphql/tasker/graph_ql_types/named_tasks_named_step_type.rb +19 -0
- data/app/graphql/tasker/graph_ql_types/node_type.rb +12 -0
- data/app/graphql/tasker/graph_ql_types/query_type.rb +20 -0
- data/app/graphql/tasker/graph_ql_types/task_annotation_type.rb +17 -0
- data/app/graphql/tasker/graph_ql_types/task_interface.rb +17 -0
- data/app/graphql/tasker/graph_ql_types/task_type.rb +26 -0
- data/app/graphql/tasker/graph_ql_types/workflow_step_type.rb +154 -0
- data/app/graphql/tasker/graph_ql_types.rb +42 -0
- data/app/graphql/tasker/mutations/base_mutation.rb +13 -0
- data/app/graphql/tasker/mutations/cancel_step.rb +29 -0
- data/app/graphql/tasker/mutations/cancel_task.rb +29 -0
- data/app/graphql/tasker/mutations/create_task.rb +52 -0
- data/app/graphql/tasker/mutations/update_step.rb +36 -0
- data/app/graphql/tasker/mutations/update_task.rb +41 -0
- data/app/graphql/tasker/queries/all_annotation_types.rb +17 -0
- data/app/graphql/tasker/queries/all_tasks.rb +23 -0
- data/app/graphql/tasker/queries/base_query.rb +9 -0
- data/app/graphql/tasker/queries/helpers.rb +16 -0
- data/app/graphql/tasker/queries/one_step.rb +24 -0
- data/app/graphql/tasker/queries/one_task.rb +18 -0
- data/app/graphql/tasker/queries/tasks_by_annotation.rb +31 -0
- data/app/graphql/tasker/queries/tasks_by_status.rb +30 -0
- data/app/graphql/tasker/tasker_rails_schema.rb +52 -0
- data/app/jobs/tasker/application_job.rb +8 -0
- data/app/jobs/tasker/metrics_export_job.rb +252 -0
- data/app/jobs/tasker/task_runner_job.rb +224 -0
- data/app/models/tasker/annotation_type.rb +26 -0
- data/app/models/tasker/application_record.rb +70 -0
- data/app/models/tasker/dependent_system.rb +26 -0
- data/app/models/tasker/dependent_system_object_map.rb +64 -0
- data/app/models/tasker/diagram/edge.rb +106 -0
- data/app/models/tasker/diagram/flowchart.rb +137 -0
- data/app/models/tasker/diagram/node.rb +99 -0
- data/app/models/tasker/named_step.rb +41 -0
- data/app/models/tasker/named_task.rb +121 -0
- data/app/models/tasker/named_tasks_named_step.rb +82 -0
- data/app/models/tasker/step_dag_relationship.rb +65 -0
- data/app/models/tasker/step_readiness_status.rb +59 -0
- data/app/models/tasker/task.rb +424 -0
- data/app/models/tasker/task_annotation.rb +36 -0
- data/app/models/tasker/task_diagram.rb +332 -0
- data/app/models/tasker/task_execution_context.rb +29 -0
- data/app/models/tasker/task_namespace.rb +41 -0
- data/app/models/tasker/task_transition.rb +235 -0
- data/app/models/tasker/workflow_step.rb +461 -0
- data/app/models/tasker/workflow_step_edge.rb +94 -0
- data/app/models/tasker/workflow_step_transition.rb +434 -0
- data/app/serializers/tasker/annotation_type_serializer.rb +8 -0
- data/app/serializers/tasker/handler_serializer.rb +109 -0
- data/app/serializers/tasker/task_annotation_serializer.rb +32 -0
- data/app/serializers/tasker/task_serializer.rb +168 -0
- data/app/serializers/tasker/workflow_step_serializer.rb +27 -0
- data/app/services/tasker/analytics_service.rb +409 -0
- data/app/views/tasker/task/_diagram.html.erb +32 -0
- data/config/initializers/dry_struct.rb +11 -0
- data/config/initializers/statesman.rb +6 -0
- data/config/initializers/tasker_orchestration.rb +17 -0
- data/config/initializers/time_formats.rb +4 -0
- data/config/routes.rb +34 -0
- data/config/tasker/subscriptions/example_integrations.yml +67 -0
- data/config/tasker/system_events.yml +305 -0
- data/db/functions/calculate_dependency_levels_v01.sql +45 -0
- data/db/functions/get_analytics_metrics_v01.sql +137 -0
- data/db/functions/get_slowest_steps_v01.sql +82 -0
- data/db/functions/get_slowest_tasks_v01.sql +96 -0
- data/db/functions/get_step_readiness_status_batch_v01.sql +140 -0
- data/db/functions/get_step_readiness_status_v01.sql +139 -0
- data/db/functions/get_system_health_counts_v01.sql +108 -0
- data/db/functions/get_task_execution_context_v01.sql +108 -0
- data/db/functions/get_task_execution_contexts_batch_v01.sql +104 -0
- data/db/init/schema.sql +2277 -0
- data/db/migrate/20250701165431_initial_tasker_schema.rb +116 -0
- data/db/views/tasker_step_dag_relationships_v01.sql +69 -0
- data/docs/APPLICATION_GENERATOR.md +384 -0
- data/docs/AUTH.md +1780 -0
- data/docs/CIRCUIT_BREAKER.md +224 -0
- data/docs/DEVELOPER_GUIDE.md +2665 -0
- data/docs/EVENT_SYSTEM.md +637 -0
- data/docs/EXECUTION_CONFIGURATION.md +341 -0
- data/docs/FLOW_CHART.md +149 -0
- data/docs/HEALTH.md +542 -0
- data/docs/METRICS.md +731 -0
- data/docs/OPTIMIZATION_PLAN.md +1479 -0
- data/docs/OVERVIEW.md +552 -0
- data/docs/QUICK_START.md +270 -0
- data/docs/REGISTRY_SYSTEMS.md +373 -0
- data/docs/REST_API.md +632 -0
- data/docs/ROADMAP.md +221 -0
- data/docs/SQL_FUNCTIONS.md +1408 -0
- data/docs/TASK_DIAGRAM.md +252 -0
- data/docs/TASK_EXECUTION_CONTROL_FLOW.md +237 -0
- data/docs/TELEMETRY.md +795 -0
- data/docs/TROUBLESHOOTING.md +756 -0
- data/docs/TaskHandlerGenerator.html +255 -0
- data/docs/Tasker/Analysis/RuntimeGraphAnalyzer.html +907 -0
- data/docs/Tasker/Analysis/TemplateGraphAnalyzer.html +1236 -0
- data/docs/Tasker/Analysis.html +117 -0
- data/docs/Tasker/AnalyticsController.html +450 -0
- data/docs/Tasker/AnalyticsService/BottleneckAnalytics.html +816 -0
- data/docs/Tasker/AnalyticsService/PerformanceAnalytics.html +586 -0
- data/docs/Tasker/AnalyticsService.html +2221 -0
- data/docs/Tasker/AnnotationType.html +137 -0
- data/docs/Tasker/AnnotationTypeSerializer.html +124 -0
- data/docs/Tasker/ApplicationController.html +147 -0
- data/docs/Tasker/ApplicationJob.html +128 -0
- data/docs/Tasker/ApplicationRecord.html +378 -0
- data/docs/Tasker/Authentication/AuthenticationError.html +124 -0
- data/docs/Tasker/Authentication/ConfigurationError.html +124 -0
- data/docs/Tasker/Authentication/Coordinator.html +242 -0
- data/docs/Tasker/Authentication/Interface.html +560 -0
- data/docs/Tasker/Authentication/InterfaceError.html +124 -0
- data/docs/Tasker/Authentication/NoneAuthenticator.html +338 -0
- data/docs/Tasker/Authentication.html +119 -0
- data/docs/Tasker/Authorization/AuthorizationError.html +139 -0
- data/docs/Tasker/Authorization/BaseCoordinator.html +927 -0
- data/docs/Tasker/Authorization/ConfigurationError.html +153 -0
- data/docs/Tasker/Authorization/ResourceConstants/ACTIONS.html +428 -0
- data/docs/Tasker/Authorization/ResourceConstants/RESOURCES.html +365 -0
- data/docs/Tasker/Authorization/ResourceConstants.html +146 -0
- data/docs/Tasker/Authorization/ResourceRegistry.html +882 -0
- data/docs/Tasker/Authorization/UnauthorizedError.html +153 -0
- data/docs/Tasker/Authorization.html +582 -0
- data/docs/Tasker/CacheCapabilities.html +167 -0
- data/docs/Tasker/CacheStrategy.html +1297 -0
- data/docs/Tasker/Concerns/Authenticatable.html +116 -0
- data/docs/Tasker/Concerns/Authorizable/AdminStatusChecker.html +256 -0
- data/docs/Tasker/Concerns/Authorizable.html +816 -0
- data/docs/Tasker/Concerns/ControllerAuthorizable.html +157 -0
- data/docs/Tasker/Concerns/EventPublisher.html +4023 -0
- data/docs/Tasker/Concerns/IdempotentStateTransitions.html +806 -0
- data/docs/Tasker/Concerns/LifecycleEventHelpers.html +129 -0
- data/docs/Tasker/Concerns/OrchestrationPublisher.html +129 -0
- data/docs/Tasker/Concerns/StateMachineBase/ClassMethods.html +1075 -0
- data/docs/Tasker/Concerns/StateMachineBase/StateMachineBase/ClassMethods.html +191 -0
- data/docs/Tasker/Concerns/StateMachineBase/StateMachineBase.html +126 -0
- data/docs/Tasker/Concerns/StateMachineBase.html +153 -0
- data/docs/Tasker/Concerns/StructuredLogging.html +1413 -0
- data/docs/Tasker/Concerns.html +117 -0
- data/docs/Tasker/Configuration/AuthConfiguration.html +1023 -0
- data/docs/Tasker/Configuration/ConfigurationProxy.html +581 -0
- data/docs/Tasker/Configuration/DatabaseConfiguration.html +475 -0
- data/docs/Tasker/Configuration/EngineConfiguration.html +1265 -0
- data/docs/Tasker/Configuration/HealthConfiguration.html +791 -0
- data/docs/Tasker/Configuration/TelemetryConfiguration.html +1308 -0
- data/docs/Tasker/Configuration/TelemetryConfigurationProxy.html +388 -0
- data/docs/Tasker/Configuration.html +1669 -0
- data/docs/Tasker/ConfigurationError.html +143 -0
- data/docs/Tasker/ConfiguredTask.html +514 -0
- data/docs/Tasker/Constants/EventDefinitions.html +590 -0
- data/docs/Tasker/Constants/LifecycleEvents.html +137 -0
- data/docs/Tasker/Constants/ObservabilityEvents/Step.html +152 -0
- data/docs/Tasker/Constants/ObservabilityEvents/Task.html +142 -0
- data/docs/Tasker/Constants/ObservabilityEvents.html +126 -0
- data/docs/Tasker/Constants/RegistryEvents.html +285 -0
- data/docs/Tasker/Constants/StepEvents.html +177 -0
- data/docs/Tasker/Constants/TaskEvents.html +167 -0
- data/docs/Tasker/Constants/TaskExecution/ExecutionStatus.html +207 -0
- data/docs/Tasker/Constants/TaskExecution/HealthStatus.html +191 -0
- data/docs/Tasker/Constants/TaskExecution/RecommendedAction.html +207 -0
- data/docs/Tasker/Constants/TaskExecution.html +126 -0
- data/docs/Tasker/Constants/TaskFinalization/ErrorMessages.html +132 -0
- data/docs/Tasker/Constants/TaskFinalization/PendingReasons.html +207 -0
- data/docs/Tasker/Constants/TaskFinalization/ReenqueueReasons.html +239 -0
- data/docs/Tasker/Constants/TaskFinalization.html +126 -0
- data/docs/Tasker/Constants/TaskStatuses.html +223 -0
- data/docs/Tasker/Constants/TestEvents.html +163 -0
- data/docs/Tasker/Constants/WorkflowEvents.html +222 -0
- data/docs/Tasker/Constants/WorkflowStepStatuses.html +223 -0
- data/docs/Tasker/Constants.html +561 -0
- data/docs/Tasker/DependentSystem.html +137 -0
- data/docs/Tasker/DependentSystemObjectMap.html +250 -0
- data/docs/Tasker/DetectorRegistry.html +598 -0
- data/docs/Tasker/Diagram/Edge.html +1191 -0
- data/docs/Tasker/Diagram/Flowchart.html +1539 -0
- data/docs/Tasker/Diagram/Node.html +1165 -0
- data/docs/Tasker/Diagram.html +117 -0
- data/docs/Tasker/Engine.html +215 -0
- data/docs/Tasker/Error.html +139 -0
- data/docs/Tasker/Events/Bus.html +1226 -0
- data/docs/Tasker/Events/Catalog/CatalogPrinter.html +258 -0
- data/docs/Tasker/Events/Catalog/CustomEventRegistrar.html +276 -0
- data/docs/Tasker/Events/Catalog/ExamplePayloadGenerator.html +294 -0
- data/docs/Tasker/Events/Catalog.html +1291 -0
- data/docs/Tasker/Events/CustomRegistry.html +943 -0
- data/docs/Tasker/Events/DefinitionLoader.html +575 -0
- data/docs/Tasker/Events/EventPayloadBuilder/ErrorInfoExtractor.html +286 -0
- data/docs/Tasker/Events/EventPayloadBuilder/StepPayloadBuilder.html +312 -0
- data/docs/Tasker/Events/EventPayloadBuilder.html +664 -0
- data/docs/Tasker/Events/Publisher.html +365 -0
- data/docs/Tasker/Events/Subscribers/BaseSubscriber/ErrorCategorizer/ErrorTypeClassifier.html +1128 -0
- data/docs/Tasker/Events/Subscribers/BaseSubscriber/ErrorCategorizer.html +270 -0
- data/docs/Tasker/Events/Subscribers/BaseSubscriber/MetricTagsExtractor.html +266 -0
- data/docs/Tasker/Events/Subscribers/BaseSubscriber.html +2556 -0
- data/docs/Tasker/Events/Subscribers/MetricsSubscriber.html +723 -0
- data/docs/Tasker/Events/Subscribers/TelemetrySubscriber.html +2251 -0
- data/docs/Tasker/Events/Subscribers.html +117 -0
- data/docs/Tasker/Events/SubscriptionLoader.html +493 -0
- data/docs/Tasker/Events.html +294 -0
- data/docs/Tasker/EventsGenerator.html +459 -0
- data/docs/Tasker/Functions/FunctionBasedAnalyticsMetrics/AnalyticsMetrics.html +135 -0
- data/docs/Tasker/Functions/FunctionBasedAnalyticsMetrics.html +412 -0
- data/docs/Tasker/Functions/FunctionBasedDependencyLevels.html +598 -0
- data/docs/Tasker/Functions/FunctionBasedSlowestSteps/SlowestStep.html +135 -0
- data/docs/Tasker/Functions/FunctionBasedSlowestSteps.html +453 -0
- data/docs/Tasker/Functions/FunctionBasedSlowestTasks/SlowestTask.html +135 -0
- data/docs/Tasker/Functions/FunctionBasedSlowestTasks.html +453 -0
- data/docs/Tasker/Functions/FunctionBasedStepReadinessStatus.html +1457 -0
- data/docs/Tasker/Functions/FunctionBasedSystemHealthCounts/HealthMetrics.html +135 -0
- data/docs/Tasker/Functions/FunctionBasedSystemHealthCounts.html +370 -0
- data/docs/Tasker/Functions/FunctionBasedTaskExecutionContext.html +1250 -0
- data/docs/Tasker/Functions/FunctionWrapper.html +479 -0
- data/docs/Tasker/Functions.html +117 -0
- data/docs/Tasker/Generators/AuthenticatorGenerator/UsageInstructionsFormatter.html +244 -0
- data/docs/Tasker/Generators/AuthenticatorGenerator.html +373 -0
- data/docs/Tasker/Generators/AuthorizationCoordinatorGenerator.html +430 -0
- data/docs/Tasker/Generators/SubscriberGenerator.html +377 -0
- data/docs/Tasker/Generators/TaskHandlerGenerator.html +263 -0
- data/docs/Tasker/Generators.html +117 -0
- data/docs/Tasker/GraphQLTypes/AnnotationType.html +132 -0
- data/docs/Tasker/GraphQLTypes/BaseArgument.html +124 -0
- data/docs/Tasker/GraphQLTypes/BaseConnection.html +124 -0
- data/docs/Tasker/GraphQLTypes/BaseEdge.html +130 -0
- data/docs/Tasker/GraphQLTypes/BaseEnum.html +124 -0
- data/docs/Tasker/GraphQLTypes/BaseField.html +124 -0
- data/docs/Tasker/GraphQLTypes/BaseInputObject.html +124 -0
- data/docs/Tasker/GraphQLTypes/BaseInterface.html +116 -0
- data/docs/Tasker/GraphQLTypes/BaseObject.html +128 -0
- data/docs/Tasker/GraphQLTypes/BaseScalar.html +124 -0
- data/docs/Tasker/GraphQLTypes/BaseUnion.html +124 -0
- data/docs/Tasker/GraphQLTypes/DependentSystemObjectMapType.html +132 -0
- data/docs/Tasker/GraphQLTypes/DependentSystemType.html +132 -0
- data/docs/Tasker/GraphQLTypes/MutationType.html +132 -0
- data/docs/Tasker/GraphQLTypes/NamedStepType.html +132 -0
- data/docs/Tasker/GraphQLTypes/NamedTaskType.html +132 -0
- data/docs/Tasker/GraphQLTypes/NamedTasksNamedStepType.html +132 -0
- data/docs/Tasker/GraphQLTypes/NodeType.html +118 -0
- data/docs/Tasker/GraphQLTypes/QueryType.html +139 -0
- data/docs/Tasker/GraphQLTypes/TaskAnnotationType.html +132 -0
- data/docs/Tasker/GraphQLTypes/TaskInterface.html +111 -0
- data/docs/Tasker/GraphQLTypes/TaskType.html +201 -0
- data/docs/Tasker/GraphQLTypes/WorkflowStepType.html +694 -0
- data/docs/Tasker/GraphQLTypes.html +130 -0
- data/docs/Tasker/GraphqlController.html +251 -0
- data/docs/Tasker/HandlerFactory.html +1518 -0
- data/docs/Tasker/HandlerSerializer.html +682 -0
- data/docs/Tasker/HandlersController.html +574 -0
- data/docs/Tasker/HashIdentityStrategy.html +278 -0
- data/docs/Tasker/Health/ReadinessChecker.html +712 -0
- data/docs/Tasker/Health/StatusChecker.html +653 -0
- data/docs/Tasker/Health.html +117 -0
- data/docs/Tasker/HealthController.html +523 -0
- data/docs/Tasker/IdentityStrategy.html +276 -0
- data/docs/Tasker/InvalidTaskHandlerConfig.html +135 -0
- data/docs/Tasker/LifecycleEvents/Events/Step.html +162 -0
- data/docs/Tasker/LifecycleEvents/Events/Task.html +162 -0
- data/docs/Tasker/LifecycleEvents/Events.html +204 -0
- data/docs/Tasker/LifecycleEvents/Publisher.html +132 -0
- data/docs/Tasker/LifecycleEvents.html +799 -0
- data/docs/Tasker/Logging/CorrelationIdGenerator.html +688 -0
- data/docs/Tasker/Logging.html +115 -0
- data/docs/Tasker/MetricsController.html +293 -0
- data/docs/Tasker/MetricsExportJob.html +414 -0
- data/docs/Tasker/Mutations/BaseMutation.html +128 -0
- data/docs/Tasker/Mutations/CancelStep.html +219 -0
- data/docs/Tasker/Mutations/CancelTask.html +221 -0
- data/docs/Tasker/Mutations/CreateTask.html +243 -0
- data/docs/Tasker/Mutations/UpdateStep.html +243 -0
- data/docs/Tasker/Mutations/UpdateTask.html +243 -0
- data/docs/Tasker/Mutations.html +117 -0
- data/docs/Tasker/NamedStep.html +216 -0
- data/docs/Tasker/NamedTask.html +910 -0
- data/docs/Tasker/NamedTasksNamedStep.html +435 -0
- data/docs/Tasker/Orchestration/BackoffCalculator.html +404 -0
- data/docs/Tasker/Orchestration/ConnectionBuilder/ConfigValidator.html +258 -0
- data/docs/Tasker/Orchestration/ConnectionBuilder.html +435 -0
- data/docs/Tasker/Orchestration/ConnectionPoolIntelligence.html +513 -0
- data/docs/Tasker/Orchestration/Coordinator.html +641 -0
- data/docs/Tasker/Orchestration/FutureStateAnalyzer.html +1045 -0
- data/docs/Tasker/Orchestration/Orchestrator.html +679 -0
- data/docs/Tasker/Orchestration/PluginIntegration.html +1127 -0
- data/docs/Tasker/Orchestration/ResponseProcessor.html +504 -0
- data/docs/Tasker/Orchestration/RetryHeaderParser.html +304 -0
- data/docs/Tasker/Orchestration/StepExecutor.html +995 -0
- data/docs/Tasker/Orchestration/StepSequenceFactory.html +644 -0
- data/docs/Tasker/Orchestration/TaskFinalizer/BlockageChecker.html +264 -0
- data/docs/Tasker/Orchestration/TaskFinalizer/ContextManager.html +254 -0
- data/docs/Tasker/Orchestration/TaskFinalizer/DelayCalculator.html +556 -0
- data/docs/Tasker/Orchestration/TaskFinalizer/FinalizationDecisionMaker.html +348 -0
- data/docs/Tasker/Orchestration/TaskFinalizer/FinalizationProcessor.html +286 -0
- data/docs/Tasker/Orchestration/TaskFinalizer/ReasonDeterminer.html +432 -0
- data/docs/Tasker/Orchestration/TaskFinalizer/ReenqueueManager.html +296 -0
- data/docs/Tasker/Orchestration/TaskFinalizer/UnclearStateHandler.html +314 -0
- data/docs/Tasker/Orchestration/TaskFinalizer.html +1212 -0
- data/docs/Tasker/Orchestration/TaskInitializer.html +766 -0
- data/docs/Tasker/Orchestration/TaskReenqueuer.html +506 -0
- data/docs/Tasker/Orchestration/ViableStepDiscovery.html +442 -0
- data/docs/Tasker/Orchestration/WorkflowCoordinator.html +510 -0
- data/docs/Tasker/Orchestration.html +130 -0
- data/docs/Tasker/PageSort/PageSortParamsBuilder.html +296 -0
- data/docs/Tasker/PageSort.html +247 -0
- data/docs/Tasker/PermanentError.html +518 -0
- data/docs/Tasker/ProceduralError.html +147 -0
- data/docs/Tasker/Queries/AllAnnotationTypes.html +217 -0
- data/docs/Tasker/Queries/AllTasks.html +221 -0
- data/docs/Tasker/Queries/BaseQuery.html +128 -0
- data/docs/Tasker/Queries/Helpers.html +187 -0
- data/docs/Tasker/Queries/OneStep.html +225 -0
- data/docs/Tasker/Queries/OneTask.html +217 -0
- data/docs/Tasker/Queries/TasksByAnnotation.html +231 -0
- data/docs/Tasker/Queries/TasksByStatus.html +233 -0
- data/docs/Tasker/Queries.html +119 -0
- data/docs/Tasker/Railtie.html +124 -0
- data/docs/Tasker/Registry/BaseRegistry.html +1690 -0
- data/docs/Tasker/Registry/EventPublisher.html +667 -0
- data/docs/Tasker/Registry/InterfaceValidator.html +569 -0
- data/docs/Tasker/Registry/RegistrationError.html +132 -0
- data/docs/Tasker/Registry/RegistryError.html +139 -0
- data/docs/Tasker/Registry/StatisticsCollector.html +841 -0
- data/docs/Tasker/Registry/SubscriberRegistry.html +1504 -0
- data/docs/Tasker/Registry/ValidationError.html +132 -0
- data/docs/Tasker/Registry.html +119 -0
- data/docs/Tasker/RetryableError.html +515 -0
- data/docs/Tasker/StateMachine/Compatibility.html +282 -0
- data/docs/Tasker/StateMachine/InvalidStateTransition.html +135 -0
- data/docs/Tasker/StateMachine/StepStateMachine/StandardizedPayloadBuilder.html +260 -0
- data/docs/Tasker/StateMachine/StepStateMachine.html +2215 -0
- data/docs/Tasker/StateMachine/TaskStateMachine.html +734 -0
- data/docs/Tasker/StateMachine.html +602 -0
- data/docs/Tasker/StepDagRelationship.html +657 -0
- data/docs/Tasker/StepHandler/Api/Config.html +1091 -0
- data/docs/Tasker/StepHandler/Api.html +884 -0
- data/docs/Tasker/StepHandler/AutomaticEventPublishing.html +321 -0
- data/docs/Tasker/StepHandler/Base.html +970 -0
- data/docs/Tasker/StepHandler.html +119 -0
- data/docs/Tasker/StepReadinessStatus.html +836 -0
- data/docs/Tasker/Task.html +2575 -0
- data/docs/Tasker/TaskAnnotation.html +137 -0
- data/docs/Tasker/TaskAnnotationSerializer.html +124 -0
- data/docs/Tasker/TaskBuilder/StepNameValidator.html +264 -0
- data/docs/Tasker/TaskBuilder/StepTemplateDefiner.html +264 -0
- data/docs/Tasker/TaskBuilder.html +764 -0
- data/docs/Tasker/TaskDiagram/StepToStepEdgeBuilder.html +260 -0
- data/docs/Tasker/TaskDiagram/TaskToRootStepEdgeBuilder.html +290 -0
- data/docs/Tasker/TaskDiagram.html +548 -0
- data/docs/Tasker/TaskDiagramsController.html +240 -0
- data/docs/Tasker/TaskExecutionContext.html +469 -0
- data/docs/Tasker/TaskHandler/ClassMethods/StepTemplateDefiner/ClassBasedEventRegistrar.html +238 -0
- data/docs/Tasker/TaskHandler/ClassMethods/StepTemplateDefiner/YamlEventRegistrar.html +254 -0
- data/docs/Tasker/TaskHandler/ClassMethods/StepTemplateDefiner.html +988 -0
- data/docs/Tasker/TaskHandler/ClassMethods.html +357 -0
- data/docs/Tasker/TaskHandler/InstanceMethods.html +1396 -0
- data/docs/Tasker/TaskHandler/StepGroup.html +1748 -0
- data/docs/Tasker/TaskHandler.html +271 -0
- data/docs/Tasker/TaskNamespace.html +312 -0
- data/docs/Tasker/TaskRunnerJob.html +406 -0
- data/docs/Tasker/TaskSerializer.html +474 -0
- data/docs/Tasker/TaskTransition.html +1517 -0
- data/docs/Tasker/TaskWorkflowSummary.html +988 -0
- data/docs/Tasker/TaskerRailsSchema/InvalidObjectTypeError.html +132 -0
- data/docs/Tasker/TaskerRailsSchema/TypeResolutionError.html +139 -0
- data/docs/Tasker/TaskerRailsSchema/UnknownInterfaceError.html +132 -0
- data/docs/Tasker/TaskerRailsSchema.html +384 -0
- data/docs/Tasker/TasksController.html +595 -0
- data/docs/Tasker/Telemetry/EventMapping.html +1307 -0
- data/docs/Tasker/Telemetry/EventRouter.html +2178 -0
- data/docs/Tasker/Telemetry/Events/ExportEvents.html +246 -0
- data/docs/Tasker/Telemetry/Events.html +115 -0
- data/docs/Tasker/Telemetry/ExportCoordinator/DistributedLockTimeoutError.html +135 -0
- data/docs/Tasker/Telemetry/ExportCoordinator.html +2137 -0
- data/docs/Tasker/Telemetry/IntelligentCacheManager.html +1083 -0
- data/docs/Tasker/Telemetry/LogBackend.html +1088 -0
- data/docs/Tasker/Telemetry/MetricTypes/Counter.html +1054 -0
- data/docs/Tasker/Telemetry/MetricTypes/Gauge.html +1270 -0
- data/docs/Tasker/Telemetry/MetricTypes/Histogram.html +1492 -0
- data/docs/Tasker/Telemetry/MetricTypes.html +153 -0
- data/docs/Tasker/Telemetry/MetricsBackend.html +2510 -0
- data/docs/Tasker/Telemetry/MetricsExportService.html +578 -0
- data/docs/Tasker/Telemetry/PluginRegistry.html +1774 -0
- data/docs/Tasker/Telemetry/Plugins/BaseExporter.html +1835 -0
- data/docs/Tasker/Telemetry/Plugins/CsvExporter.html +768 -0
- data/docs/Tasker/Telemetry/Plugins/JsonExporter.html +747 -0
- data/docs/Tasker/Telemetry/Plugins.html +117 -0
- data/docs/Tasker/Telemetry/PrometheusExporter.html +481 -0
- data/docs/Tasker/Telemetry/TraceBackend.html +891 -0
- data/docs/Tasker/Telemetry.html +130 -0
- data/docs/Tasker/Types/AuthConfig.html +886 -0
- data/docs/Tasker/Types/BackoffConfig.html +1063 -0
- data/docs/Tasker/Types/BaseConfig.html +227 -0
- data/docs/Tasker/Types/CacheConfig.html +1731 -0
- data/docs/Tasker/Types/DatabaseConfig.html +388 -0
- data/docs/Tasker/Types/DependencyGraph.html +526 -0
- data/docs/Tasker/Types/DependencyGraphConfig.html +753 -0
- data/docs/Tasker/Types/EngineConfig.html +1181 -0
- data/docs/Tasker/Types/ExecutionConfig.html +1963 -0
- data/docs/Tasker/Types/GraphEdge.html +517 -0
- data/docs/Tasker/Types/GraphMetadata.html +781 -0
- data/docs/Tasker/Types/GraphNode.html +694 -0
- data/docs/Tasker/Types/HealthConfig.html +784 -0
- data/docs/Tasker/Types/StepSequence.html +353 -0
- data/docs/Tasker/Types/StepTemplate.html +1193 -0
- data/docs/Tasker/Types/TaskRequest.html +1179 -0
- data/docs/Tasker/Types/TelemetryConfig.html +2746 -0
- data/docs/Tasker/Types.html +154 -0
- data/docs/Tasker/WorkflowStep/StepFinder.html +282 -0
- data/docs/Tasker/WorkflowStep.html +2724 -0
- data/docs/Tasker/WorkflowStepEdge.html +304 -0
- data/docs/Tasker/WorkflowStepSerializer.html +305 -0
- data/docs/Tasker/WorkflowStepTransition/TransitionDescriptionFormatter.html +282 -0
- data/docs/Tasker/WorkflowStepTransition.html +2201 -0
- data/docs/Tasker/WorkflowStepsController.html +462 -0
- data/docs/Tasker.html +452 -0
- data/docs/VISION.md +584 -0
- data/docs/WHY.md +21 -0
- data/docs/_index.html +2375 -0
- data/docs/class_list.html +54 -0
- data/docs/css/common.css +1 -0
- data/docs/css/full_list.css +58 -0
- data/docs/css/style.css +503 -0
- data/docs/events/migration_plan_outcomes.md +80 -0
- data/docs/file.README.html +541 -0
- data/docs/file_list.html +59 -0
- data/docs/frames.html +22 -0
- data/docs/index.html +541 -0
- data/docs/js/app.js +344 -0
- data/docs/js/full_list.js +242 -0
- data/docs/js/jquery.js +4 -0
- data/docs/method_list.html +9182 -0
- data/docs/top-level-namespace.html +110 -0
- data/lib/generators/tasker/authenticator_generator.rb +301 -0
- data/lib/generators/tasker/authorization_coordinator_generator.rb +139 -0
- data/lib/generators/tasker/events_generator.rb +91 -0
- data/lib/generators/tasker/subscriber_generator.rb +107 -0
- data/lib/generators/tasker/task_handler_generator.rb +138 -0
- data/lib/generators/tasker/templates/api_token_authenticator.rb.erb +113 -0
- data/lib/generators/tasker/templates/api_token_authenticator_spec.rb.erb +144 -0
- data/lib/generators/tasker/templates/authorization_coordinator.rb.erb +95 -0
- data/lib/generators/tasker/templates/authorization_coordinator_spec.rb.erb +142 -0
- data/lib/generators/tasker/templates/custom_authenticator.rb.erb +108 -0
- data/lib/generators/tasker/templates/custom_authenticator_spec.rb.erb +162 -0
- data/lib/generators/tasker/templates/custom_events.yml.erb +62 -0
- data/lib/generators/tasker/templates/custom_subscriber.rb.erb +72 -0
- data/lib/generators/tasker/templates/devise_authenticator.rb.erb +101 -0
- data/lib/generators/tasker/templates/devise_authenticator_spec.rb.erb +126 -0
- data/lib/generators/tasker/templates/initialize.rb.erb +202 -0
- data/lib/generators/tasker/templates/jwt_authenticator.rb.erb +144 -0
- data/lib/generators/tasker/templates/jwt_authenticator_spec.rb.erb +298 -0
- data/lib/generators/tasker/templates/metrics_subscriber.rb.erb +258 -0
- data/lib/generators/tasker/templates/metrics_subscriber_spec.rb.erb +308 -0
- data/lib/generators/tasker/templates/omniauth_authenticator.rb.erb +135 -0
- data/lib/generators/tasker/templates/omniauth_authenticator_spec.rb.erb +196 -0
- data/lib/generators/tasker/templates/opentelemetry_initializer.rb +52 -0
- data/lib/generators/tasker/templates/subscriber.rb.erb +64 -0
- data/lib/generators/tasker/templates/subscriber_spec.rb.erb +80 -0
- data/lib/generators/tasker/templates/task_config.yaml.erb +117 -0
- data/lib/generators/tasker/templates/task_handler.rb.erb +59 -0
- data/lib/generators/tasker/templates/task_handler_spec.rb.erb +159 -0
- data/lib/tasker/analysis/runtime_graph_analyzer.rb +1168 -0
- data/lib/tasker/analysis/template_graph_analyzer.rb +328 -0
- data/lib/tasker/authentication/coordinator.rb +78 -0
- data/lib/tasker/authentication/errors.rb +9 -0
- data/lib/tasker/authentication/interface.rb +36 -0
- data/lib/tasker/authentication/none_authenticator.rb +26 -0
- data/lib/tasker/authorization/base_coordinator.rb +112 -0
- data/lib/tasker/authorization/errors.rb +26 -0
- data/lib/tasker/authorization/resource_constants.rb +74 -0
- data/lib/tasker/authorization/resource_registry.rb +143 -0
- data/lib/tasker/authorization.rb +75 -0
- data/lib/tasker/cache_capabilities.rb +131 -0
- data/lib/tasker/cache_strategy.rb +469 -0
- data/lib/tasker/concerns/authenticatable.rb +41 -0
- data/lib/tasker/concerns/authorizable.rb +204 -0
- data/lib/tasker/concerns/controller_authorizable.rb +124 -0
- data/lib/tasker/concerns/event_publisher.rb +716 -0
- data/lib/tasker/concerns/idempotent_state_transitions.rb +128 -0
- data/lib/tasker/concerns/state_machine_base.rb +218 -0
- data/lib/tasker/concerns/structured_logging.rb +387 -0
- data/lib/tasker/configuration.rb +325 -0
- data/lib/tasker/constants/event_definitions.rb +147 -0
- data/lib/tasker/constants/registry_events.rb +54 -0
- data/lib/tasker/constants.rb +417 -0
- data/lib/tasker/engine.rb +90 -0
- data/lib/tasker/errors.rb +90 -0
- data/lib/tasker/events/catalog.rb +432 -0
- data/lib/tasker/events/custom_registry.rb +175 -0
- data/lib/tasker/events/definition_loader.rb +199 -0
- data/lib/tasker/events/event_payload_builder.rb +461 -0
- data/lib/tasker/events/publisher.rb +149 -0
- data/lib/tasker/events/subscribers/base_subscriber.rb +601 -0
- data/lib/tasker/events/subscribers/metrics_subscriber.rb +120 -0
- data/lib/tasker/events/subscribers/telemetry_subscriber.rb +462 -0
- data/lib/tasker/events/subscription_loader.rb +161 -0
- data/lib/tasker/events.rb +37 -0
- data/lib/tasker/functions/function_based_analytics_metrics.rb +103 -0
- data/lib/tasker/functions/function_based_dependency_levels.rb +54 -0
- data/lib/tasker/functions/function_based_slowest_steps.rb +84 -0
- data/lib/tasker/functions/function_based_slowest_tasks.rb +84 -0
- data/lib/tasker/functions/function_based_step_readiness_status.rb +183 -0
- data/lib/tasker/functions/function_based_system_health_counts.rb +94 -0
- data/lib/tasker/functions/function_based_task_execution_context.rb +148 -0
- data/lib/tasker/functions/function_wrapper.rb +42 -0
- data/lib/tasker/functions.rb +12 -0
- data/lib/tasker/handler_factory.rb +322 -0
- data/lib/tasker/health/readiness_checker.rb +186 -0
- data/lib/tasker/health/status_checker.rb +203 -0
- data/lib/tasker/identity_strategy.rb +38 -0
- data/lib/tasker/logging/correlation_id_generator.rb +120 -0
- data/lib/tasker/orchestration/backoff_calculator.rb +184 -0
- data/lib/tasker/orchestration/connection_builder.rb +122 -0
- data/lib/tasker/orchestration/connection_pool_intelligence.rb +177 -0
- data/lib/tasker/orchestration/coordinator.rb +119 -0
- data/lib/tasker/orchestration/future_state_analyzer.rb +137 -0
- data/lib/tasker/orchestration/plugin_integration.rb +124 -0
- data/lib/tasker/orchestration/response_processor.rb +168 -0
- data/lib/tasker/orchestration/retry_header_parser.rb +78 -0
- data/lib/tasker/orchestration/step_executor.rb +941 -0
- data/lib/tasker/orchestration/step_sequence_factory.rb +67 -0
- data/lib/tasker/orchestration/task_finalizer.rb +564 -0
- data/lib/tasker/orchestration/task_initializer.rb +140 -0
- data/lib/tasker/orchestration/task_reenqueuer.rb +71 -0
- data/lib/tasker/orchestration/viable_step_discovery.rb +65 -0
- data/lib/tasker/orchestration/workflow_coordinator.rb +294 -0
- data/lib/tasker/orchestration.rb +45 -0
- data/lib/tasker/railtie.rb +9 -0
- data/lib/tasker/registry/base_registry.rb +177 -0
- data/lib/tasker/registry/event_publisher.rb +91 -0
- data/lib/tasker/registry/interface_validator.rb +140 -0
- data/lib/tasker/registry/statistics_collector.rb +381 -0
- data/lib/tasker/registry/subscriber_registry.rb +285 -0
- data/lib/tasker/registry.rb +22 -0
- data/lib/tasker/state_machine/step_state_machine.rb +508 -0
- data/lib/tasker/state_machine/task_state_machine.rb +192 -0
- data/lib/tasker/state_machine.rb +83 -0
- data/lib/tasker/step_handler/api.rb +410 -0
- data/lib/tasker/step_handler/base.rb +206 -0
- data/lib/tasker/task_builder.rb +432 -0
- data/lib/tasker/task_handler/class_methods.rb +324 -0
- data/lib/tasker/task_handler/instance_methods.rb +293 -0
- data/lib/tasker/task_handler/step_group.rb +182 -0
- data/lib/tasker/task_handler.rb +43 -0
- data/lib/tasker/telemetry/event_mapping.rb +126 -0
- data/lib/tasker/telemetry/event_router.rb +318 -0
- data/lib/tasker/telemetry/events/export_events.rb +38 -0
- data/lib/tasker/telemetry/export_coordinator.rb +497 -0
- data/lib/tasker/telemetry/intelligent_cache_manager.rb +508 -0
- data/lib/tasker/telemetry/log_backend.rb +224 -0
- data/lib/tasker/telemetry/metric_types.rb +368 -0
- data/lib/tasker/telemetry/metrics_backend.rb +1227 -0
- data/lib/tasker/telemetry/metrics_export_service.rb +392 -0
- data/lib/tasker/telemetry/plugin_registry.rb +333 -0
- data/lib/tasker/telemetry/plugins/base_exporter.rb +246 -0
- data/lib/tasker/telemetry/plugins/csv_exporter.rb +198 -0
- data/lib/tasker/telemetry/plugins/json_exporter.rb +141 -0
- data/lib/tasker/telemetry/prometheus_exporter.rb +249 -0
- data/lib/tasker/telemetry/trace_backend.rb +186 -0
- data/lib/tasker/telemetry.rb +59 -0
- data/lib/tasker/types/auth_config.rb +81 -0
- data/lib/tasker/types/backoff_config.rb +142 -0
- data/lib/tasker/types/cache_config.rb +257 -0
- data/lib/tasker/types/database_config.rb +39 -0
- data/lib/tasker/types/dependency_graph.rb +225 -0
- data/lib/tasker/types/dependency_graph_config.rb +149 -0
- data/lib/tasker/types/engine_config.rb +131 -0
- data/lib/tasker/types/execution_config.rb +289 -0
- data/lib/tasker/types/health_config.rb +84 -0
- data/lib/tasker/types/step_sequence.rb +24 -0
- data/lib/tasker/types/step_template.rb +63 -0
- data/lib/tasker/types/task_request.rb +60 -0
- data/lib/tasker/types/telemetry_config.rb +273 -0
- data/lib/tasker/types.rb +64 -0
- data/lib/tasker/version.rb +7 -0
- data/lib/tasker.rb +82 -0
- data/lib/tasks/tasker_tasks.rake +302 -0
- 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
|