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,434 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tasker
|
4
|
+
# WorkflowStepTransition represents state transitions for WorkflowStep entities using Statesman
|
5
|
+
#
|
6
|
+
# This model stores the audit trail of all workflow step state changes, providing
|
7
|
+
# a complete history of step lifecycle events with metadata and timestamps.
|
8
|
+
class WorkflowStepTransition < ApplicationRecord
|
9
|
+
# NOTE: We don't include Statesman::Adapters::ActiveRecordTransition
|
10
|
+
# because we're using PostgreSQL JSONB column for metadata
|
11
|
+
|
12
|
+
# Associations
|
13
|
+
belongs_to :workflow_step, inverse_of: :workflow_step_transitions
|
14
|
+
|
15
|
+
# Validations
|
16
|
+
validates :to_state, inclusion: {
|
17
|
+
in: %w[pending in_progress complete error cancelled resolved_manually],
|
18
|
+
message: 'is not a valid workflow step state'
|
19
|
+
}
|
20
|
+
|
21
|
+
# Validate from_state - allow nil (for initial transitions) but not empty strings
|
22
|
+
validates :from_state, inclusion: {
|
23
|
+
in: %w[pending in_progress complete error cancelled resolved_manually],
|
24
|
+
message: 'is not a valid workflow step state'
|
25
|
+
}, allow_nil: true
|
26
|
+
|
27
|
+
# Prevent empty string states that can cause state machine issues
|
28
|
+
validate :from_state_cannot_be_empty_string
|
29
|
+
validate :to_state_cannot_be_empty_string
|
30
|
+
|
31
|
+
# Ensure metadata is always a hash
|
32
|
+
after_initialize :ensure_metadata_hash
|
33
|
+
# Clean up any empty string states before validation
|
34
|
+
before_validation :normalize_empty_string_states
|
35
|
+
|
36
|
+
# Validate that the workflow step exists before creating transition
|
37
|
+
validate :workflow_step_must_exist
|
38
|
+
|
39
|
+
validates :sort_key, presence: true, uniqueness: { scope: :workflow_step_id }
|
40
|
+
# Custom validation for metadata that allows empty hash but not nil
|
41
|
+
validate :metadata_must_be_hash
|
42
|
+
|
43
|
+
# Ensure metadata defaults to empty hash if not provided
|
44
|
+
before_validation :ensure_metadata_presence
|
45
|
+
|
46
|
+
# Scopes
|
47
|
+
scope :recent, -> { order(sort_key: :desc) }
|
48
|
+
scope :to_state, ->(state) { where(to_state: state) }
|
49
|
+
scope :with_metadata_key, ->(key) { where('metadata ? :key', key: key.to_s) }
|
50
|
+
scope :for_task, ->(task_id) { joins(:workflow_step).where(workflow_steps: { task_id: task_id }) }
|
51
|
+
|
52
|
+
# Class methods for querying transitions
|
53
|
+
class << self
|
54
|
+
# Find the most recent transition to a specific state
|
55
|
+
#
|
56
|
+
# @param state [String, Symbol] The state to find the most recent transition to
|
57
|
+
# @return [WorkflowStepTransition, nil] The most recent transition to the given state
|
58
|
+
def most_recent_to_state(state)
|
59
|
+
to_state(state.to_s).order(sort_key: :desc).first
|
60
|
+
end
|
61
|
+
|
62
|
+
# Find all transitions that occurred within a time range
|
63
|
+
#
|
64
|
+
# @param start_time [Time] The start of the time range
|
65
|
+
# @param end_time [Time] The end of the time range
|
66
|
+
# @return [ActiveRecord::Relation] Transitions within the time range
|
67
|
+
def in_time_range(start_time, end_time)
|
68
|
+
where(created_at: start_time..end_time)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Find transitions with specific metadata values
|
72
|
+
#
|
73
|
+
# @param key [String, Symbol] The metadata key to search for
|
74
|
+
# @param value [Object] The value to match
|
75
|
+
# @return [ActiveRecord::Relation] Transitions with matching metadata
|
76
|
+
def with_metadata_value(key, value)
|
77
|
+
where('metadata->:key = :value', key: key.to_s, value: value.to_json.delete('"'))
|
78
|
+
end
|
79
|
+
|
80
|
+
# Find retry transitions
|
81
|
+
#
|
82
|
+
# @return [ActiveRecord::Relation] Transitions from error back to pending (retries)
|
83
|
+
def retry_transitions
|
84
|
+
joins("INNER JOIN #{table_name} prev ON prev.workflow_step_id = #{table_name}.workflow_step_id")
|
85
|
+
.where(to_state: 'pending')
|
86
|
+
.where('prev.to_state = ? AND prev.sort_key < ?', 'error', arel_table[:sort_key])
|
87
|
+
end
|
88
|
+
|
89
|
+
# Find transitions by attempt number
|
90
|
+
#
|
91
|
+
# @param attempt [Integer] The attempt number to filter by
|
92
|
+
# @return [ActiveRecord::Relation] Transitions for the given attempt
|
93
|
+
def for_attempt(attempt)
|
94
|
+
with_metadata_value('attempt_number', attempt)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Get transition statistics for analytics
|
98
|
+
#
|
99
|
+
# @return [Hash] Statistics about transitions
|
100
|
+
def statistics
|
101
|
+
{
|
102
|
+
total_transitions: count,
|
103
|
+
states: group(:to_state).count,
|
104
|
+
recent_activity: where(created_at: 24.hours.ago..Time.current).count,
|
105
|
+
retry_attempts: retry_transitions.count,
|
106
|
+
average_execution_time: average_execution_time,
|
107
|
+
average_time_between_transitions: average_time_between_transitions
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
# Calculate average execution time for completed steps
|
114
|
+
#
|
115
|
+
# @return [Float, nil] Average execution time in seconds
|
116
|
+
def average_execution_time
|
117
|
+
completed_transitions = with_metadata_key('execution_duration')
|
118
|
+
return nil if completed_transitions.empty?
|
119
|
+
|
120
|
+
total_time = completed_transitions.sum { |t| t.get_metadata('execution_duration', 0) }
|
121
|
+
total_time / completed_transitions.count
|
122
|
+
end
|
123
|
+
|
124
|
+
# Calculate average time between transitions
|
125
|
+
#
|
126
|
+
# @return [Float, nil] Average seconds between transitions
|
127
|
+
def average_time_between_transitions
|
128
|
+
transitions = order(:created_at).pluck(:created_at)
|
129
|
+
return nil if transitions.size < 2
|
130
|
+
|
131
|
+
total_time = 0
|
132
|
+
(1...transitions.size).each do |i|
|
133
|
+
total_time += (transitions[i] - transitions[i - 1])
|
134
|
+
end
|
135
|
+
|
136
|
+
total_time / (transitions.size - 1)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Instance methods
|
141
|
+
|
142
|
+
# Get the associated task through the workflow step
|
143
|
+
#
|
144
|
+
# @return [Task] The task that owns this workflow step
|
145
|
+
delegate :task, to: :workflow_step
|
146
|
+
|
147
|
+
# Get the step name through the workflow step
|
148
|
+
#
|
149
|
+
# @return [String] The name of the workflow step
|
150
|
+
def step_name
|
151
|
+
workflow_step.name
|
152
|
+
end
|
153
|
+
|
154
|
+
# Get the duration since the previous transition
|
155
|
+
#
|
156
|
+
# @return [Float, nil] Duration in seconds since previous transition
|
157
|
+
def duration_since_previous
|
158
|
+
previous_transition = self.class.where(workflow_step_id: workflow_step_id)
|
159
|
+
.where(sort_key: ...sort_key)
|
160
|
+
.order(sort_key: :desc)
|
161
|
+
.first
|
162
|
+
|
163
|
+
return nil unless previous_transition
|
164
|
+
|
165
|
+
created_at - previous_transition.created_at
|
166
|
+
end
|
167
|
+
|
168
|
+
# Check if this transition represents an error state
|
169
|
+
#
|
170
|
+
# @return [Boolean] True if transitioning to an error state
|
171
|
+
def error_transition?
|
172
|
+
to_state == 'error'
|
173
|
+
end
|
174
|
+
|
175
|
+
# Check if this transition represents completion
|
176
|
+
#
|
177
|
+
# @return [Boolean] True if transitioning to a completion state
|
178
|
+
def completion_transition?
|
179
|
+
%w[complete resolved_manually].include?(to_state)
|
180
|
+
end
|
181
|
+
|
182
|
+
# Check if this transition represents cancellation
|
183
|
+
#
|
184
|
+
# @return [Boolean] True if transitioning to cancelled state
|
185
|
+
def cancellation_transition?
|
186
|
+
to_state == 'cancelled'
|
187
|
+
end
|
188
|
+
|
189
|
+
# Check if this transition represents a retry attempt
|
190
|
+
#
|
191
|
+
# @return [Boolean] True if this is a retry transition
|
192
|
+
def retry_transition?
|
193
|
+
to_state == 'pending' && has_metadata?('retry_attempt')
|
194
|
+
end
|
195
|
+
|
196
|
+
# Get the attempt number for this transition
|
197
|
+
#
|
198
|
+
# @return [Integer] The attempt number
|
199
|
+
def attempt_number
|
200
|
+
get_metadata('attempt_number', 1)
|
201
|
+
end
|
202
|
+
|
203
|
+
# Get the execution duration if available
|
204
|
+
#
|
205
|
+
# @return [Float, nil] Execution duration in seconds
|
206
|
+
def execution_duration
|
207
|
+
get_metadata('execution_duration')
|
208
|
+
end
|
209
|
+
|
210
|
+
# Get human-readable description of the transition
|
211
|
+
#
|
212
|
+
# @return [String] Description of what this transition represents
|
213
|
+
def description
|
214
|
+
TransitionDescriptionFormatter.format(self)
|
215
|
+
end
|
216
|
+
|
217
|
+
# Get formatted metadata for display
|
218
|
+
#
|
219
|
+
# @return [Hash] Formatted metadata with additional computed fields
|
220
|
+
def formatted_metadata
|
221
|
+
base_metadata = metadata.dup
|
222
|
+
|
223
|
+
# Add computed fields
|
224
|
+
base_metadata['duration_since_previous'] = duration_since_previous
|
225
|
+
base_metadata['transition_description'] = description
|
226
|
+
base_metadata['transition_timestamp'] = created_at.iso8601
|
227
|
+
base_metadata['step_name'] = step_name
|
228
|
+
base_metadata['task_id'] = workflow_step.task_id
|
229
|
+
|
230
|
+
base_metadata
|
231
|
+
end
|
232
|
+
|
233
|
+
# Check if transition has specific metadata
|
234
|
+
#
|
235
|
+
# @param key [String, Symbol] The metadata key to check for
|
236
|
+
# @return [Boolean] True if the metadata contains the key
|
237
|
+
def has_metadata?(key)
|
238
|
+
metadata.key?(key.to_s)
|
239
|
+
end
|
240
|
+
|
241
|
+
# Get metadata value with default
|
242
|
+
#
|
243
|
+
# @param key [String, Symbol] The metadata key
|
244
|
+
# @param default [Object] Default value if key not found
|
245
|
+
# @return [Object] The metadata value or default
|
246
|
+
def get_metadata(key, default = nil)
|
247
|
+
metadata.fetch(key.to_s, default)
|
248
|
+
end
|
249
|
+
|
250
|
+
# Set metadata value
|
251
|
+
#
|
252
|
+
# @param key [String, Symbol] The metadata key
|
253
|
+
# @param value [Object] The value to set
|
254
|
+
# @return [Object] The set value
|
255
|
+
def set_metadata(key, value)
|
256
|
+
self.metadata = metadata.merge(key.to_s => value)
|
257
|
+
value
|
258
|
+
end
|
259
|
+
|
260
|
+
# Get backoff information if this is an error transition
|
261
|
+
#
|
262
|
+
# @return [Hash, nil] Backoff information or nil if not applicable
|
263
|
+
def backoff_info
|
264
|
+
return nil unless error_transition? && has_metadata?('backoff_until')
|
265
|
+
|
266
|
+
{
|
267
|
+
backoff_until: Time.zone.parse(get_metadata('backoff_until')),
|
268
|
+
backoff_seconds: get_metadata('backoff_seconds'),
|
269
|
+
retry_available: get_metadata('retry_available', false)
|
270
|
+
}
|
271
|
+
end
|
272
|
+
|
273
|
+
private
|
274
|
+
|
275
|
+
# Ensure metadata is always initialized as a hash
|
276
|
+
#
|
277
|
+
# @return [void]
|
278
|
+
def ensure_metadata_hash
|
279
|
+
self.metadata ||= {}
|
280
|
+
end
|
281
|
+
|
282
|
+
# Ensure metadata is present for validation
|
283
|
+
#
|
284
|
+
# @return [void]
|
285
|
+
def ensure_metadata_presence
|
286
|
+
self.metadata = {} if metadata.blank?
|
287
|
+
end
|
288
|
+
|
289
|
+
# Custom validation for metadata
|
290
|
+
#
|
291
|
+
# @return [void]
|
292
|
+
def metadata_must_be_hash
|
293
|
+
if metadata.nil?
|
294
|
+
self.metadata = {}
|
295
|
+
elsif !metadata.is_a?(Hash)
|
296
|
+
errors.add(:metadata, 'must be a hash')
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
# Validate that the workflow step exists
|
301
|
+
#
|
302
|
+
# @return [void]
|
303
|
+
def workflow_step_must_exist
|
304
|
+
return if workflow_step_id.blank?
|
305
|
+
|
306
|
+
return if Tasker::WorkflowStep.exists?(workflow_step_id: workflow_step_id)
|
307
|
+
|
308
|
+
errors.add(:workflow_step_id, 'must reference an existing workflow step')
|
309
|
+
end
|
310
|
+
|
311
|
+
# Prevent empty string from_state values that cause state machine failures
|
312
|
+
def from_state_cannot_be_empty_string
|
313
|
+
return unless from_state == ''
|
314
|
+
|
315
|
+
errors.add(:from_state, 'cannot be an empty string (use nil for initial transitions)')
|
316
|
+
end
|
317
|
+
|
318
|
+
# Prevent empty string to_state values
|
319
|
+
def to_state_cannot_be_empty_string
|
320
|
+
return unless to_state == ''
|
321
|
+
|
322
|
+
errors.add(:to_state, 'cannot be an empty string')
|
323
|
+
end
|
324
|
+
|
325
|
+
# Clean up any empty string states before validation
|
326
|
+
# This prevents empty strings from being saved and causing state machine issues
|
327
|
+
def normalize_empty_string_states
|
328
|
+
# Convert empty strings to nil for from_state (initial transitions)
|
329
|
+
self.from_state = nil if from_state == ''
|
330
|
+
|
331
|
+
# For to_state, empty strings are always invalid - convert to nil and let validation catch it
|
332
|
+
return unless to_state == ''
|
333
|
+
|
334
|
+
self.to_state = nil
|
335
|
+
errors.add(:to_state, 'cannot be empty - must specify a valid state')
|
336
|
+
end
|
337
|
+
|
338
|
+
# Service class to format transition descriptions
|
339
|
+
# Reduces complexity by organizing description logic by state
|
340
|
+
class TransitionDescriptionFormatter
|
341
|
+
class << self
|
342
|
+
# Format transition description based on state
|
343
|
+
#
|
344
|
+
# @param transition [WorkflowStepTransition] The transition to describe
|
345
|
+
# @return [String] Formatted description
|
346
|
+
def format(transition)
|
347
|
+
case transition.to_state
|
348
|
+
when 'pending'
|
349
|
+
format_pending_description(transition)
|
350
|
+
when 'in_progress'
|
351
|
+
format_in_progress_description(transition)
|
352
|
+
when 'complete'
|
353
|
+
format_complete_description(transition)
|
354
|
+
when 'error'
|
355
|
+
format_error_description(transition)
|
356
|
+
when 'cancelled'
|
357
|
+
format_cancelled_description(transition)
|
358
|
+
when 'resolved_manually'
|
359
|
+
format_resolved_description(transition)
|
360
|
+
else
|
361
|
+
format_unknown_description(transition)
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
private
|
366
|
+
|
367
|
+
# Format description for pending transitions
|
368
|
+
#
|
369
|
+
# @param transition [WorkflowStepTransition] The transition
|
370
|
+
# @return [String] Formatted description
|
371
|
+
def format_pending_description(transition)
|
372
|
+
if transition.retry_transition?
|
373
|
+
"Step retry attempt ##{transition.attempt_number}"
|
374
|
+
else
|
375
|
+
'Step initialized and ready for execution'
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
# Format description for in_progress transitions
|
380
|
+
#
|
381
|
+
# @param transition [WorkflowStepTransition] The transition
|
382
|
+
# @return [String] Formatted description
|
383
|
+
def format_in_progress_description(transition)
|
384
|
+
"Step execution started (attempt ##{transition.attempt_number})"
|
385
|
+
end
|
386
|
+
|
387
|
+
# Format description for complete transitions
|
388
|
+
#
|
389
|
+
# @param transition [WorkflowStepTransition] The transition
|
390
|
+
# @return [String] Formatted description
|
391
|
+
def format_complete_description(transition)
|
392
|
+
duration_text = transition.execution_duration ? " in #{transition.execution_duration.round(2)}s" : ''
|
393
|
+
"Step completed successfully#{duration_text}"
|
394
|
+
end
|
395
|
+
|
396
|
+
# Format description for error transitions
|
397
|
+
#
|
398
|
+
# @param transition [WorkflowStepTransition] The transition
|
399
|
+
# @return [String] Formatted description
|
400
|
+
def format_error_description(transition)
|
401
|
+
error_msg = transition.get_metadata('error_message', 'Unknown error')
|
402
|
+
backoff_text = transition.has_metadata?('backoff_until') ? ' (retry scheduled)' : ''
|
403
|
+
"Step failed: #{error_msg}#{backoff_text}"
|
404
|
+
end
|
405
|
+
|
406
|
+
# Format description for cancelled transitions
|
407
|
+
#
|
408
|
+
# @param transition [WorkflowStepTransition] The transition
|
409
|
+
# @return [String] Formatted description
|
410
|
+
def format_cancelled_description(transition)
|
411
|
+
reason = transition.get_metadata('triggered_by', 'manual cancellation')
|
412
|
+
"Step cancelled due to #{reason}"
|
413
|
+
end
|
414
|
+
|
415
|
+
# Format description for resolved_manually transitions
|
416
|
+
#
|
417
|
+
# @param transition [WorkflowStepTransition] The transition
|
418
|
+
# @return [String] Formatted description
|
419
|
+
def format_resolved_description(transition)
|
420
|
+
resolver = transition.get_metadata('resolved_by', 'unknown')
|
421
|
+
"Step manually resolved by #{resolver}"
|
422
|
+
end
|
423
|
+
|
424
|
+
# Format description for unknown transitions
|
425
|
+
#
|
426
|
+
# @param transition [WorkflowStepTransition] The transition
|
427
|
+
# @return [String] Formatted description
|
428
|
+
def format_unknown_description(transition)
|
429
|
+
"Step transitioned to #{transition.to_state}"
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|
433
|
+
end
|
434
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Tasker
|
5
|
+
class HandlerSerializer < ActiveModel::Serializer
|
6
|
+
attributes :name, :namespace, :version, :full_name, :class_name, :available, :step_templates
|
7
|
+
|
8
|
+
def initialize(object, options = {})
|
9
|
+
@handler_name = options[:handler_name]
|
10
|
+
@namespace = options[:namespace] || :default
|
11
|
+
@version = options[:version] || '0.1.0'
|
12
|
+
@handler_class = object
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
def name
|
17
|
+
@handler_name.to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
def namespace
|
21
|
+
@namespace.to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
def version
|
25
|
+
@version.to_s
|
26
|
+
end
|
27
|
+
|
28
|
+
def full_name
|
29
|
+
"#{namespace}.#{name}@#{version}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def class_name
|
33
|
+
if @handler_class.is_a?(Class)
|
34
|
+
@handler_class.name
|
35
|
+
else
|
36
|
+
@handler_class.to_s
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def available
|
41
|
+
instantiate_handler
|
42
|
+
true
|
43
|
+
rescue StandardError
|
44
|
+
false
|
45
|
+
end
|
46
|
+
|
47
|
+
def step_templates
|
48
|
+
return [] unless handler_instance
|
49
|
+
|
50
|
+
begin
|
51
|
+
templates = handler_instance.step_templates
|
52
|
+
return [] unless templates.respond_to?(:map)
|
53
|
+
|
54
|
+
templates.map do |template|
|
55
|
+
template_hash = {}
|
56
|
+
|
57
|
+
# Handle StepTemplate dry-struct attributes
|
58
|
+
template_hash[:name] = template.name.to_s if template.respond_to?(:name)
|
59
|
+
template_hash[:description] = template.description if template.respond_to?(:description)
|
60
|
+
template_hash[:dependent_system] = template.dependent_system.to_s if template.respond_to?(:dependent_system)
|
61
|
+
if template.respond_to?(:depends_on_step) && template.depends_on_step
|
62
|
+
template_hash[:depends_on_step] =
|
63
|
+
template.depends_on_step.to_s
|
64
|
+
end
|
65
|
+
template_hash[:depends_on_steps] = template.depends_on_steps if template.respond_to?(:depends_on_steps)
|
66
|
+
|
67
|
+
# Handle handler class - could be Class object or string
|
68
|
+
if template.respond_to?(:handler_class)
|
69
|
+
template_hash[:handler_class] =
|
70
|
+
template.handler_class.is_a?(Class) ? template.handler_class.name : template.handler_class.to_s
|
71
|
+
end
|
72
|
+
|
73
|
+
# Use the correct attribute name for configuration
|
74
|
+
template_hash[:configuration] = template.handler_config if template.respond_to?(:handler_config)
|
75
|
+
|
76
|
+
# Include dry-struct specific attributes
|
77
|
+
template_hash[:default_retryable] = template.default_retryable if template.respond_to?(:default_retryable)
|
78
|
+
if template.respond_to?(:default_retry_limit)
|
79
|
+
template_hash[:default_retry_limit] =
|
80
|
+
template.default_retry_limit
|
81
|
+
end
|
82
|
+
template_hash[:skippable] = template.skippable if template.respond_to?(:skippable)
|
83
|
+
template_hash[:custom_events] = template.custom_events if template.respond_to?(:custom_events)
|
84
|
+
|
85
|
+
template_hash
|
86
|
+
end
|
87
|
+
rescue StandardError => e
|
88
|
+
Rails.logger.warn "Failed to introspect step templates for #{class_name}: #{e.message}"
|
89
|
+
[]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def handler_instance
|
96
|
+
@handler_instance ||= instantiate_handler
|
97
|
+
rescue StandardError
|
98
|
+
nil
|
99
|
+
end
|
100
|
+
|
101
|
+
def instantiate_handler
|
102
|
+
if @handler_class.is_a?(Class)
|
103
|
+
@handler_class.new
|
104
|
+
else
|
105
|
+
@handler_class.to_s.camelize.constantize.new
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# == Schema Information
|
5
|
+
#
|
6
|
+
# Table name: task_annotations
|
7
|
+
#
|
8
|
+
# annotation :jsonb
|
9
|
+
# created_at :datetime not null
|
10
|
+
# updated_at :datetime not null
|
11
|
+
# annotation_type_id :integer not null
|
12
|
+
# task_annotation_id :bigint not null, primary key
|
13
|
+
# task_id :bigint not null
|
14
|
+
#
|
15
|
+
# Indexes
|
16
|
+
#
|
17
|
+
# task_annotations_annotation_idx (annotation) USING gin
|
18
|
+
# task_annotations_annotation_idx1 (annotation) USING gin
|
19
|
+
# task_annotations_annotation_type_id_index (annotation_type_id)
|
20
|
+
# task_annotations_task_id_index (task_id)
|
21
|
+
#
|
22
|
+
# Foreign Keys
|
23
|
+
#
|
24
|
+
# task_annotations_annotation_type_id_foreign (annotation_type_id => annotation_types.annotation_type_id)
|
25
|
+
# task_annotations_task_id_foreign (task_id => tasks.task_id)
|
26
|
+
#
|
27
|
+
|
28
|
+
module Tasker
|
29
|
+
class TaskAnnotationSerializer < ActiveModel::Serializer
|
30
|
+
attributes :task_id, :task_annotation_id, :annotation, :annotation_type_name
|
31
|
+
end
|
32
|
+
end
|