tasker-engine 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +22 -0
- data/README.md +440 -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/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/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 +414 -0
- data/app/models/tasker/task_annotation.rb +36 -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 +95 -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/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_single_and_batch_v02.sql +223 -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 +2254 -0
- data/db/migrate/20250701165431_initial_tasker_schema.rb +116 -0
- data/db/migrate/20250710110830_step_readiness_sql_functions_v02.rb +39 -0
- data/db/views/tasker_step_dag_relationships_v01.sql +69 -0
- data/docs/APPLICATION_GENERATOR.md +384 -0
- data/docs/AUTH.md +1741 -0
- data/docs/CIRCUIT_BREAKER.md +224 -0
- data/docs/DEVELOPER_GUIDE.md +2664 -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 +548 -0
- data/docs/QUICK_START.md +270 -0
- data/docs/REGISTRY_SYSTEMS.md +373 -0
- data/docs/REST_API.md +632 -0
- data/docs/REVERSIONING.md +404 -0
- data/docs/ROADMAP.md +221 -0
- data/docs/SQL_FUNCTIONS.md +1408 -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 +360 -0
- data/docs/Tasker/Authorization/ResourceConstants.html +146 -0
- data/docs/Tasker/Authorization/ResourceRegistry.html +875 -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 +1528 -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 +2478 -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 +395 -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 +306 -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 +468 -0
- data/docs/VISION.md +584 -0
- data/docs/WHY.md +21 -0
- data/docs/_index.html +2319 -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 +537 -0
- data/docs/file_list.html +59 -0
- data/docs/frames.html +22 -0
- data/docs/index.html +537 -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 +8854 -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 +82 -0
- data/lib/generators/tasker/templates/authorization_coordinator_spec.rb.erb +136 -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 +60 -0
- data/lib/generators/tasker/templates/task_handler_spec.rb.erb +165 -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 +73 -0
- data/lib/tasker/authorization/resource_registry.rb +136 -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 +327 -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 +327 -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 +416 -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 +8 -0
- data/lib/tasker.rb +82 -0
- data/lib/tasks/tasker_tasks.rake +383 -0
- metadata +954 -0
@@ -0,0 +1,96 @@
|
|
1
|
+
-- Slowest Tasks Analysis Function
|
2
|
+
-- Returns the slowest tasks within a specified time period with performance metrics
|
3
|
+
-- Input: since_timestamp, limit_count, and optional namespace/name/version filters
|
4
|
+
-- Output: Ranked list of slowest tasks with duration and context
|
5
|
+
|
6
|
+
CREATE OR REPLACE FUNCTION get_slowest_tasks_v01(
|
7
|
+
since_timestamp TIMESTAMPTZ DEFAULT NULL,
|
8
|
+
limit_count INTEGER DEFAULT 10,
|
9
|
+
namespace_filter TEXT DEFAULT NULL,
|
10
|
+
task_name_filter TEXT DEFAULT NULL,
|
11
|
+
version_filter TEXT DEFAULT NULL
|
12
|
+
)
|
13
|
+
RETURNS TABLE (
|
14
|
+
task_id BIGINT,
|
15
|
+
task_name VARCHAR(64),
|
16
|
+
namespace_name VARCHAR(64),
|
17
|
+
version VARCHAR(64),
|
18
|
+
duration_seconds NUMERIC(10,3),
|
19
|
+
step_count BIGINT,
|
20
|
+
completed_steps BIGINT,
|
21
|
+
error_steps BIGINT,
|
22
|
+
created_at TIMESTAMPTZ,
|
23
|
+
completed_at TIMESTAMPTZ,
|
24
|
+
initiator VARCHAR(128),
|
25
|
+
source_system VARCHAR(128)
|
26
|
+
) LANGUAGE plpgsql STABLE AS $$
|
27
|
+
DECLARE
|
28
|
+
analysis_start TIMESTAMPTZ;
|
29
|
+
BEGIN
|
30
|
+
-- Set analysis start time (default to 24 hours ago if not provided)
|
31
|
+
analysis_start := COALESCE(since_timestamp, NOW() - INTERVAL '24 hours');
|
32
|
+
|
33
|
+
RETURN QUERY
|
34
|
+
WITH task_durations AS (
|
35
|
+
SELECT
|
36
|
+
t.task_id,
|
37
|
+
nt.name as task_name,
|
38
|
+
tn.name as namespace_name,
|
39
|
+
nt.version,
|
40
|
+
t.created_at,
|
41
|
+
t.initiator,
|
42
|
+
t.source_system,
|
43
|
+
-- Find the latest completion time across all steps
|
44
|
+
MAX(wst.created_at) FILTER (
|
45
|
+
WHERE wst.to_state IN ('complete', 'error') AND wst.most_recent = true
|
46
|
+
) as latest_completion,
|
47
|
+
-- Calculate duration from task creation to latest step completion
|
48
|
+
EXTRACT(EPOCH FROM (
|
49
|
+
MAX(wst.created_at) FILTER (
|
50
|
+
WHERE wst.to_state IN ('complete', 'error') AND wst.most_recent = true
|
51
|
+
) - t.created_at
|
52
|
+
)) as duration_seconds,
|
53
|
+
COUNT(ws.workflow_step_id) as total_steps,
|
54
|
+
COUNT(ws.workflow_step_id) FILTER (
|
55
|
+
WHERE complete_wst.to_state = 'complete' AND complete_wst.most_recent = true
|
56
|
+
) as completed_step_count,
|
57
|
+
COUNT(ws.workflow_step_id) FILTER (
|
58
|
+
WHERE error_wst.to_state = 'error' AND error_wst.most_recent = true
|
59
|
+
) as error_step_count
|
60
|
+
FROM tasker_tasks t
|
61
|
+
INNER JOIN tasker_named_tasks nt ON nt.named_task_id = t.named_task_id
|
62
|
+
INNER JOIN tasker_task_namespaces tn ON tn.task_namespace_id = nt.task_namespace_id
|
63
|
+
INNER JOIN tasker_workflow_steps ws ON ws.task_id = t.task_id
|
64
|
+
LEFT JOIN tasker_workflow_step_transitions wst ON wst.workflow_step_id = ws.workflow_step_id
|
65
|
+
LEFT JOIN tasker_workflow_step_transitions complete_wst ON complete_wst.workflow_step_id = ws.workflow_step_id
|
66
|
+
AND complete_wst.to_state = 'complete' AND complete_wst.most_recent = true
|
67
|
+
LEFT JOIN tasker_workflow_step_transitions error_wst ON error_wst.workflow_step_id = ws.workflow_step_id
|
68
|
+
AND error_wst.to_state = 'error' AND error_wst.most_recent = true
|
69
|
+
WHERE t.created_at > analysis_start
|
70
|
+
AND (namespace_filter IS NULL OR tn.name = namespace_filter)
|
71
|
+
AND (task_name_filter IS NULL OR nt.name = task_name_filter)
|
72
|
+
AND (version_filter IS NULL OR nt.version = version_filter)
|
73
|
+
GROUP BY t.task_id, nt.name, tn.name, nt.version, t.created_at, t.initiator, t.source_system
|
74
|
+
HAVING MAX(wst.created_at) FILTER (
|
75
|
+
WHERE wst.to_state IN ('complete', 'error') AND wst.most_recent = true
|
76
|
+
) IS NOT NULL -- Only include tasks that have at least one completed/failed step
|
77
|
+
)
|
78
|
+
SELECT
|
79
|
+
td.task_id,
|
80
|
+
td.task_name,
|
81
|
+
td.namespace_name,
|
82
|
+
td.version,
|
83
|
+
ROUND(td.duration_seconds, 3),
|
84
|
+
td.total_steps,
|
85
|
+
td.completed_step_count,
|
86
|
+
td.error_step_count,
|
87
|
+
td.created_at,
|
88
|
+
td.latest_completion,
|
89
|
+
td.initiator,
|
90
|
+
td.source_system
|
91
|
+
FROM task_durations td
|
92
|
+
WHERE td.duration_seconds IS NOT NULL
|
93
|
+
ORDER BY td.duration_seconds DESC
|
94
|
+
LIMIT limit_count;
|
95
|
+
END;
|
96
|
+
$$;
|
@@ -0,0 +1,140 @@
|
|
1
|
+
-- Batch Step Readiness Status Function
|
2
|
+
-- Gets step readiness data for multiple tasks in a single query
|
3
|
+
-- Input: Array of task_ids (gets all steps for each task)
|
4
|
+
-- Output: Multiple rows with step readiness data, properly grouped by task
|
5
|
+
|
6
|
+
CREATE OR REPLACE FUNCTION get_step_readiness_status_batch(input_task_ids BIGINT[])
|
7
|
+
RETURNS TABLE(
|
8
|
+
workflow_step_id BIGINT,
|
9
|
+
task_id BIGINT,
|
10
|
+
named_step_id INTEGER,
|
11
|
+
name TEXT,
|
12
|
+
current_state TEXT,
|
13
|
+
dependencies_satisfied BOOLEAN,
|
14
|
+
retry_eligible BOOLEAN,
|
15
|
+
ready_for_execution BOOLEAN,
|
16
|
+
last_failure_at TIMESTAMP,
|
17
|
+
next_retry_at TIMESTAMP,
|
18
|
+
total_parents INTEGER,
|
19
|
+
completed_parents INTEGER,
|
20
|
+
attempts INTEGER,
|
21
|
+
retry_limit INTEGER,
|
22
|
+
backoff_request_seconds INTEGER,
|
23
|
+
last_attempted_at TIMESTAMP
|
24
|
+
) LANGUAGE plpgsql STABLE AS $$
|
25
|
+
BEGIN
|
26
|
+
RETURN QUERY
|
27
|
+
SELECT
|
28
|
+
ws.workflow_step_id,
|
29
|
+
ws.task_id,
|
30
|
+
ws.named_step_id,
|
31
|
+
ns.name::TEXT,
|
32
|
+
|
33
|
+
-- Current State Information (optimized using most_recent flag)
|
34
|
+
COALESCE(current_state.to_state, 'pending')::TEXT as current_state,
|
35
|
+
|
36
|
+
-- Dependency Analysis (calculated from direct joins)
|
37
|
+
CASE
|
38
|
+
WHEN dep_edges.to_step_id IS NULL THEN true -- Root steps (no parents)
|
39
|
+
WHEN COUNT(dep_edges.from_step_id) = 0 THEN true -- Steps with zero dependencies
|
40
|
+
WHEN COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END) = COUNT(dep_edges.from_step_id) THEN true
|
41
|
+
ELSE false
|
42
|
+
END as dependencies_satisfied,
|
43
|
+
|
44
|
+
-- Simplified Retry & Backoff Analysis
|
45
|
+
CASE
|
46
|
+
WHEN ws.attempts >= COALESCE(ws.retry_limit, 3) THEN false
|
47
|
+
WHEN ws.attempts > 0 AND COALESCE(ws.retryable, true) = false THEN false
|
48
|
+
WHEN last_failure.created_at IS NULL THEN true
|
49
|
+
WHEN ws.backoff_request_seconds IS NOT NULL AND ws.last_attempted_at IS NOT NULL THEN
|
50
|
+
ws.last_attempted_at + (ws.backoff_request_seconds * interval '1 second') <= NOW()
|
51
|
+
WHEN last_failure.created_at IS NOT NULL THEN
|
52
|
+
last_failure.created_at + (
|
53
|
+
LEAST(power(2, COALESCE(ws.attempts, 1)) * interval '1 second', interval '30 seconds')
|
54
|
+
) <= NOW()
|
55
|
+
ELSE true
|
56
|
+
END as retry_eligible,
|
57
|
+
|
58
|
+
-- Simplified Final Readiness Calculation
|
59
|
+
CASE
|
60
|
+
WHEN COALESCE(current_state.to_state, 'pending') IN ('pending', 'error')
|
61
|
+
AND (ws.processed = false OR ws.processed IS NULL) -- CRITICAL: Only unprocessed steps can be ready
|
62
|
+
AND (dep_edges.to_step_id IS NULL OR
|
63
|
+
COUNT(dep_edges.from_step_id) = 0 OR
|
64
|
+
COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END) = COUNT(dep_edges.from_step_id))
|
65
|
+
AND (ws.attempts < COALESCE(ws.retry_limit, 3))
|
66
|
+
AND (COALESCE(ws.retryable, true) = true)
|
67
|
+
AND (ws.in_process = false OR ws.in_process IS NULL)
|
68
|
+
AND (
|
69
|
+
-- Check explicit backoff timing (most restrictive)
|
70
|
+
-- If backoff is set, the backoff period must have expired
|
71
|
+
CASE
|
72
|
+
WHEN ws.backoff_request_seconds IS NOT NULL AND ws.last_attempted_at IS NOT NULL THEN
|
73
|
+
ws.last_attempted_at + (ws.backoff_request_seconds * interval '1 second') <= NOW()
|
74
|
+
ELSE true -- No explicit backoff set
|
75
|
+
END
|
76
|
+
AND
|
77
|
+
-- Then check failure-based backoff
|
78
|
+
(last_failure.created_at IS NULL OR
|
79
|
+
last_failure.created_at + (LEAST(power(2, COALESCE(ws.attempts, 1)) * interval '1 second', interval '30 seconds')) <= NOW())
|
80
|
+
)
|
81
|
+
THEN true
|
82
|
+
ELSE false
|
83
|
+
END as ready_for_execution,
|
84
|
+
|
85
|
+
-- Timing Information
|
86
|
+
last_failure.created_at as last_failure_at,
|
87
|
+
CASE
|
88
|
+
WHEN ws.backoff_request_seconds IS NOT NULL AND ws.last_attempted_at IS NOT NULL THEN
|
89
|
+
ws.last_attempted_at + (ws.backoff_request_seconds * interval '1 second')
|
90
|
+
WHEN last_failure.created_at IS NOT NULL THEN
|
91
|
+
last_failure.created_at + (LEAST(power(2, COALESCE(ws.attempts, 1)) * interval '1 second', interval '30 seconds'))
|
92
|
+
ELSE NULL
|
93
|
+
END as next_retry_at,
|
94
|
+
|
95
|
+
-- Dependency Context (calculated from joins)
|
96
|
+
COALESCE(COUNT(dep_edges.from_step_id), 0)::INTEGER as total_parents,
|
97
|
+
COALESCE(COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END), 0)::INTEGER as completed_parents,
|
98
|
+
|
99
|
+
-- Retry Context
|
100
|
+
ws.attempts,
|
101
|
+
COALESCE(ws.retry_limit, 3) as retry_limit,
|
102
|
+
ws.backoff_request_seconds,
|
103
|
+
ws.last_attempted_at
|
104
|
+
|
105
|
+
FROM tasker_workflow_steps ws
|
106
|
+
JOIN tasker_named_steps ns ON ns.named_step_id = ws.named_step_id
|
107
|
+
|
108
|
+
-- OPTIMIZED: Current State using most_recent flag instead of DISTINCT ON
|
109
|
+
LEFT JOIN tasker_workflow_step_transitions current_state
|
110
|
+
ON current_state.workflow_step_id = ws.workflow_step_id
|
111
|
+
AND current_state.most_recent = true
|
112
|
+
|
113
|
+
-- OPTIMIZED: Dependency check using direct joins (no subquery)
|
114
|
+
LEFT JOIN tasker_workflow_step_edges dep_edges
|
115
|
+
ON dep_edges.to_step_id = ws.workflow_step_id
|
116
|
+
LEFT JOIN tasker_workflow_step_transitions parent_states
|
117
|
+
ON parent_states.workflow_step_id = dep_edges.from_step_id
|
118
|
+
AND parent_states.most_recent = true
|
119
|
+
|
120
|
+
-- OPTIMIZED: Last failure using index-optimized approach
|
121
|
+
LEFT JOIN tasker_workflow_step_transitions last_failure
|
122
|
+
ON last_failure.workflow_step_id = ws.workflow_step_id
|
123
|
+
AND last_failure.to_state = 'error'
|
124
|
+
AND last_failure.most_recent = true
|
125
|
+
|
126
|
+
-- KEY PERFORMANCE IMPROVEMENT: Filter by multiple tasks at once
|
127
|
+
-- CRITICAL FIX: Include ALL steps for task execution context calculation
|
128
|
+
-- Only filter by processed status when specifically querying for ready steps
|
129
|
+
WHERE ws.task_id = ANY(input_task_ids)
|
130
|
+
|
131
|
+
GROUP BY
|
132
|
+
ws.workflow_step_id, ws.task_id, ws.named_step_id, ns.name,
|
133
|
+
current_state.to_state, last_failure.created_at,
|
134
|
+
ws.attempts, ws.retry_limit, ws.backoff_request_seconds, ws.last_attempted_at,
|
135
|
+
ws.in_process, ws.processed, ws.retryable, dep_edges.to_step_id
|
136
|
+
|
137
|
+
-- IMPORTANT: Order by task_id, then workflow_step_id for consistent grouping
|
138
|
+
ORDER BY ws.task_id, ws.workflow_step_id;
|
139
|
+
END;
|
140
|
+
$$;
|
@@ -0,0 +1,223 @@
|
|
1
|
+
-- Fix step readiness logic for NULL attempts
|
2
|
+
-- When attempts is NULL, it should be treated as 0 for comparison purposes
|
3
|
+
|
4
|
+
-- Update get_step_readiness_status function
|
5
|
+
CREATE OR REPLACE FUNCTION get_step_readiness_status(input_task_id bigint, step_ids bigint[] DEFAULT NULL::bigint[]) RETURNS TABLE(workflow_step_id bigint, task_id bigint, named_step_id integer, name text, current_state text, dependencies_satisfied boolean, retry_eligible boolean, ready_for_execution boolean, last_failure_at timestamp without time zone, next_retry_at timestamp without time zone, total_parents integer, completed_parents integer, attempts integer, retry_limit integer, backoff_request_seconds integer, last_attempted_at timestamp without time zone)
|
6
|
+
LANGUAGE plpgsql STABLE
|
7
|
+
AS $$
|
8
|
+
BEGIN
|
9
|
+
RETURN QUERY
|
10
|
+
SELECT
|
11
|
+
ws.workflow_step_id,
|
12
|
+
ws.task_id,
|
13
|
+
ws.named_step_id,
|
14
|
+
ns.name::TEXT,
|
15
|
+
|
16
|
+
-- Current State Information (optimized using most_recent flag)
|
17
|
+
COALESCE(current_state.to_state, 'pending')::TEXT as current_state,
|
18
|
+
|
19
|
+
-- Dependency Satisfaction Analysis
|
20
|
+
CASE
|
21
|
+
WHEN dep_edges.to_step_id IS NULL OR
|
22
|
+
COUNT(dep_edges.from_step_id) = 0 THEN true
|
23
|
+
ELSE
|
24
|
+
COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END) = COUNT(dep_edges.from_step_id)
|
25
|
+
END as dependencies_satisfied,
|
26
|
+
|
27
|
+
-- Retry Eligibility
|
28
|
+
CASE
|
29
|
+
WHEN COALESCE(ws.attempts, 0) < COALESCE(ws.retry_limit, 3) THEN true
|
30
|
+
ELSE false
|
31
|
+
END as retry_eligible,
|
32
|
+
|
33
|
+
-- Overall Ready for Execution (complex business logic)
|
34
|
+
CASE
|
35
|
+
WHEN COALESCE(current_state.to_state, 'pending') IN ('pending', 'error')
|
36
|
+
AND (ws.processed = false OR ws.processed IS NULL) -- CRITICAL: Only unprocessed steps can be ready
|
37
|
+
AND (dep_edges.to_step_id IS NULL OR
|
38
|
+
COUNT(dep_edges.from_step_id) = 0 OR
|
39
|
+
COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END) = COUNT(dep_edges.from_step_id))
|
40
|
+
AND (COALESCE(ws.attempts, 0) < COALESCE(ws.retry_limit, 3)) -- FIXED: Handle NULL attempts
|
41
|
+
AND (COALESCE(ws.retryable, true) = true)
|
42
|
+
AND (ws.in_process = false OR ws.in_process IS NULL)
|
43
|
+
AND (
|
44
|
+
-- Check explicit backoff timing (most restrictive)
|
45
|
+
-- If backoff is set, the backoff period must have expired
|
46
|
+
CASE
|
47
|
+
WHEN ws.backoff_request_seconds IS NOT NULL AND ws.last_attempted_at IS NOT NULL THEN
|
48
|
+
ws.last_attempted_at + (ws.backoff_request_seconds * interval '1 second') <= NOW()
|
49
|
+
ELSE true -- No explicit backoff set
|
50
|
+
END
|
51
|
+
AND
|
52
|
+
-- Then check failure-based backoff
|
53
|
+
(last_failure.created_at IS NULL OR
|
54
|
+
last_failure.created_at + (LEAST(power(2, COALESCE(ws.attempts, 1)) * interval '1 second', interval '30 seconds')) <= NOW())
|
55
|
+
)
|
56
|
+
THEN true
|
57
|
+
ELSE false
|
58
|
+
END as ready_for_execution,
|
59
|
+
|
60
|
+
-- Timing Information
|
61
|
+
last_failure.created_at as last_failure_at,
|
62
|
+
CASE
|
63
|
+
WHEN ws.backoff_request_seconds IS NOT NULL AND ws.last_attempted_at IS NOT NULL THEN
|
64
|
+
ws.last_attempted_at + (ws.backoff_request_seconds * interval '1 second')
|
65
|
+
WHEN last_failure.created_at IS NOT NULL THEN
|
66
|
+
last_failure.created_at + (LEAST(power(2, COALESCE(ws.attempts, 1)) * interval '1 second', interval '30 seconds'))
|
67
|
+
ELSE NULL
|
68
|
+
END as next_retry_at,
|
69
|
+
|
70
|
+
-- Dependency Context (calculated from joins)
|
71
|
+
COALESCE(COUNT(dep_edges.from_step_id), 0)::INTEGER as total_parents,
|
72
|
+
COALESCE(COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END), 0)::INTEGER as completed_parents,
|
73
|
+
|
74
|
+
-- Retry Context
|
75
|
+
COALESCE(ws.attempts, 0)::INTEGER as attempts, -- FIXED: Return 0 instead of NULL
|
76
|
+
COALESCE(ws.retry_limit, 3) as retry_limit,
|
77
|
+
ws.backoff_request_seconds,
|
78
|
+
ws.last_attempted_at
|
79
|
+
|
80
|
+
FROM tasker_workflow_steps ws
|
81
|
+
JOIN tasker_named_steps ns ON ns.named_step_id = ws.named_step_id
|
82
|
+
|
83
|
+
-- OPTIMIZED: Current State using most_recent flag instead of DISTINCT ON
|
84
|
+
LEFT JOIN tasker_workflow_step_transitions current_state
|
85
|
+
ON current_state.workflow_step_id = ws.workflow_step_id
|
86
|
+
AND current_state.most_recent = true
|
87
|
+
|
88
|
+
-- OPTIMIZED: Dependency check using direct joins (no subquery)
|
89
|
+
LEFT JOIN tasker_workflow_step_edges dep_edges
|
90
|
+
ON dep_edges.to_step_id = ws.workflow_step_id
|
91
|
+
LEFT JOIN tasker_workflow_step_transitions parent_states
|
92
|
+
ON parent_states.workflow_step_id = dep_edges.from_step_id
|
93
|
+
AND parent_states.most_recent = true
|
94
|
+
|
95
|
+
-- OPTIMIZED: Last failure using index-optimized approach
|
96
|
+
LEFT JOIN tasker_workflow_step_transitions last_failure
|
97
|
+
ON last_failure.workflow_step_id = ws.workflow_step_id
|
98
|
+
AND last_failure.to_state = 'error'
|
99
|
+
AND last_failure.most_recent = true
|
100
|
+
|
101
|
+
-- KEY PERFORMANCE IMPROVEMENT: Filter by task first, then optionally by step IDs
|
102
|
+
-- CRITICAL FIX: Include ALL steps for task execution context calculation
|
103
|
+
-- Only filter by processed status when specifically querying for ready steps
|
104
|
+
WHERE ws.task_id = input_task_id
|
105
|
+
AND (step_ids IS NULL OR ws.workflow_step_id = ANY(step_ids))
|
106
|
+
|
107
|
+
GROUP BY
|
108
|
+
ws.workflow_step_id, ws.task_id, ws.named_step_id, ns.name,
|
109
|
+
current_state.to_state, last_failure.created_at,
|
110
|
+
ws.attempts, ws.retry_limit, ws.backoff_request_seconds, ws.last_attempted_at,
|
111
|
+
ws.in_process, ws.processed, ws.retryable, dep_edges.to_step_id,
|
112
|
+
current_state.workflow_step_id, last_failure.workflow_step_id;
|
113
|
+
END;
|
114
|
+
$$;
|
115
|
+
|
116
|
+
-- Also update the batch version
|
117
|
+
CREATE OR REPLACE FUNCTION get_step_readiness_status_batch(input_task_ids bigint[]) RETURNS TABLE(workflow_step_id bigint, task_id bigint, named_step_id integer, name text, current_state text, dependencies_satisfied boolean, retry_eligible boolean, ready_for_execution boolean, last_failure_at timestamp without time zone, next_retry_at timestamp without time zone, total_parents integer, completed_parents integer, attempts integer, retry_limit integer, backoff_request_seconds integer, last_attempted_at timestamp without time zone)
|
118
|
+
LANGUAGE plpgsql STABLE
|
119
|
+
AS $$
|
120
|
+
BEGIN
|
121
|
+
RETURN QUERY
|
122
|
+
SELECT
|
123
|
+
ws.workflow_step_id,
|
124
|
+
ws.task_id,
|
125
|
+
ws.named_step_id,
|
126
|
+
ns.name::TEXT,
|
127
|
+
|
128
|
+
-- Current State Information (optimized using most_recent flag)
|
129
|
+
COALESCE(current_state.to_state, 'pending')::TEXT as current_state,
|
130
|
+
|
131
|
+
-- Dependency Satisfaction Analysis
|
132
|
+
CASE
|
133
|
+
WHEN dep_edges.to_step_id IS NULL OR
|
134
|
+
COUNT(dep_edges.from_step_id) = 0 THEN true
|
135
|
+
ELSE
|
136
|
+
COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END) = COUNT(dep_edges.from_step_id)
|
137
|
+
END as dependencies_satisfied,
|
138
|
+
|
139
|
+
-- Retry Eligibility
|
140
|
+
CASE
|
141
|
+
WHEN COALESCE(ws.attempts, 0) < COALESCE(ws.retry_limit, 3) THEN true
|
142
|
+
ELSE false
|
143
|
+
END as retry_eligible,
|
144
|
+
|
145
|
+
-- Overall Ready for Execution (complex business logic)
|
146
|
+
CASE
|
147
|
+
WHEN COALESCE(current_state.to_state, 'pending') IN ('pending', 'error')
|
148
|
+
AND (ws.processed = false OR ws.processed IS NULL)
|
149
|
+
AND (dep_edges.to_step_id IS NULL OR
|
150
|
+
COUNT(dep_edges.from_step_id) = 0 OR
|
151
|
+
COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END) = COUNT(dep_edges.from_step_id))
|
152
|
+
AND (COALESCE(ws.attempts, 0) < COALESCE(ws.retry_limit, 3)) -- FIXED: Handle NULL attempts
|
153
|
+
AND (COALESCE(ws.retryable, true) = true)
|
154
|
+
AND (ws.in_process = false OR ws.in_process IS NULL)
|
155
|
+
AND (
|
156
|
+
-- Check explicit backoff timing (most restrictive)
|
157
|
+
-- If backoff is set, the backoff period must have expired
|
158
|
+
CASE
|
159
|
+
WHEN ws.backoff_request_seconds IS NOT NULL AND ws.last_attempted_at IS NOT NULL THEN
|
160
|
+
ws.last_attempted_at + (ws.backoff_request_seconds * interval '1 second') <= NOW()
|
161
|
+
ELSE true -- No explicit backoff set
|
162
|
+
END
|
163
|
+
AND
|
164
|
+
-- Then check failure-based backoff
|
165
|
+
(last_failure.created_at IS NULL OR
|
166
|
+
last_failure.created_at + (LEAST(power(2, COALESCE(ws.attempts, 1)) * interval '1 second', interval '30 seconds')) <= NOW())
|
167
|
+
)
|
168
|
+
THEN true
|
169
|
+
ELSE false
|
170
|
+
END as ready_for_execution,
|
171
|
+
|
172
|
+
-- Timing Information
|
173
|
+
last_failure.created_at as last_failure_at,
|
174
|
+
CASE
|
175
|
+
WHEN ws.backoff_request_seconds IS NOT NULL AND ws.last_attempted_at IS NOT NULL THEN
|
176
|
+
ws.last_attempted_at + (ws.backoff_request_seconds * interval '1 second')
|
177
|
+
WHEN last_failure.created_at IS NOT NULL THEN
|
178
|
+
last_failure.created_at + (LEAST(power(2, COALESCE(ws.attempts, 1)) * interval '1 second', interval '30 seconds'))
|
179
|
+
ELSE NULL
|
180
|
+
END as next_retry_at,
|
181
|
+
|
182
|
+
-- Dependency Context (calculated from joins)
|
183
|
+
COALESCE(COUNT(dep_edges.from_step_id), 0)::INTEGER as total_parents,
|
184
|
+
COALESCE(COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END), 0)::INTEGER as completed_parents,
|
185
|
+
|
186
|
+
-- Retry Context
|
187
|
+
COALESCE(ws.attempts, 0)::INTEGER as attempts, -- FIXED: Return 0 instead of NULL
|
188
|
+
COALESCE(ws.retry_limit, 3) as retry_limit,
|
189
|
+
ws.backoff_request_seconds,
|
190
|
+
ws.last_attempted_at
|
191
|
+
|
192
|
+
FROM tasker_workflow_steps ws
|
193
|
+
JOIN tasker_named_steps ns ON ns.named_step_id = ws.named_step_id
|
194
|
+
|
195
|
+
-- OPTIMIZED: Current State using most_recent flag instead of DISTINCT ON
|
196
|
+
LEFT JOIN tasker_workflow_step_transitions current_state
|
197
|
+
ON current_state.workflow_step_id = ws.workflow_step_id
|
198
|
+
AND current_state.most_recent = true
|
199
|
+
|
200
|
+
-- OPTIMIZED: Dependency check using direct joins (no subquery)
|
201
|
+
LEFT JOIN tasker_workflow_step_edges dep_edges
|
202
|
+
ON dep_edges.to_step_id = ws.workflow_step_id
|
203
|
+
LEFT JOIN tasker_workflow_step_transitions parent_states
|
204
|
+
ON parent_states.workflow_step_id = dep_edges.from_step_id
|
205
|
+
AND parent_states.most_recent = true
|
206
|
+
|
207
|
+
-- OPTIMIZED: Last failure using index-optimized approach
|
208
|
+
LEFT JOIN tasker_workflow_step_transitions last_failure
|
209
|
+
ON last_failure.workflow_step_id = ws.workflow_step_id
|
210
|
+
AND last_failure.to_state = 'error'
|
211
|
+
AND last_failure.most_recent = true
|
212
|
+
|
213
|
+
-- KEY PERFORMANCE IMPROVEMENT: Filter by task first, then optionally by step IDs
|
214
|
+
WHERE ws.task_id = ANY(input_task_ids)
|
215
|
+
|
216
|
+
GROUP BY
|
217
|
+
ws.workflow_step_id, ws.task_id, ws.named_step_id, ns.name,
|
218
|
+
current_state.to_state, last_failure.created_at,
|
219
|
+
ws.attempts, ws.retry_limit, ws.backoff_request_seconds, ws.last_attempted_at,
|
220
|
+
ws.in_process, ws.processed, ws.retryable, dep_edges.to_step_id,
|
221
|
+
current_state.workflow_step_id, last_failure.workflow_step_id;
|
222
|
+
END;
|
223
|
+
$$;
|
@@ -0,0 +1,139 @@
|
|
1
|
+
-- Step Readiness Status Function
|
2
|
+
-- Converts the view logic to a parameterized function for targeted queries
|
3
|
+
-- Input: Array of workflow_step_ids
|
4
|
+
-- Output: Readiness data for specified steps only
|
5
|
+
|
6
|
+
CREATE OR REPLACE FUNCTION get_step_readiness_status(input_task_id BIGINT, step_ids BIGINT[] DEFAULT NULL)
|
7
|
+
RETURNS TABLE(
|
8
|
+
workflow_step_id BIGINT,
|
9
|
+
task_id BIGINT,
|
10
|
+
named_step_id INTEGER,
|
11
|
+
name TEXT,
|
12
|
+
current_state TEXT,
|
13
|
+
dependencies_satisfied BOOLEAN,
|
14
|
+
retry_eligible BOOLEAN,
|
15
|
+
ready_for_execution BOOLEAN,
|
16
|
+
last_failure_at TIMESTAMP,
|
17
|
+
next_retry_at TIMESTAMP,
|
18
|
+
total_parents INTEGER,
|
19
|
+
completed_parents INTEGER,
|
20
|
+
attempts INTEGER,
|
21
|
+
retry_limit INTEGER,
|
22
|
+
backoff_request_seconds INTEGER,
|
23
|
+
last_attempted_at TIMESTAMP
|
24
|
+
) LANGUAGE plpgsql STABLE AS $$
|
25
|
+
BEGIN
|
26
|
+
RETURN QUERY
|
27
|
+
SELECT
|
28
|
+
ws.workflow_step_id,
|
29
|
+
ws.task_id,
|
30
|
+
ws.named_step_id,
|
31
|
+
ns.name::TEXT,
|
32
|
+
|
33
|
+
-- Current State Information (optimized using most_recent flag)
|
34
|
+
COALESCE(current_state.to_state, 'pending')::TEXT as current_state,
|
35
|
+
|
36
|
+
-- Dependency Analysis (calculated from direct joins)
|
37
|
+
CASE
|
38
|
+
WHEN dep_edges.to_step_id IS NULL THEN true -- Root steps (no parents)
|
39
|
+
WHEN COUNT(dep_edges.from_step_id) = 0 THEN true -- Steps with zero dependencies
|
40
|
+
WHEN COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END) = COUNT(dep_edges.from_step_id) THEN true
|
41
|
+
ELSE false
|
42
|
+
END as dependencies_satisfied,
|
43
|
+
|
44
|
+
-- Simplified Retry & Backoff Analysis
|
45
|
+
CASE
|
46
|
+
WHEN ws.attempts >= COALESCE(ws.retry_limit, 3) THEN false
|
47
|
+
WHEN ws.attempts > 0 AND COALESCE(ws.retryable, true) = false THEN false
|
48
|
+
WHEN last_failure.created_at IS NULL THEN true
|
49
|
+
WHEN ws.backoff_request_seconds IS NOT NULL AND ws.last_attempted_at IS NOT NULL THEN
|
50
|
+
ws.last_attempted_at + (ws.backoff_request_seconds * interval '1 second') <= NOW()
|
51
|
+
WHEN last_failure.created_at IS NOT NULL THEN
|
52
|
+
last_failure.created_at + (
|
53
|
+
LEAST(power(2, COALESCE(ws.attempts, 1)) * interval '1 second', interval '30 seconds')
|
54
|
+
) <= NOW()
|
55
|
+
ELSE true
|
56
|
+
END as retry_eligible,
|
57
|
+
|
58
|
+
-- Simplified Final Readiness Calculation
|
59
|
+
CASE
|
60
|
+
WHEN COALESCE(current_state.to_state, 'pending') IN ('pending', 'error')
|
61
|
+
AND (ws.processed = false OR ws.processed IS NULL) -- CRITICAL: Only unprocessed steps can be ready
|
62
|
+
AND (dep_edges.to_step_id IS NULL OR
|
63
|
+
COUNT(dep_edges.from_step_id) = 0 OR
|
64
|
+
COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END) = COUNT(dep_edges.from_step_id))
|
65
|
+
AND (ws.attempts < COALESCE(ws.retry_limit, 3))
|
66
|
+
AND (COALESCE(ws.retryable, true) = true)
|
67
|
+
AND (ws.in_process = false OR ws.in_process IS NULL)
|
68
|
+
AND (
|
69
|
+
-- Check explicit backoff timing (most restrictive)
|
70
|
+
-- If backoff is set, the backoff period must have expired
|
71
|
+
CASE
|
72
|
+
WHEN ws.backoff_request_seconds IS NOT NULL AND ws.last_attempted_at IS NOT NULL THEN
|
73
|
+
ws.last_attempted_at + (ws.backoff_request_seconds * interval '1 second') <= NOW()
|
74
|
+
ELSE true -- No explicit backoff set
|
75
|
+
END
|
76
|
+
AND
|
77
|
+
-- Then check failure-based backoff
|
78
|
+
(last_failure.created_at IS NULL OR
|
79
|
+
last_failure.created_at + (LEAST(power(2, COALESCE(ws.attempts, 1)) * interval '1 second', interval '30 seconds')) <= NOW())
|
80
|
+
)
|
81
|
+
THEN true
|
82
|
+
ELSE false
|
83
|
+
END as ready_for_execution,
|
84
|
+
|
85
|
+
-- Timing Information
|
86
|
+
last_failure.created_at as last_failure_at,
|
87
|
+
CASE
|
88
|
+
WHEN ws.backoff_request_seconds IS NOT NULL AND ws.last_attempted_at IS NOT NULL THEN
|
89
|
+
ws.last_attempted_at + (ws.backoff_request_seconds * interval '1 second')
|
90
|
+
WHEN last_failure.created_at IS NOT NULL THEN
|
91
|
+
last_failure.created_at + (LEAST(power(2, COALESCE(ws.attempts, 1)) * interval '1 second', interval '30 seconds'))
|
92
|
+
ELSE NULL
|
93
|
+
END as next_retry_at,
|
94
|
+
|
95
|
+
-- Dependency Context (calculated from joins)
|
96
|
+
COALESCE(COUNT(dep_edges.from_step_id), 0)::INTEGER as total_parents,
|
97
|
+
COALESCE(COUNT(CASE WHEN parent_states.to_state IN ('complete', 'resolved_manually') THEN 1 END), 0)::INTEGER as completed_parents,
|
98
|
+
|
99
|
+
-- Retry Context
|
100
|
+
ws.attempts,
|
101
|
+
COALESCE(ws.retry_limit, 3) as retry_limit,
|
102
|
+
ws.backoff_request_seconds,
|
103
|
+
ws.last_attempted_at
|
104
|
+
|
105
|
+
FROM tasker_workflow_steps ws
|
106
|
+
JOIN tasker_named_steps ns ON ns.named_step_id = ws.named_step_id
|
107
|
+
|
108
|
+
-- OPTIMIZED: Current State using most_recent flag instead of DISTINCT ON
|
109
|
+
LEFT JOIN tasker_workflow_step_transitions current_state
|
110
|
+
ON current_state.workflow_step_id = ws.workflow_step_id
|
111
|
+
AND current_state.most_recent = true
|
112
|
+
|
113
|
+
-- OPTIMIZED: Dependency check using direct joins (no subquery)
|
114
|
+
LEFT JOIN tasker_workflow_step_edges dep_edges
|
115
|
+
ON dep_edges.to_step_id = ws.workflow_step_id
|
116
|
+
LEFT JOIN tasker_workflow_step_transitions parent_states
|
117
|
+
ON parent_states.workflow_step_id = dep_edges.from_step_id
|
118
|
+
AND parent_states.most_recent = true
|
119
|
+
|
120
|
+
-- OPTIMIZED: Last failure using index-optimized approach
|
121
|
+
LEFT JOIN tasker_workflow_step_transitions last_failure
|
122
|
+
ON last_failure.workflow_step_id = ws.workflow_step_id
|
123
|
+
AND last_failure.to_state = 'error'
|
124
|
+
AND last_failure.most_recent = true
|
125
|
+
|
126
|
+
-- KEY PERFORMANCE IMPROVEMENT: Filter by task first, then optionally by step IDs
|
127
|
+
-- CRITICAL FIX: Include ALL steps for task execution context calculation
|
128
|
+
-- Only filter by processed status when specifically querying for ready steps
|
129
|
+
WHERE ws.task_id = input_task_id
|
130
|
+
AND (step_ids IS NULL OR ws.workflow_step_id = ANY(step_ids))
|
131
|
+
|
132
|
+
GROUP BY
|
133
|
+
ws.workflow_step_id, ws.task_id, ws.named_step_id, ns.name,
|
134
|
+
current_state.to_state, last_failure.created_at,
|
135
|
+
ws.attempts, ws.retry_limit, ws.backoff_request_seconds, ws.last_attempted_at,
|
136
|
+
ws.in_process, ws.processed, ws.retryable, dep_edges.to_step_id,
|
137
|
+
current_state.workflow_step_id, last_failure.workflow_step_id;
|
138
|
+
END;
|
139
|
+
$$;
|