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,328 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tasker
|
4
|
+
module Analysis
|
5
|
+
# Analyzes step template dependencies for workflow design validation
|
6
|
+
#
|
7
|
+
# This class provides comprehensive analysis of step template dependencies,
|
8
|
+
# including cycle detection, topological sorting, and dependency visualization.
|
9
|
+
# It's designed to help with workflow design validation and troubleshooting.
|
10
|
+
#
|
11
|
+
# The analyzer performs static analysis on step templates to identify potential
|
12
|
+
# issues before workflow execution, including circular dependencies, dependency
|
13
|
+
# depth analysis, and parallel execution opportunities.
|
14
|
+
#
|
15
|
+
# @example Basic usage
|
16
|
+
# analyzer = TemplateGraphAnalyzer.new(handler.step_templates)
|
17
|
+
# graph = analyzer.analyze
|
18
|
+
# puts "Cycles detected: #{graph[:cycles].any?}"
|
19
|
+
#
|
20
|
+
# @example Checking for specific issues
|
21
|
+
# analyzer = TemplateGraphAnalyzer.new(templates)
|
22
|
+
# if analyzer.has_cycles?
|
23
|
+
# puts "Circular dependencies found: #{analyzer.cycles}"
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# @since 2.2.0
|
27
|
+
class TemplateGraphAnalyzer
|
28
|
+
# @return [Array<Tasker::Types::StepTemplate>] The step templates being analyzed
|
29
|
+
attr_reader :templates
|
30
|
+
|
31
|
+
# Initialize the analyzer with step templates
|
32
|
+
#
|
33
|
+
# @param templates [Array<Tasker::Types::StepTemplate>] Step templates to analyze
|
34
|
+
def initialize(templates)
|
35
|
+
@templates = templates
|
36
|
+
@dependency_map = nil
|
37
|
+
@analysis_cache = nil
|
38
|
+
end
|
39
|
+
|
40
|
+
# Perform comprehensive dependency analysis
|
41
|
+
#
|
42
|
+
# @return [Hash] Comprehensive dependency analysis containing:
|
43
|
+
# - :nodes - Array of step information with dependencies
|
44
|
+
# - :edges - Array of dependency relationships
|
45
|
+
# - :topology - Topologically sorted step names
|
46
|
+
# - :cycles - Array of detected circular dependencies
|
47
|
+
# - :levels - Hash mapping steps to their dependency depth levels
|
48
|
+
# - :roots - Array of steps with no dependencies
|
49
|
+
# - :leaves - Array of steps with no dependents
|
50
|
+
# - :summary - Summary statistics
|
51
|
+
def analyze
|
52
|
+
return @analysis_cache if @analysis_cache
|
53
|
+
|
54
|
+
nodes = build_nodes
|
55
|
+
edges = build_edges
|
56
|
+
dependency_map = build_dependency_map
|
57
|
+
cycles = detect_cycles(dependency_map)
|
58
|
+
topology = cycles.empty? ? topological_sort(dependency_map) : []
|
59
|
+
levels = calculate_dependency_levels(dependency_map, topology)
|
60
|
+
roots = find_root_steps
|
61
|
+
leaves = find_leaf_steps(edges)
|
62
|
+
|
63
|
+
@analysis_cache = {
|
64
|
+
nodes: nodes,
|
65
|
+
edges: edges,
|
66
|
+
topology: topology,
|
67
|
+
cycles: cycles,
|
68
|
+
levels: levels,
|
69
|
+
roots: roots,
|
70
|
+
leaves: leaves,
|
71
|
+
summary: build_summary(cycles, levels, edges)
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
# Check if the workflow has circular dependencies
|
76
|
+
#
|
77
|
+
# @return [Boolean] True if cycles are detected
|
78
|
+
def has_cycles?
|
79
|
+
cycles.any?
|
80
|
+
end
|
81
|
+
|
82
|
+
# Get detected circular dependencies
|
83
|
+
#
|
84
|
+
# @return [Array<Array<String>>] Array of detected cycles
|
85
|
+
def cycles
|
86
|
+
analyze[:cycles]
|
87
|
+
end
|
88
|
+
|
89
|
+
# Get topological ordering of steps
|
90
|
+
#
|
91
|
+
# @return [Array<String>] Topologically sorted step names
|
92
|
+
def topology
|
93
|
+
analyze[:topology]
|
94
|
+
end
|
95
|
+
|
96
|
+
# Get dependency levels for all steps
|
97
|
+
#
|
98
|
+
# @return [Hash<String, Integer>] Step name to dependency level mapping
|
99
|
+
def levels
|
100
|
+
analyze[:levels]
|
101
|
+
end
|
102
|
+
|
103
|
+
# Get steps with no dependencies (workflow entry points)
|
104
|
+
#
|
105
|
+
# @return [Array<String>] Root step names
|
106
|
+
def roots
|
107
|
+
analyze[:roots]
|
108
|
+
end
|
109
|
+
|
110
|
+
# Get steps with no dependents (workflow exit points)
|
111
|
+
#
|
112
|
+
# @return [Array<String>] Leaf step names
|
113
|
+
def leaves
|
114
|
+
analyze[:leaves]
|
115
|
+
end
|
116
|
+
|
117
|
+
# Clear analysis cache (useful if templates change)
|
118
|
+
#
|
119
|
+
# @return [void]
|
120
|
+
def clear_cache!
|
121
|
+
@analysis_cache = nil
|
122
|
+
@dependency_map = nil
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
# Build nodes with dependency information
|
128
|
+
#
|
129
|
+
# @return [Array<Hash>] Node information for each step
|
130
|
+
# @api private
|
131
|
+
def build_nodes
|
132
|
+
templates.map do |template|
|
133
|
+
{
|
134
|
+
name: template.name,
|
135
|
+
description: template.description,
|
136
|
+
handler_class: template.handler_class.name,
|
137
|
+
dependencies: template.all_dependencies,
|
138
|
+
dependency_count: template.all_dependencies.size
|
139
|
+
}
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# Build edges (dependency relationships)
|
144
|
+
#
|
145
|
+
# @return [Array<Hash>] Edge information for dependencies
|
146
|
+
# @api private
|
147
|
+
def build_edges
|
148
|
+
edges = []
|
149
|
+
templates.each do |template|
|
150
|
+
template.all_dependencies.each do |dependency|
|
151
|
+
edges << {
|
152
|
+
from: dependency,
|
153
|
+
to: template.name,
|
154
|
+
type: template.depends_on_step == dependency ? 'single' : 'multiple'
|
155
|
+
}
|
156
|
+
end
|
157
|
+
end
|
158
|
+
edges
|
159
|
+
end
|
160
|
+
|
161
|
+
# Build dependency map from step templates
|
162
|
+
#
|
163
|
+
# @return [Hash<String, Array<String>>] Map of step name to its dependencies
|
164
|
+
# @api private
|
165
|
+
def build_dependency_map
|
166
|
+
return @dependency_map if @dependency_map
|
167
|
+
|
168
|
+
@dependency_map = templates.each_with_object({}) do |template, map|
|
169
|
+
map[template.name] = template.all_dependencies
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# Detect circular dependencies using depth-first search
|
174
|
+
#
|
175
|
+
# @param dependency_map [Hash<String, Array<String>>] Step dependencies
|
176
|
+
# @return [Array<Array<String>>] Array of detected cycles
|
177
|
+
# @api private
|
178
|
+
def detect_cycles(dependency_map)
|
179
|
+
cycles = []
|
180
|
+
visited = Set.new
|
181
|
+
rec_stack = Set.new
|
182
|
+
|
183
|
+
dependency_map.each_key do |step|
|
184
|
+
next if visited.include?(step)
|
185
|
+
|
186
|
+
cycle = find_cycle_from_step(step, dependency_map, visited, rec_stack, [])
|
187
|
+
cycles << cycle if cycle
|
188
|
+
end
|
189
|
+
|
190
|
+
cycles
|
191
|
+
end
|
192
|
+
|
193
|
+
# Find cycle starting from a specific step
|
194
|
+
#
|
195
|
+
# @param step [String] Starting step name
|
196
|
+
# @param dependency_map [Hash] Step dependencies
|
197
|
+
# @param visited [Set] Visited steps
|
198
|
+
# @param rec_stack [Set] Recursion stack
|
199
|
+
# @param path [Array] Current path
|
200
|
+
# @return [Array<String>, nil] Cycle path or nil
|
201
|
+
# @api private
|
202
|
+
def find_cycle_from_step(step, dependency_map, visited, rec_stack, path)
|
203
|
+
return nil if visited.include?(step)
|
204
|
+
|
205
|
+
visited.add(step)
|
206
|
+
rec_stack.add(step)
|
207
|
+
current_path = path + [step]
|
208
|
+
|
209
|
+
dependency_map[step].each do |dependency|
|
210
|
+
if rec_stack.include?(dependency)
|
211
|
+
# Found cycle - return the cycle portion
|
212
|
+
cycle_start = current_path.index(dependency)
|
213
|
+
return current_path[cycle_start..] + [dependency]
|
214
|
+
end
|
215
|
+
|
216
|
+
cycle = find_cycle_from_step(dependency, dependency_map, visited, rec_stack, current_path)
|
217
|
+
return cycle if cycle
|
218
|
+
end
|
219
|
+
|
220
|
+
rec_stack.delete(step)
|
221
|
+
nil
|
222
|
+
end
|
223
|
+
|
224
|
+
# Perform topological sort of steps using Kahn's algorithm
|
225
|
+
#
|
226
|
+
# @param dependency_map [Hash<String, Array<String>>] Step dependencies
|
227
|
+
# @return [Array<String>] Topologically sorted step names
|
228
|
+
# @api private
|
229
|
+
def topological_sort(dependency_map)
|
230
|
+
in_degree = Hash.new(0)
|
231
|
+
reverse_deps = Hash.new { |h, k| h[k] = [] }
|
232
|
+
|
233
|
+
# Calculate in-degrees and reverse dependencies
|
234
|
+
dependency_map.each do |step, dependencies|
|
235
|
+
in_degree[step] ||= 0
|
236
|
+
dependencies.each do |dep|
|
237
|
+
in_degree[step] += 1
|
238
|
+
reverse_deps[dep] << step
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
# Start with steps that have no dependencies
|
243
|
+
queue = dependency_map.keys.select { |step| in_degree[step].zero? }
|
244
|
+
result = []
|
245
|
+
|
246
|
+
while queue.any?
|
247
|
+
current = queue.shift
|
248
|
+
result << current
|
249
|
+
|
250
|
+
# Remove edges from current step to its dependents
|
251
|
+
reverse_deps[current].each do |dependent|
|
252
|
+
in_degree[dependent] -= 1
|
253
|
+
queue << dependent if in_degree[dependent].zero?
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
result
|
258
|
+
end
|
259
|
+
|
260
|
+
# Calculate dependency levels for each step
|
261
|
+
#
|
262
|
+
# @param dependency_map [Hash<String, Array<String>>] Step dependencies
|
263
|
+
# @param topology [Array<String>] Topologically sorted steps
|
264
|
+
# @return [Hash<String, Integer>] Step name to dependency level
|
265
|
+
# @api private
|
266
|
+
def calculate_dependency_levels(dependency_map, topology)
|
267
|
+
levels = {}
|
268
|
+
|
269
|
+
topology.each do |step|
|
270
|
+
if dependency_map[step].empty?
|
271
|
+
levels[step] = 0
|
272
|
+
else
|
273
|
+
max_dependency_level = dependency_map[step].map { |dep| levels[dep] || 0 }.max
|
274
|
+
levels[step] = max_dependency_level + 1
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
levels
|
279
|
+
end
|
280
|
+
|
281
|
+
# Find steps with no dependencies
|
282
|
+
#
|
283
|
+
# @return [Array<String>] Root step names
|
284
|
+
# @api private
|
285
|
+
def find_root_steps
|
286
|
+
dependency_map = build_dependency_map
|
287
|
+
dependency_map.keys.select { |name| dependency_map[name].empty? }
|
288
|
+
end
|
289
|
+
|
290
|
+
# Find steps with no dependents
|
291
|
+
#
|
292
|
+
# @param edges [Array<Hash>] Dependency edges
|
293
|
+
# @return [Array<String>] Leaf step names
|
294
|
+
# @api private
|
295
|
+
def find_leaf_steps(edges)
|
296
|
+
step_names = templates.map(&:name)
|
297
|
+
step_names.reject { |name| edges.any? { |edge| edge[:from] == name } }
|
298
|
+
end
|
299
|
+
|
300
|
+
# Build summary statistics
|
301
|
+
#
|
302
|
+
# @param cycles [Array] Detected cycles
|
303
|
+
# @param levels [Hash] Dependency levels
|
304
|
+
# @param edges [Array] Dependency edges
|
305
|
+
# @return [Hash] Summary statistics
|
306
|
+
# @api private
|
307
|
+
def build_summary(cycles, levels, edges)
|
308
|
+
{
|
309
|
+
total_steps: templates.size,
|
310
|
+
total_dependencies: edges.size,
|
311
|
+
has_cycles: cycles.any?,
|
312
|
+
max_depth: levels.values.max || 0,
|
313
|
+
parallel_branches: count_parallel_branches(levels)
|
314
|
+
}
|
315
|
+
end
|
316
|
+
|
317
|
+
# Count parallel branches in the dependency graph
|
318
|
+
#
|
319
|
+
# @param levels [Hash<String, Integer>] Dependency levels
|
320
|
+
# @return [Integer] Number of parallel execution branches
|
321
|
+
# @api private
|
322
|
+
def count_parallel_branches(levels)
|
323
|
+
level_counts = levels.values.group_by(&:itself).transform_values(&:size)
|
324
|
+
level_counts.values.max || 1
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'errors'
|
4
|
+
require_relative 'none_authenticator'
|
5
|
+
|
6
|
+
module Tasker
|
7
|
+
module Authentication
|
8
|
+
class Coordinator
|
9
|
+
class << self
|
10
|
+
def authenticator
|
11
|
+
@authenticator ||= build_authenticator
|
12
|
+
end
|
13
|
+
|
14
|
+
delegate :authenticate!, to: :authenticator
|
15
|
+
|
16
|
+
delegate :current_user, to: :authenticator
|
17
|
+
|
18
|
+
delegate :authenticated?, to: :authenticator
|
19
|
+
|
20
|
+
def reset!
|
21
|
+
@authenticator = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def build_authenticator
|
27
|
+
auth_config = Tasker.configuration.auth
|
28
|
+
|
29
|
+
if auth_config.authentication_enabled
|
30
|
+
build_custom_authenticator(auth_config)
|
31
|
+
else
|
32
|
+
NoneAuthenticator.new
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def build_custom_authenticator(auth_config)
|
37
|
+
authenticator_class = auth_config.authenticator_class
|
38
|
+
|
39
|
+
unless authenticator_class
|
40
|
+
raise ConfigurationError,
|
41
|
+
'Authentication is enabled but no authenticator_class is specified'
|
42
|
+
end
|
43
|
+
|
44
|
+
# Instantiate the host app's authenticator
|
45
|
+
klass = authenticator_class.constantize
|
46
|
+
# Pass empty options hash for now - authenticators can get config from Tasker.configuration
|
47
|
+
authenticator = klass.new({})
|
48
|
+
|
49
|
+
# Validate it implements the interface
|
50
|
+
validate_authenticator!(authenticator)
|
51
|
+
|
52
|
+
authenticator
|
53
|
+
end
|
54
|
+
|
55
|
+
def validate_authenticator!(authenticator)
|
56
|
+
required_methods = %i[authenticate! current_user]
|
57
|
+
|
58
|
+
required_methods.each do |method|
|
59
|
+
unless authenticator.respond_to?(method)
|
60
|
+
raise InterfaceError,
|
61
|
+
"Authenticator #{authenticator.class} must implement ##{method}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Run configuration validation if supported
|
66
|
+
return unless authenticator.respond_to?(:validate_configuration)
|
67
|
+
|
68
|
+
# Pass configuration options for validation - authenticators can extract what they need
|
69
|
+
errors = authenticator.validate_configuration({})
|
70
|
+
return unless errors.any?
|
71
|
+
|
72
|
+
raise ConfigurationError,
|
73
|
+
"Authenticator configuration errors: #{errors.join(', ')}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tasker
|
4
|
+
module Authentication
|
5
|
+
# Interface that host application authenticators must implement
|
6
|
+
module Interface
|
7
|
+
# Required: Authenticate the request, raise exception if fails
|
8
|
+
# @param controller [ActionController::Base] The controller instance
|
9
|
+
# @return [void] Should raise exception on authentication failure
|
10
|
+
def authenticate!(controller)
|
11
|
+
raise NotImplementedError, 'Authenticator must implement #authenticate!'
|
12
|
+
end
|
13
|
+
|
14
|
+
# Required: Get the current authenticated user
|
15
|
+
# @param controller [ActionController::Base] The controller instance
|
16
|
+
# @return [Object, nil] The authenticated user object or nil
|
17
|
+
def current_user(controller)
|
18
|
+
raise NotImplementedError, 'Authenticator must implement #current_user'
|
19
|
+
end
|
20
|
+
|
21
|
+
# Optional: Check if user is authenticated (uses current_user by default)
|
22
|
+
# @param controller [ActionController::Base] The controller instance
|
23
|
+
# @return [Boolean] true if authenticated, false otherwise
|
24
|
+
def authenticated?(controller)
|
25
|
+
current_user(controller).present?
|
26
|
+
end
|
27
|
+
|
28
|
+
# Optional: Configuration validation for the authenticator
|
29
|
+
# @param _options [Hash] Configuration options (unused in default implementation)
|
30
|
+
# @return [Array<String>] Array of validation error messages, empty if valid
|
31
|
+
def validate_configuration(_options = {})
|
32
|
+
[]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'interface'
|
4
|
+
|
5
|
+
module Tasker
|
6
|
+
module Authentication
|
7
|
+
class NoneAuthenticator
|
8
|
+
include Interface
|
9
|
+
|
10
|
+
def authenticate!(_controller)
|
11
|
+
# No authentication required - always succeeds
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
def current_user(_controller)
|
16
|
+
# No user in no-auth mode
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def authenticated?(_controller)
|
21
|
+
# Always considered "authenticated" in no-auth mode
|
22
|
+
true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tasker
|
4
|
+
module Authorization
|
5
|
+
# Base authorization coordinator providing the foundation for authorization logic.
|
6
|
+
#
|
7
|
+
# This class implements the core authorization interface that can be extended
|
8
|
+
# by host applications to provide custom authorization logic. It follows the
|
9
|
+
# same dependency injection pattern as the authentication system.
|
10
|
+
#
|
11
|
+
# Host applications should inherit from this class and implement the
|
12
|
+
# `authorized?` method to provide their authorization logic.
|
13
|
+
#
|
14
|
+
# @example Basic usage
|
15
|
+
# coordinator = BaseCoordinator.new(current_user)
|
16
|
+
# coordinator.authorize!('tasker.task', :show, { task_id: 123 })
|
17
|
+
#
|
18
|
+
# @example Custom implementation
|
19
|
+
# class MyAuthorizationCoordinator < BaseCoordinator
|
20
|
+
# protected
|
21
|
+
#
|
22
|
+
# def authorized?(resource, action, context = {})
|
23
|
+
# case resource
|
24
|
+
# when 'tasker.task'
|
25
|
+
# user.can_access_tasks?
|
26
|
+
# else
|
27
|
+
# false
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
class BaseCoordinator
|
32
|
+
# Initialize the authorization coordinator
|
33
|
+
#
|
34
|
+
# @param user [Object, nil] The user object to authorize against
|
35
|
+
def initialize(user = nil)
|
36
|
+
@user = user
|
37
|
+
end
|
38
|
+
|
39
|
+
# Authorize an action and raise an exception if not permitted
|
40
|
+
#
|
41
|
+
# This method checks authorization and raises an UnauthorizedError
|
42
|
+
# if the action is not permitted.
|
43
|
+
#
|
44
|
+
# @param resource [String] The resource being accessed (e.g., 'tasker.task')
|
45
|
+
# @param action [Symbol, String] The action being performed (e.g., :show)
|
46
|
+
# @param context [Hash] Additional context for authorization decisions
|
47
|
+
# @raise [UnauthorizedError] When the action is not authorized
|
48
|
+
# @return [true] When the action is authorized
|
49
|
+
def authorize!(resource, action, context = {})
|
50
|
+
unless can?(resource, action, context)
|
51
|
+
raise UnauthorizedError,
|
52
|
+
"Not authorized to #{action} on #{resource}"
|
53
|
+
end
|
54
|
+
|
55
|
+
true
|
56
|
+
end
|
57
|
+
|
58
|
+
# Check if an action is authorized
|
59
|
+
#
|
60
|
+
# This method performs the authorization check without raising an exception.
|
61
|
+
# It validates the resource and action exist, then delegates to the
|
62
|
+
# `authorized?` method for the actual authorization logic.
|
63
|
+
#
|
64
|
+
# @param resource [String] The resource being accessed
|
65
|
+
# @param action [Symbol, String] The action being performed
|
66
|
+
# @param context [Hash] Additional context for authorization decisions
|
67
|
+
# @return [Boolean] True if the action is authorized
|
68
|
+
def can?(resource, action, context = {})
|
69
|
+
# Allow all actions if authorization is disabled
|
70
|
+
return true unless authorization_enabled?
|
71
|
+
|
72
|
+
# Validate resource and action exist in the registry
|
73
|
+
unless ResourceRegistry.action_exists?(resource, action)
|
74
|
+
raise ArgumentError, "Unknown resource:action '#{resource}:#{action}'"
|
75
|
+
end
|
76
|
+
|
77
|
+
# Delegate to subclass implementation
|
78
|
+
authorized?(resource, action, context)
|
79
|
+
end
|
80
|
+
|
81
|
+
protected
|
82
|
+
|
83
|
+
# Authorization logic to be implemented by subclasses
|
84
|
+
#
|
85
|
+
# This method should be overridden by host applications to provide
|
86
|
+
# their specific authorization logic. The default implementation
|
87
|
+
# denies all access.
|
88
|
+
#
|
89
|
+
# @param _resource [String] The resource being accessed (unused in base implementation)
|
90
|
+
# @param _action [Symbol, String] The action being performed (unused in base implementation)
|
91
|
+
# @param _context [Hash] Additional context for authorization decisions (unused in base implementation)
|
92
|
+
# @return [Boolean] True if the action should be authorized
|
93
|
+
def authorized?(_resource, _action, _context = {})
|
94
|
+
# Default implementation: deny all access
|
95
|
+
# Subclasses should override this method
|
96
|
+
false
|
97
|
+
end
|
98
|
+
|
99
|
+
# Check if authorization is enabled in the configuration
|
100
|
+
#
|
101
|
+
# @return [Boolean] True if authorization is enabled
|
102
|
+
def authorization_enabled?
|
103
|
+
Tasker.configuration.auth.authorization_enabled
|
104
|
+
end
|
105
|
+
|
106
|
+
# The user object for authorization checks
|
107
|
+
#
|
108
|
+
# @return [Object, nil] The current user
|
109
|
+
attr_reader :user
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tasker
|
4
|
+
module Authorization
|
5
|
+
# Base error class for all authorization-related errors
|
6
|
+
class AuthorizationError < StandardError; end
|
7
|
+
|
8
|
+
# Raised when a user is not authorized to perform a specific action
|
9
|
+
#
|
10
|
+
# This error should be raised when authorization checks fail, typically
|
11
|
+
# resulting in a 403 Forbidden HTTP response.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# raise UnauthorizedError, "Not authorized to delete task 123"
|
15
|
+
class UnauthorizedError < AuthorizationError; end
|
16
|
+
|
17
|
+
# Raised when authorization configuration is invalid
|
18
|
+
#
|
19
|
+
# This error indicates problems with the authorization setup, such as
|
20
|
+
# missing coordinator classes or invalid configuration options.
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
# raise ConfigurationError, "Authorization coordinator class 'InvalidClass' not found"
|
24
|
+
class ConfigurationError < AuthorizationError; end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tasker
|
4
|
+
module Authorization
|
5
|
+
# Constants for authorization resource names and actions.
|
6
|
+
#
|
7
|
+
# This module provides centralized constants for all authorization
|
8
|
+
# resource identifiers, making the codebase more maintainable and
|
9
|
+
# reducing the risk of typos in resource strings.
|
10
|
+
#
|
11
|
+
# @example Using resource constants
|
12
|
+
# coordinator.authorize!(RESOURCES::TASK, ACTIONS::SHOW)
|
13
|
+
# ResourceRegistry.resource_exists?(RESOURCES::WORKFLOW_STEP)
|
14
|
+
module ResourceConstants
|
15
|
+
# Resource name constants
|
16
|
+
module RESOURCES
|
17
|
+
TASK = 'tasker.task'
|
18
|
+
WORKFLOW_STEP = 'tasker.workflow_step'
|
19
|
+
TASK_DIAGRAM = 'tasker.task_diagram'
|
20
|
+
HEALTH_STATUS = 'tasker.health_status'
|
21
|
+
HANDLER = 'tasker.handler'
|
22
|
+
METRICS = 'tasker.metrics'
|
23
|
+
ANALYTICS = 'tasker.analytics'
|
24
|
+
|
25
|
+
# Get all resource constants as an array
|
26
|
+
#
|
27
|
+
# @return [Array<String>] All defined resource names
|
28
|
+
def self.all
|
29
|
+
[TASK, WORKFLOW_STEP, TASK_DIAGRAM, HEALTH_STATUS, HANDLER, METRICS, ANALYTICS]
|
30
|
+
end
|
31
|
+
|
32
|
+
# Check if a resource constant is defined
|
33
|
+
#
|
34
|
+
# @param resource [String] Resource name to check
|
35
|
+
# @return [Boolean] True if the resource is defined
|
36
|
+
def self.include?(resource)
|
37
|
+
all.include?(resource)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Common action constants used across resources
|
42
|
+
module ACTIONS
|
43
|
+
INDEX = :index
|
44
|
+
SHOW = :show
|
45
|
+
CREATE = :create
|
46
|
+
UPDATE = :update
|
47
|
+
DESTROY = :destroy
|
48
|
+
RETRY = :retry
|
49
|
+
CANCEL = :cancel
|
50
|
+
|
51
|
+
# Standard CRUD actions
|
52
|
+
#
|
53
|
+
# @return [Array<Symbol>] Standard CRUD action symbols
|
54
|
+
def self.crud
|
55
|
+
[INDEX, SHOW, CREATE, UPDATE, DESTROY]
|
56
|
+
end
|
57
|
+
|
58
|
+
# Task-specific actions
|
59
|
+
#
|
60
|
+
# @return [Array<Symbol>] Actions specific to tasks
|
61
|
+
def self.task_specific
|
62
|
+
[RETRY, CANCEL]
|
63
|
+
end
|
64
|
+
|
65
|
+
# All defined actions
|
66
|
+
#
|
67
|
+
# @return [Array<Symbol>] All action constants
|
68
|
+
def self.all
|
69
|
+
[INDEX, SHOW, CREATE, UPDATE, DESTROY, RETRY, CANCEL]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|