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,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# typed: false
|
4
|
+
|
5
|
+
module Tasker
|
6
|
+
# Abstract base class for all Tasker models that provides optional secondary database support.
|
7
|
+
#
|
8
|
+
# This class follows Rails multi-database conventions using the `connects_to` API.
|
9
|
+
# When secondary database is enabled, it connects to a database named 'tasker' in database.yml.
|
10
|
+
#
|
11
|
+
# @example Basic usage with shared database (default)
|
12
|
+
# Tasker.configuration do |config|
|
13
|
+
# config.database.enable_secondary_database = false
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# @example Using a dedicated Tasker database
|
17
|
+
# Tasker.configuration do |config|
|
18
|
+
# config.database.enable_secondary_database = true
|
19
|
+
# config.database.name = :tasker
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# # In database.yml:
|
23
|
+
# production:
|
24
|
+
# primary:
|
25
|
+
# database: my_primary_database
|
26
|
+
# adapter: postgresql
|
27
|
+
# tasker:
|
28
|
+
# database: my_tasker_database
|
29
|
+
# adapter: postgresql
|
30
|
+
#
|
31
|
+
class ApplicationRecord < ActiveRecord::Base
|
32
|
+
self.abstract_class = true
|
33
|
+
|
34
|
+
# Configure database connections based on Tasker configuration
|
35
|
+
# This follows Rails multi-database conventions but only when database is actually available
|
36
|
+
def self.configure_database_connections
|
37
|
+
# Ensure Tasker configuration is available - fail fast if not
|
38
|
+
unless defined?(Tasker.configuration)
|
39
|
+
error_message = 'Tasker.configuration is not available. This indicates a Rails initialization order issue. ' \
|
40
|
+
'Ensure Tasker is properly initialized before models are loaded.'
|
41
|
+
raise StandardError, error_message
|
42
|
+
end
|
43
|
+
|
44
|
+
config = Tasker.configuration.database
|
45
|
+
if config.enable_secondary_database && config.name.present?
|
46
|
+
# Check if the database configuration actually exists before calling connects_to
|
47
|
+
if database_configuration_exists?(config.name)
|
48
|
+
# Use connects_to for proper Rails multi-database support
|
49
|
+
connects_to database: { writing: config.name.to_sym, reading: config.name.to_sym }
|
50
|
+
else
|
51
|
+
warning_message = "Tasker secondary database '#{config.name}' is enabled but not found in database.yml. " \
|
52
|
+
'Using default database.'
|
53
|
+
Rails.logger.warn warning_message
|
54
|
+
end
|
55
|
+
end
|
56
|
+
rescue ActiveRecord::DatabaseConfigurations::InvalidConfigurationError => e
|
57
|
+
# Log database configuration errors but don't fail startup - this allows for
|
58
|
+
# environments where the secondary database might not be available
|
59
|
+
Rails.logger.warn "Tasker database configuration error: #{e.message}"
|
60
|
+
end
|
61
|
+
|
62
|
+
# Check if a database configuration exists in the current environment
|
63
|
+
def self.database_configuration_exists?(db_name)
|
64
|
+
Rails.application.config.database_configuration.key?(db_name.to_s)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Call the connection configuration method
|
68
|
+
configure_database_connections
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# == Schema Information
|
5
|
+
#
|
6
|
+
# Table name: dependent_systems
|
7
|
+
#
|
8
|
+
# description :string(255)
|
9
|
+
# name :string(64) not null
|
10
|
+
# created_at :datetime not null
|
11
|
+
# updated_at :datetime not null
|
12
|
+
# dependent_system_id :integer not null, primary key
|
13
|
+
#
|
14
|
+
# Indexes
|
15
|
+
#
|
16
|
+
# dependent_systems_name_index (name)
|
17
|
+
# dependent_systems_name_unique (name) UNIQUE
|
18
|
+
#
|
19
|
+
module Tasker
|
20
|
+
class DependentSystem < ApplicationRecord
|
21
|
+
self.primary_key = :dependent_system_id
|
22
|
+
has_many :dependent_system_object_maps, dependent: :destroy
|
23
|
+
has_many :named_steps, dependent: :destroy
|
24
|
+
validates :name, presence: true, uniqueness: true
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# == Schema Information
|
5
|
+
#
|
6
|
+
# Table name: dependent_system_object_maps
|
7
|
+
#
|
8
|
+
# remote_id_one :string(128) not null
|
9
|
+
# remote_id_two :string(128) not null
|
10
|
+
# created_at :datetime not null
|
11
|
+
# updated_at :datetime not null
|
12
|
+
# dependent_system_object_map_id :bigint not null, primary key
|
13
|
+
# dependent_system_one_id :integer not null
|
14
|
+
# dependent_system_two_id :integer not null
|
15
|
+
#
|
16
|
+
# Indexes
|
17
|
+
#
|
18
|
+
# dependent_system_object_maps_dependent_system_one_id_dependent_ (dependent_system_one_id,dependent_system_two_id,remote_id_one,remote_id_two) UNIQUE
|
19
|
+
# dependent_system_object_maps_dependent_system_one_id_index (dependent_system_one_id)
|
20
|
+
# dependent_system_object_maps_dependent_system_two_id_index (dependent_system_two_id)
|
21
|
+
# dependent_system_object_maps_remote_id_one_index (remote_id_one)
|
22
|
+
# dependent_system_object_maps_remote_id_two_index (remote_id_two)
|
23
|
+
#
|
24
|
+
# Foreign Keys
|
25
|
+
#
|
26
|
+
# dependent_system_object_maps_dependent_system_one_id_foreign (dependent_system_one_id => dependent_systems.dependent_system_id)
|
27
|
+
# dependent_system_object_maps_dependent_system_two_id_foreign (dependent_system_two_id => dependent_systems.dependent_system_id)
|
28
|
+
#
|
29
|
+
|
30
|
+
module Tasker
|
31
|
+
class DependentSystemObjectMap < ApplicationRecord
|
32
|
+
self.primary_key = :dependent_system_object_map_id
|
33
|
+
belongs_to :dependent_system_one, class_name: 'Tasker::DependentSystem'
|
34
|
+
belongs_to :dependent_system_two, class_name: 'Tasker::DependentSystem'
|
35
|
+
validates :remote_id_one, presence: true
|
36
|
+
validates :remote_id_two, presence: true
|
37
|
+
|
38
|
+
def self.find_or_create(system_one_name, system_one_id, system_two_name, system_two_id)
|
39
|
+
system_one = Tasker::DependentSystem.find_or_create_by!(name: system_one_name)
|
40
|
+
system_two = Tasker::DependentSystem.find_or_create_by!(name: system_two_name)
|
41
|
+
# these could be in either order
|
42
|
+
inst = where(
|
43
|
+
remote_id_one: system_one_id,
|
44
|
+
remote_id_two: system_two_id,
|
45
|
+
dependent_system_one_id: system_one.dependent_system_id,
|
46
|
+
dependent_system_two_id: system_two.dependent_system_id
|
47
|
+
).or(
|
48
|
+
where(
|
49
|
+
remote_id_one: system_two_id,
|
50
|
+
remote_id_two: system_one_id,
|
51
|
+
dependent_system_one_id: system_two.dependent_system_id,
|
52
|
+
dependent_system_two_id: system_one.dependent_system_id
|
53
|
+
)
|
54
|
+
).first
|
55
|
+
inst ||= create(
|
56
|
+
remote_id_one: system_one_id,
|
57
|
+
remote_id_two: system_two_id,
|
58
|
+
dependent_system_one: system_one,
|
59
|
+
dependent_system_two: system_two
|
60
|
+
)
|
61
|
+
inst
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tasker
|
4
|
+
module Diagram
|
5
|
+
# Represents an edge (connection) between nodes in a flowchart diagram
|
6
|
+
class Edge
|
7
|
+
# @return [String] The ID of the source node
|
8
|
+
attr_accessor :source_id
|
9
|
+
|
10
|
+
# @return [String] The ID of the target node
|
11
|
+
attr_accessor :target_id
|
12
|
+
|
13
|
+
# @return [String] The label to display on the edge
|
14
|
+
attr_accessor :label
|
15
|
+
|
16
|
+
# @return [String] The type of edge (e.g., 'solid', 'dashed')
|
17
|
+
attr_accessor :type
|
18
|
+
|
19
|
+
# @return [String] Direction of the arrow (e.g., 'forward', 'back', 'both', 'none')
|
20
|
+
attr_accessor :direction
|
21
|
+
|
22
|
+
# @return [Hash] Additional attributes for the edge
|
23
|
+
attr_accessor :attributes
|
24
|
+
|
25
|
+
# Define constants for style mappings
|
26
|
+
EDGE_STYLES = {
|
27
|
+
'dashed' => '--',
|
28
|
+
'thick' => '==',
|
29
|
+
'dotted' => '-.-',
|
30
|
+
'solid' => '--' # Default
|
31
|
+
}.freeze
|
32
|
+
|
33
|
+
ARROW_STYLES = {
|
34
|
+
'back' => '<',
|
35
|
+
'both' => '<>',
|
36
|
+
'none' => '',
|
37
|
+
'forward' => '>' # Default
|
38
|
+
}.freeze
|
39
|
+
|
40
|
+
# Creates a new diagram edge
|
41
|
+
#
|
42
|
+
# @param source_id [String] The ID of the source node
|
43
|
+
# @param target_id [String] The ID of the target node
|
44
|
+
# @param label [String] The label to display on the edge
|
45
|
+
# @param type [String] The type of edge (default: 'solid')
|
46
|
+
# @param direction [String] Direction of the arrow (default: 'forward')
|
47
|
+
# @param attributes [Hash] Additional attributes for the edge
|
48
|
+
# @return [Edge] A new diagram edge
|
49
|
+
def initialize(source_id:, target_id:, label: '', type: 'solid', direction: 'forward', attributes: {})
|
50
|
+
@source_id = source_id
|
51
|
+
@target_id = target_id
|
52
|
+
@label = label
|
53
|
+
@type = type
|
54
|
+
@direction = direction
|
55
|
+
@attributes = attributes
|
56
|
+
end
|
57
|
+
|
58
|
+
# Convert the edge to a hash representation
|
59
|
+
#
|
60
|
+
# @return [Hash] Hash representation of the edge
|
61
|
+
def to_h
|
62
|
+
{
|
63
|
+
source_id: source_id,
|
64
|
+
target_id: target_id,
|
65
|
+
label: label,
|
66
|
+
type: type,
|
67
|
+
direction: direction,
|
68
|
+
attributes: attributes
|
69
|
+
}.compact
|
70
|
+
end
|
71
|
+
|
72
|
+
# Convert the edge to a JSON string
|
73
|
+
#
|
74
|
+
# @return [String] JSON representation of the edge
|
75
|
+
def to_json(*)
|
76
|
+
to_h.to_json(*)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Generate Mermaid diagram syntax for this edge
|
80
|
+
#
|
81
|
+
# @return [String] Mermaid syntax for the edge
|
82
|
+
def to_mermaid
|
83
|
+
# For labeled edges, use the |label| syntax instead of adding a separate text label
|
84
|
+
if label&.present? # rubocop:disable Lint/RedundantSafeNavigation
|
85
|
+
"#{source_id} -->|\"#{escape_mermaid_text(label)}\"| #{target_id}"
|
86
|
+
else
|
87
|
+
"#{source_id} --> #{target_id}"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
# Escape special characters in Mermaid text
|
94
|
+
#
|
95
|
+
# @param text [String] The text to escape
|
96
|
+
# @return [String] Escaped text safe for Mermaid diagrams
|
97
|
+
def escape_mermaid_text(text)
|
98
|
+
# Handle nil values
|
99
|
+
return '' if text.nil?
|
100
|
+
|
101
|
+
# Replace instances of " with ' to avoid breaking the Mermaid syntax
|
102
|
+
text.to_s.tr('"', "'")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tasker
|
4
|
+
module Diagram
|
5
|
+
# Represents a flowchart diagram with nodes and edges
|
6
|
+
class Flowchart
|
7
|
+
# @return [Array<Tasker::Diagram::Node>] The nodes in the flowchart
|
8
|
+
attr_accessor :nodes
|
9
|
+
|
10
|
+
# @return [Array<Tasker::Diagram::Edge>] The edges in the flowchart
|
11
|
+
attr_accessor :edges
|
12
|
+
|
13
|
+
# @return [String] The direction of the flowchart (TD: top-down, LR: left-right, etc.)
|
14
|
+
attr_accessor :direction
|
15
|
+
|
16
|
+
# @return [String] The title of the flowchart
|
17
|
+
attr_accessor :title
|
18
|
+
|
19
|
+
# @return [Hash] Additional attributes for the flowchart
|
20
|
+
attr_accessor :attributes
|
21
|
+
|
22
|
+
# Creates a new flowchart diagram
|
23
|
+
#
|
24
|
+
# @param nodes [Array<Tasker::Diagram::Node>] The nodes in the flowchart
|
25
|
+
# @param edges [Array<Tasker::Diagram::Edge>] The edges in the flowchart
|
26
|
+
# @param direction [String] The direction of the flowchart (default: 'TD')
|
27
|
+
# @param title [String, nil] The title of the flowchart
|
28
|
+
# @param attributes [Hash] Additional attributes for the flowchart
|
29
|
+
# @return [Flowchart] A new flowchart diagram
|
30
|
+
def initialize(nodes: [], edges: [], direction: 'TD', title: nil, attributes: {})
|
31
|
+
@nodes = nodes
|
32
|
+
@edges = edges
|
33
|
+
@direction = direction
|
34
|
+
@title = title
|
35
|
+
@attributes = attributes
|
36
|
+
end
|
37
|
+
|
38
|
+
# Add a node to the flowchart
|
39
|
+
#
|
40
|
+
# @param node [Tasker::Diagram::Node] The node to add
|
41
|
+
# @return [Tasker::Diagram::Node] The added node
|
42
|
+
def add_node(node)
|
43
|
+
@nodes << node
|
44
|
+
node
|
45
|
+
end
|
46
|
+
|
47
|
+
# Add an edge to the flowchart
|
48
|
+
#
|
49
|
+
# @param edge [Tasker::Diagram::Edge] The edge to add
|
50
|
+
# @return [Tasker::Diagram::Edge] The added edge
|
51
|
+
def add_edge(edge)
|
52
|
+
@edges << edge
|
53
|
+
edge
|
54
|
+
end
|
55
|
+
|
56
|
+
# Find a node by its ID
|
57
|
+
#
|
58
|
+
# @param id [String] The ID of the node to find
|
59
|
+
# @return [Tasker::Diagram::Node, nil] The node with the given ID, or nil if not found
|
60
|
+
def find_node(id)
|
61
|
+
@nodes.find { |node| node.id == id }
|
62
|
+
end
|
63
|
+
|
64
|
+
# Find all edges connected to a node
|
65
|
+
#
|
66
|
+
# @param node_id [String] The ID of the node
|
67
|
+
# @param direction [Symbol] :outgoing, :incoming, or :both (default: :both)
|
68
|
+
# @return [Array<Tasker::Diagram::Edge>] The edges connected to the node
|
69
|
+
def find_edges_for_node(node_id, direction = :both)
|
70
|
+
case direction
|
71
|
+
when :outgoing
|
72
|
+
@edges.select { |edge| edge.source_id == node_id }
|
73
|
+
when :incoming
|
74
|
+
@edges.select { |edge| edge.target_id == node_id }
|
75
|
+
else
|
76
|
+
@edges.select { |edge| edge.source_id == node_id || edge.target_id == node_id }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Convert the flowchart to a hash representation
|
81
|
+
#
|
82
|
+
# @return [Hash] Hash representation of the flowchart
|
83
|
+
def to_h
|
84
|
+
{
|
85
|
+
nodes: nodes.map(&:to_h),
|
86
|
+
edges: edges.map(&:to_h),
|
87
|
+
direction: direction,
|
88
|
+
title: title,
|
89
|
+
attributes: attributes
|
90
|
+
}.compact
|
91
|
+
end
|
92
|
+
|
93
|
+
# Convert the flowchart to a JSON string
|
94
|
+
#
|
95
|
+
# @return [String] JSON representation of the flowchart
|
96
|
+
def to_json(*)
|
97
|
+
to_h.to_json(*)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Generate Mermaid diagram syntax for this flowchart
|
101
|
+
#
|
102
|
+
# @return [String] Mermaid syntax for the flowchart
|
103
|
+
def to_mermaid
|
104
|
+
lines = []
|
105
|
+
|
106
|
+
# Add the flowchart definition
|
107
|
+
lines << "graph #{direction}"
|
108
|
+
|
109
|
+
# Use a subgraph with title if title is present
|
110
|
+
if title
|
111
|
+
lines << "subgraph \"#{title}\""
|
112
|
+
indent = ' '
|
113
|
+
else
|
114
|
+
indent = ''
|
115
|
+
end
|
116
|
+
|
117
|
+
# Add all nodes
|
118
|
+
nodes.each do |node|
|
119
|
+
node.to_mermaid.each do |line|
|
120
|
+
lines << "#{indent}#{line}"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Add all edges
|
125
|
+
edges.each do |edge|
|
126
|
+
lines << "#{indent}#{edge.to_mermaid}"
|
127
|
+
end
|
128
|
+
|
129
|
+
# Close the subgraph if we have a title
|
130
|
+
lines << 'end' if title
|
131
|
+
|
132
|
+
# Join all lines with newlines
|
133
|
+
lines.join("\n")
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tasker
|
4
|
+
module Diagram
|
5
|
+
# Represents a node in a flowchart diagram
|
6
|
+
class Node
|
7
|
+
# @return [String] The unique identifier for this node
|
8
|
+
attr_accessor :id
|
9
|
+
|
10
|
+
# @return [String] The display label for this node
|
11
|
+
attr_accessor :label
|
12
|
+
|
13
|
+
# @return [String] The shape of the node (e.g., 'box', 'circle', 'diamond')
|
14
|
+
attr_accessor :shape
|
15
|
+
|
16
|
+
# @return [String] CSS styling for the node
|
17
|
+
attr_accessor :style
|
18
|
+
|
19
|
+
# @return [String, nil] URL to link to when clicking the node
|
20
|
+
attr_accessor :url
|
21
|
+
|
22
|
+
# @return [Hash] Additional attributes for the node
|
23
|
+
attr_accessor :attributes
|
24
|
+
|
25
|
+
# Creates a new diagram node
|
26
|
+
#
|
27
|
+
# @param id [String] The unique identifier for this node
|
28
|
+
# @param label [String] The display label for this node
|
29
|
+
# @param shape [String] The shape of the node (default: 'box')
|
30
|
+
# @param style [String, nil] CSS styling for the node
|
31
|
+
# @param url [String, nil] URL to link to when clicking the node
|
32
|
+
# @param attributes [Hash] Additional attributes for the node
|
33
|
+
# @return [Node] A new diagram node
|
34
|
+
def initialize(id:, label:, shape: 'box', style: nil, url: nil, attributes: {})
|
35
|
+
@id = id
|
36
|
+
@label = label
|
37
|
+
@shape = shape
|
38
|
+
@style = style
|
39
|
+
@url = url
|
40
|
+
@attributes = attributes
|
41
|
+
end
|
42
|
+
|
43
|
+
# Convert the node to a hash representation
|
44
|
+
#
|
45
|
+
# @return [Hash] Hash representation of the node
|
46
|
+
def to_h
|
47
|
+
{
|
48
|
+
id: id,
|
49
|
+
label: label,
|
50
|
+
shape: shape,
|
51
|
+
style: style,
|
52
|
+
url: url,
|
53
|
+
attributes: attributes
|
54
|
+
}.compact
|
55
|
+
end
|
56
|
+
|
57
|
+
# Convert the node to a JSON string
|
58
|
+
#
|
59
|
+
# @return [String] JSON representation of the node
|
60
|
+
def to_json(*)
|
61
|
+
to_h.to_json(*)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Generate Mermaid diagram syntax for this node
|
65
|
+
#
|
66
|
+
# @return [Array<String>] Array of Mermaid syntax lines for the node
|
67
|
+
def to_mermaid
|
68
|
+
# Use HTML line breaks in the label
|
69
|
+
formatted_label = escape_mermaid_text(label).gsub("\n", '<br/>')
|
70
|
+
|
71
|
+
# Basic node definition
|
72
|
+
node_def = "#{id}[\"#{formatted_label}\"]"
|
73
|
+
|
74
|
+
# Add URL link if present
|
75
|
+
click_def = url ? "click #{id} \"#{escape_mermaid_text(url)}\"" : nil
|
76
|
+
|
77
|
+
# Add style definition if present
|
78
|
+
style_def = style ? "style #{id} #{style}" : nil
|
79
|
+
|
80
|
+
# Return node definition and optional click and style definitions
|
81
|
+
[node_def, click_def, style_def].compact
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
# Escape special characters in Mermaid text
|
87
|
+
#
|
88
|
+
# @param text [String] The text to escape
|
89
|
+
# @return [String] Escaped text safe for Mermaid diagrams
|
90
|
+
def escape_mermaid_text(text)
|
91
|
+
# Handle nil values
|
92
|
+
return '' if text.nil?
|
93
|
+
|
94
|
+
# Replace instances of " with ' to avoid breaking the Mermaid syntax
|
95
|
+
text.to_s.tr('"', "'")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# == Schema Information
|
5
|
+
#
|
6
|
+
# Table name: named_steps
|
7
|
+
#
|
8
|
+
# description :string(255)
|
9
|
+
# name :string(128) not null
|
10
|
+
# created_at :datetime not null
|
11
|
+
# updated_at :datetime not null
|
12
|
+
# dependent_system_id :integer not null
|
13
|
+
# named_step_id :integer not null, primary key
|
14
|
+
#
|
15
|
+
# Indexes
|
16
|
+
#
|
17
|
+
# named_step_by_system_uniq (dependent_system_id,name) UNIQUE
|
18
|
+
# named_steps_dependent_system_id_index (dependent_system_id)
|
19
|
+
# named_steps_name_index (name)
|
20
|
+
#
|
21
|
+
# Foreign Keys
|
22
|
+
#
|
23
|
+
# named_steps_dependent_system_id_foreign (dependent_system_id => dependent_systems.dependent_system_id)
|
24
|
+
#
|
25
|
+
module Tasker
|
26
|
+
class NamedStep < ApplicationRecord
|
27
|
+
self.primary_key = :named_step_id
|
28
|
+
belongs_to :dependent_system
|
29
|
+
has_many :workflow_steps, dependent: :nullify
|
30
|
+
validates :name, presence: true, uniqueness: { scope: :dependent_system_id }
|
31
|
+
|
32
|
+
def self.create_named_steps_from_templates(templates)
|
33
|
+
templates.map do |template|
|
34
|
+
dependent_system = Tasker::DependentSystem.find_or_create_by!(name: template.dependent_system)
|
35
|
+
named_step = NamedStep.find_or_create_by!(name: template.name,
|
36
|
+
dependent_system_id: dependent_system.dependent_system_id)
|
37
|
+
named_step
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# == Schema Information
|
5
|
+
#
|
6
|
+
# Table name: tasker_named_tasks
|
7
|
+
#
|
8
|
+
# description :string(255)
|
9
|
+
# name :string(64) not null
|
10
|
+
# version :string(16) not null
|
11
|
+
# configuration :jsonb
|
12
|
+
# created_at :datetime not null
|
13
|
+
# updated_at :datetime not null
|
14
|
+
# named_task_id :integer not null, primary key
|
15
|
+
# task_namespace_id :integer not null
|
16
|
+
#
|
17
|
+
# Indexes
|
18
|
+
#
|
19
|
+
# named_tasks_name_index (name)
|
20
|
+
# named_tasks_namespace_name_version_unique (task_namespace_id,name,version) UNIQUE
|
21
|
+
# named_tasks_task_namespace_id_index (task_namespace_id)
|
22
|
+
# named_tasks_version_index (version)
|
23
|
+
# named_tasks_configuration_gin_index (configuration) USING gin
|
24
|
+
#
|
25
|
+
# Foreign Keys
|
26
|
+
#
|
27
|
+
# fk_rails_... (task_namespace_id => tasker_task_namespaces.task_namespace_id)
|
28
|
+
#
|
29
|
+
module Tasker
|
30
|
+
class NamedTask < ApplicationRecord
|
31
|
+
self.primary_key = :named_task_id
|
32
|
+
|
33
|
+
belongs_to :task_namespace
|
34
|
+
has_many :tasks, dependent: :nullify
|
35
|
+
|
36
|
+
validates :name, presence: true, length: { maximum: 64 }
|
37
|
+
validates :version, presence: true, format: {
|
38
|
+
with: /\A\d+\.\d+\.\d+\z/,
|
39
|
+
message: 'must be in semver format (e.g., 1.0.0)'
|
40
|
+
}, length: { maximum: 16 }
|
41
|
+
validates :task_namespace_id, uniqueness: { scope: %i[name version] }
|
42
|
+
|
43
|
+
# Default version for new tasks
|
44
|
+
DEFAULT_VERSION = '0.1.0'
|
45
|
+
|
46
|
+
# Default namespace name
|
47
|
+
DEFAULT_NAMESPACE = 'default'
|
48
|
+
|
49
|
+
# Find or create with namespace and version support
|
50
|
+
def self.find_or_create_by_full_name!(name:, namespace_name: DEFAULT_NAMESPACE, version: DEFAULT_VERSION)
|
51
|
+
namespace = TaskNamespace.find_or_create_by!(name: namespace_name)
|
52
|
+
find_or_create_by!(
|
53
|
+
task_namespace: namespace,
|
54
|
+
name: name,
|
55
|
+
version: version
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Full qualified name: namespace.name@version
|
60
|
+
def full_name
|
61
|
+
"#{task_namespace.name}.#{name}@#{version}"
|
62
|
+
end
|
63
|
+
|
64
|
+
# Short name without version: namespace.name
|
65
|
+
def qualified_name
|
66
|
+
"#{task_namespace.name}.#{name}"
|
67
|
+
end
|
68
|
+
|
69
|
+
# Configuration accessor with defaults
|
70
|
+
def config
|
71
|
+
@config ||= (configuration || {}).with_indifferent_access
|
72
|
+
end
|
73
|
+
|
74
|
+
# Get concurrency setting from configuration
|
75
|
+
def concurrent?
|
76
|
+
config.fetch('concurrent', true)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Update configuration
|
80
|
+
def update_config!(new_config)
|
81
|
+
self.configuration = (config || {}).deep_merge(new_config)
|
82
|
+
save!
|
83
|
+
@config = nil # Clear memoized config
|
84
|
+
end
|
85
|
+
|
86
|
+
# Check if this uses the default namespace
|
87
|
+
def default_namespace?
|
88
|
+
task_namespace.default?
|
89
|
+
end
|
90
|
+
|
91
|
+
def namespace_name
|
92
|
+
task_namespace.name
|
93
|
+
end
|
94
|
+
|
95
|
+
# Scope methods for common queries
|
96
|
+
scope :in_namespace, lambda { |namespace|
|
97
|
+
joins(:task_namespace).where(task_namespace: { name: namespace })
|
98
|
+
}
|
99
|
+
|
100
|
+
scope :with_version, ->(version) { where(version: version) }
|
101
|
+
|
102
|
+
scope :latest_versions, lambda {
|
103
|
+
select('DISTINCT ON (task_namespace_id, name) *')
|
104
|
+
.order(:task_namespace_id, :name, version: :desc)
|
105
|
+
}
|
106
|
+
|
107
|
+
# Find latest version of a named task in a namespace
|
108
|
+
def self.find_latest_version(namespace_name, task_name)
|
109
|
+
in_namespace(namespace_name)
|
110
|
+
.where(name: task_name)
|
111
|
+
.order(version: :desc)
|
112
|
+
.first
|
113
|
+
end
|
114
|
+
|
115
|
+
# Check if a specific version exists
|
116
|
+
def self.version_exists?(namespace_name, task_name, version)
|
117
|
+
in_namespace(namespace_name)
|
118
|
+
.exists?(name: task_name, version: version)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|