tasker-engine 0.1.0 → 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.
Potentially problematic release.
This version of tasker-engine might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +12 -9
- data/app/controllers/tasker/analytics_controller.rb +2 -2
- data/app/controllers/tasker/graphql_controller.rb +3 -3
- data/app/controllers/tasker/health_controller.rb +1 -1
- data/app/controllers/tasker/metrics_controller.rb +3 -3
- data/app/controllers/tasker/task_diagrams_controller.rb +30 -0
- data/app/jobs/tasker/metrics_export_job.rb +1 -1
- data/app/models/tasker/application_record.rb +5 -5
- 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/task.rb +11 -1
- data/app/models/tasker/task_diagram.rb +332 -0
- data/app/models/tasker/workflow_step_edge.rb +4 -5
- data/app/views/tasker/task/_diagram.html.erb +32 -0
- data/config/routes.rb +3 -3
- data/db/init/schema.sql +23 -0
- data/docs/APPLICATION_GENERATOR.md +1 -1
- data/docs/AUTH.md +51 -12
- data/docs/DEVELOPER_GUIDE.md +9 -8
- data/docs/EXECUTION_CONFIGURATION.md +1 -1
- data/docs/HEALTH.md +3 -3
- data/docs/METRICS.md +4 -4
- data/docs/OPTIMIZATION_PLAN.md +3 -3
- data/docs/OVERVIEW.md +4 -0
- data/docs/QUICK_START.md +1 -1
- data/docs/REST_API.md +1 -1
- data/docs/TASK_DIAGRAM.md +252 -0
- data/docs/TELEMETRY.md +5 -5
- data/docs/TROUBLESHOOTING.md +3 -3
- data/docs/TaskHandlerGenerator.html +55 -55
- data/docs/Tasker/Analysis/RuntimeGraphAnalyzer.html +1 -1
- data/docs/Tasker/Analysis/TemplateGraphAnalyzer.html +1 -1
- data/docs/Tasker/Analysis.html +1 -1
- data/docs/Tasker/AnalyticsController.html +1 -1
- data/docs/Tasker/AnalyticsService/BottleneckAnalytics.html +1 -1
- data/docs/Tasker/AnalyticsService/PerformanceAnalytics.html +1 -1
- data/docs/Tasker/AnalyticsService.html +1 -1
- data/docs/Tasker/AnnotationType.html +1 -1
- data/docs/Tasker/AnnotationTypeSerializer.html +1 -1
- data/docs/Tasker/ApplicationController.html +2 -2
- data/docs/Tasker/ApplicationJob.html +1 -1
- data/docs/Tasker/ApplicationRecord.html +6 -6
- data/docs/Tasker/Authentication/AuthenticationError.html +1 -1
- data/docs/Tasker/Authentication/ConfigurationError.html +1 -1
- data/docs/Tasker/Authentication/Coordinator.html +1 -1
- data/docs/Tasker/Authentication/Interface.html +1 -1
- data/docs/Tasker/Authentication/InterfaceError.html +1 -1
- data/docs/Tasker/Authentication/NoneAuthenticator.html +1 -1
- data/docs/Tasker/Authentication.html +1 -1
- data/docs/Tasker/Authorization/AuthorizationError.html +1 -1
- data/docs/Tasker/Authorization/BaseCoordinator.html +2 -2
- data/docs/Tasker/Authorization/ConfigurationError.html +1 -1
- data/docs/Tasker/Authorization/ResourceConstants/ACTIONS.html +10 -10
- data/docs/Tasker/Authorization/ResourceConstants/RESOURCES.html +13 -8
- data/docs/Tasker/Authorization/ResourceConstants.html +1 -1
- data/docs/Tasker/Authorization/ResourceRegistry.html +40 -33
- data/docs/Tasker/Authorization/UnauthorizedError.html +1 -1
- data/docs/Tasker/Authorization.html +2 -2
- data/docs/Tasker/CacheCapabilities.html +1 -1
- data/docs/Tasker/CacheStrategy.html +1 -1
- data/docs/Tasker/Concerns/Authenticatable.html +1 -1
- data/docs/Tasker/Concerns/Authorizable/AdminStatusChecker.html +1 -1
- data/docs/Tasker/Concerns/Authorizable.html +1 -1
- data/docs/Tasker/Concerns/ControllerAuthorizable.html +1 -1
- data/docs/Tasker/Concerns/EventPublisher.html +1 -1
- data/docs/Tasker/Concerns/IdempotentStateTransitions.html +1 -1
- data/docs/Tasker/Concerns/StateMachineBase/ClassMethods.html +1 -1
- data/docs/Tasker/Concerns/StateMachineBase/StateMachineBase/ClassMethods.html +1 -1
- data/docs/Tasker/Concerns/StateMachineBase/StateMachineBase.html +1 -1
- data/docs/Tasker/Concerns/StateMachineBase.html +1 -1
- data/docs/Tasker/Concerns/StructuredLogging.html +1 -1
- data/docs/Tasker/Concerns.html +1 -1
- data/docs/Tasker/Configuration/ConfigurationProxy.html +1 -1
- data/docs/Tasker/Configuration/TelemetryConfigurationProxy.html +1 -1
- data/docs/Tasker/Configuration.html +1 -1
- data/docs/Tasker/ConfigurationError.html +1 -1
- data/docs/Tasker/ConfiguredTask.html +2 -2
- data/docs/Tasker/Constants/EventDefinitions.html +1 -1
- data/docs/Tasker/Constants/ObservabilityEvents/Step.html +1 -1
- data/docs/Tasker/Constants/ObservabilityEvents/Task.html +1 -1
- data/docs/Tasker/Constants/ObservabilityEvents.html +1 -1
- data/docs/Tasker/Constants/RegistryEvents.html +1 -1
- data/docs/Tasker/Constants/StepEvents.html +1 -1
- data/docs/Tasker/Constants/TaskEvents.html +1 -1
- data/docs/Tasker/Constants/TaskExecution/ExecutionStatus.html +1 -1
- data/docs/Tasker/Constants/TaskExecution/HealthStatus.html +1 -1
- data/docs/Tasker/Constants/TaskExecution/RecommendedAction.html +1 -1
- data/docs/Tasker/Constants/TaskExecution.html +1 -1
- data/docs/Tasker/Constants/TaskFinalization/ErrorMessages.html +1 -1
- data/docs/Tasker/Constants/TaskFinalization/PendingReasons.html +1 -1
- data/docs/Tasker/Constants/TaskFinalization/ReenqueueReasons.html +1 -1
- data/docs/Tasker/Constants/TaskFinalization.html +1 -1
- data/docs/Tasker/Constants/TaskStatuses.html +1 -1
- data/docs/Tasker/Constants/TestEvents.html +1 -1
- data/docs/Tasker/Constants/WorkflowEvents.html +1 -1
- data/docs/Tasker/Constants/WorkflowStepStatuses.html +1 -1
- data/docs/Tasker/Constants.html +1 -1
- data/docs/Tasker/DependentSystem.html +1 -1
- data/docs/Tasker/DependentSystemObjectMap.html +1 -1
- data/docs/Tasker/DetectorRegistry.html +1 -1
- data/docs/Tasker/Diagram/Edge.html +1 -1
- data/docs/Tasker/Diagram/Flowchart.html +1 -1
- data/docs/Tasker/Diagram/Node.html +1 -1
- data/docs/Tasker/Diagram.html +1 -1
- data/docs/Tasker/Engine.html +1 -1
- data/docs/Tasker/Error.html +1 -1
- data/docs/Tasker/Events/Catalog/CatalogPrinter.html +1 -1
- data/docs/Tasker/Events/Catalog/CustomEventRegistrar.html +1 -1
- data/docs/Tasker/Events/Catalog/ExamplePayloadGenerator.html +1 -1
- data/docs/Tasker/Events/Catalog.html +1 -1
- data/docs/Tasker/Events/CustomRegistry.html +1 -1
- data/docs/Tasker/Events/DefinitionLoader.html +1 -1
- data/docs/Tasker/Events/EventPayloadBuilder/ErrorInfoExtractor.html +1 -1
- data/docs/Tasker/Events/EventPayloadBuilder/StepPayloadBuilder.html +1 -1
- data/docs/Tasker/Events/EventPayloadBuilder.html +1 -1
- data/docs/Tasker/Events/Publisher.html +1 -1
- data/docs/Tasker/Events/Subscribers/BaseSubscriber/ErrorCategorizer/ErrorTypeClassifier.html +1 -1
- data/docs/Tasker/Events/Subscribers/BaseSubscriber/ErrorCategorizer.html +1 -1
- data/docs/Tasker/Events/Subscribers/BaseSubscriber/MetricTagsExtractor.html +1 -1
- data/docs/Tasker/Events/Subscribers/BaseSubscriber.html +1 -1
- data/docs/Tasker/Events/Subscribers/MetricsSubscriber.html +2 -2
- data/docs/Tasker/Events/Subscribers/TelemetrySubscriber.html +5 -5
- data/docs/Tasker/Events/Subscribers.html +1 -1
- data/docs/Tasker/Events/SubscriptionLoader.html +1 -1
- data/docs/Tasker/Events.html +1 -1
- data/docs/Tasker/EventsGenerator.html +2 -2
- data/docs/Tasker/Functions/FunctionBasedAnalyticsMetrics/AnalyticsMetrics.html +1 -1
- data/docs/Tasker/Functions/FunctionBasedAnalyticsMetrics.html +1 -1
- data/docs/Tasker/Functions/FunctionBasedDependencyLevels.html +1 -1
- data/docs/Tasker/Functions/FunctionBasedSlowestSteps/SlowestStep.html +1 -1
- data/docs/Tasker/Functions/FunctionBasedSlowestSteps.html +1 -1
- data/docs/Tasker/Functions/FunctionBasedSlowestTasks/SlowestTask.html +1 -1
- data/docs/Tasker/Functions/FunctionBasedSlowestTasks.html +1 -1
- data/docs/Tasker/Functions/FunctionBasedStepReadinessStatus.html +1 -1
- data/docs/Tasker/Functions/FunctionBasedSystemHealthCounts/HealthMetrics.html +1 -1
- data/docs/Tasker/Functions/FunctionBasedSystemHealthCounts.html +1 -1
- data/docs/Tasker/Functions/FunctionBasedTaskExecutionContext.html +1 -1
- data/docs/Tasker/Functions/FunctionWrapper.html +1 -1
- data/docs/Tasker/Functions.html +1 -1
- data/docs/Tasker/Generators/AuthenticatorGenerator/UsageInstructionsFormatter.html +1 -1
- data/docs/Tasker/Generators/AuthenticatorGenerator.html +1 -1
- data/docs/Tasker/Generators/AuthorizationCoordinatorGenerator.html +1 -1
- data/docs/Tasker/Generators/SubscriberGenerator.html +1 -1
- data/docs/Tasker/Generators/TaskHandlerGenerator.html +4 -4
- data/docs/Tasker/Generators.html +1 -1
- data/docs/Tasker/GraphQLTypes/AnnotationType.html +1 -1
- data/docs/Tasker/GraphQLTypes/BaseArgument.html +1 -1
- data/docs/Tasker/GraphQLTypes/BaseConnection.html +1 -1
- data/docs/Tasker/GraphQLTypes/BaseEdge.html +1 -1
- data/docs/Tasker/GraphQLTypes/BaseEnum.html +1 -1
- data/docs/Tasker/GraphQLTypes/BaseField.html +1 -1
- data/docs/Tasker/GraphQLTypes/BaseInputObject.html +1 -1
- data/docs/Tasker/GraphQLTypes/BaseInterface.html +1 -1
- data/docs/Tasker/GraphQLTypes/BaseObject.html +1 -1
- data/docs/Tasker/GraphQLTypes/BaseScalar.html +1 -1
- data/docs/Tasker/GraphQLTypes/BaseUnion.html +1 -1
- data/docs/Tasker/GraphQLTypes/DependentSystemObjectMapType.html +1 -1
- data/docs/Tasker/GraphQLTypes/DependentSystemType.html +1 -1
- data/docs/Tasker/GraphQLTypes/MutationType.html +1 -1
- data/docs/Tasker/GraphQLTypes/NamedStepType.html +1 -1
- data/docs/Tasker/GraphQLTypes/NamedTaskType.html +1 -1
- data/docs/Tasker/GraphQLTypes/NamedTasksNamedStepType.html +1 -1
- data/docs/Tasker/GraphQLTypes/NodeType.html +1 -1
- data/docs/Tasker/GraphQLTypes/QueryType.html +1 -1
- data/docs/Tasker/GraphQLTypes/TaskAnnotationType.html +1 -1
- data/docs/Tasker/GraphQLTypes/TaskInterface.html +1 -1
- data/docs/Tasker/GraphQLTypes/TaskType.html +1 -1
- data/docs/Tasker/GraphQLTypes/WorkflowStepType.html +1 -1
- data/docs/Tasker/GraphQLTypes.html +1 -1
- data/docs/Tasker/GraphqlController.html +1 -1
- data/docs/Tasker/HandlerFactory.html +44 -54
- data/docs/Tasker/HandlerSerializer.html +1 -1
- data/docs/Tasker/HandlersController.html +1 -1
- data/docs/Tasker/HashIdentityStrategy.html +1 -1
- data/docs/Tasker/Health/ReadinessChecker.html +2 -2
- data/docs/Tasker/Health/StatusChecker.html +2 -2
- data/docs/Tasker/Health.html +1 -1
- data/docs/Tasker/HealthController.html +1 -1
- data/docs/Tasker/IdentityStrategy.html +1 -1
- data/docs/Tasker/InvalidTaskHandlerConfig.html +1 -1
- data/docs/Tasker/Logging/CorrelationIdGenerator.html +2 -2
- data/docs/Tasker/Logging.html +1 -1
- data/docs/Tasker/MetricsController.html +1 -1
- data/docs/Tasker/MetricsExportJob.html +1 -1
- data/docs/Tasker/Mutations/BaseMutation.html +1 -1
- data/docs/Tasker/Mutations/CancelStep.html +1 -1
- data/docs/Tasker/Mutations/CancelTask.html +1 -1
- data/docs/Tasker/Mutations/CreateTask.html +1 -1
- data/docs/Tasker/Mutations/UpdateStep.html +1 -1
- data/docs/Tasker/Mutations/UpdateTask.html +1 -1
- data/docs/Tasker/Mutations.html +1 -1
- data/docs/Tasker/NamedStep.html +1 -1
- data/docs/Tasker/NamedTask.html +1 -1
- data/docs/Tasker/NamedTasksNamedStep.html +1 -1
- data/docs/Tasker/Orchestration/BackoffCalculator.html +1 -1
- data/docs/Tasker/Orchestration/ConnectionBuilder/ConfigValidator.html +1 -1
- data/docs/Tasker/Orchestration/ConnectionBuilder.html +2 -2
- data/docs/Tasker/Orchestration/ConnectionPoolIntelligence.html +3 -3
- data/docs/Tasker/Orchestration/Coordinator.html +1 -1
- data/docs/Tasker/Orchestration/FutureStateAnalyzer.html +1 -1
- data/docs/Tasker/Orchestration/PluginIntegration.html +1 -1
- data/docs/Tasker/Orchestration/ResponseProcessor.html +1 -1
- data/docs/Tasker/Orchestration/RetryHeaderParser.html +1 -1
- data/docs/Tasker/Orchestration/StepExecutor.html +4 -4
- data/docs/Tasker/Orchestration/StepSequenceFactory.html +1 -1
- data/docs/Tasker/Orchestration/TaskFinalizer/BlockageChecker.html +1 -1
- data/docs/Tasker/Orchestration/TaskFinalizer/ContextManager.html +1 -1
- data/docs/Tasker/Orchestration/TaskFinalizer/DelayCalculator.html +2 -2
- data/docs/Tasker/Orchestration/TaskFinalizer/FinalizationDecisionMaker.html +1 -1
- data/docs/Tasker/Orchestration/TaskFinalizer/FinalizationProcessor.html +1 -1
- data/docs/Tasker/Orchestration/TaskFinalizer/ReasonDeterminer.html +1 -1
- data/docs/Tasker/Orchestration/TaskFinalizer/ReenqueueManager.html +1 -1
- data/docs/Tasker/Orchestration/TaskFinalizer/UnclearStateHandler.html +1 -1
- data/docs/Tasker/Orchestration/TaskFinalizer.html +1 -1
- data/docs/Tasker/Orchestration/TaskInitializer.html +1 -1
- data/docs/Tasker/Orchestration/TaskReenqueuer.html +1 -1
- data/docs/Tasker/Orchestration/ViableStepDiscovery.html +1 -1
- data/docs/Tasker/Orchestration/WorkflowCoordinator.html +1 -1
- data/docs/Tasker/Orchestration.html +1 -1
- data/docs/Tasker/PageSort/PageSortParamsBuilder.html +1 -1
- data/docs/Tasker/PageSort.html +1 -1
- data/docs/Tasker/PermanentError.html +1 -1
- data/docs/Tasker/ProceduralError.html +1 -1
- data/docs/Tasker/Queries/AllAnnotationTypes.html +1 -1
- data/docs/Tasker/Queries/AllTasks.html +1 -1
- data/docs/Tasker/Queries/BaseQuery.html +1 -1
- data/docs/Tasker/Queries/Helpers.html +1 -1
- data/docs/Tasker/Queries/OneStep.html +1 -1
- data/docs/Tasker/Queries/OneTask.html +1 -1
- data/docs/Tasker/Queries/TasksByAnnotation.html +1 -1
- data/docs/Tasker/Queries/TasksByStatus.html +1 -1
- data/docs/Tasker/Queries.html +1 -1
- data/docs/Tasker/Railtie.html +1 -1
- data/docs/Tasker/Registry/BaseRegistry.html +2 -2
- data/docs/Tasker/Registry/EventPublisher.html +1 -1
- data/docs/Tasker/Registry/InterfaceValidator.html +1 -1
- data/docs/Tasker/Registry/RegistrationError.html +1 -1
- data/docs/Tasker/Registry/RegistryError.html +1 -1
- data/docs/Tasker/Registry/StatisticsCollector.html +1 -1
- data/docs/Tasker/Registry/SubscriberRegistry.html +1 -1
- data/docs/Tasker/Registry/ValidationError.html +1 -1
- data/docs/Tasker/Registry.html +1 -1
- data/docs/Tasker/RetryableError.html +1 -1
- data/docs/Tasker/StateMachine/Compatibility.html +1 -1
- data/docs/Tasker/StateMachine/InvalidStateTransition.html +1 -1
- data/docs/Tasker/StateMachine/StepStateMachine.html +1 -1
- data/docs/Tasker/StateMachine/TaskStateMachine.html +1 -1
- data/docs/Tasker/StateMachine.html +1 -1
- data/docs/Tasker/StepDagRelationship.html +1 -1
- data/docs/Tasker/StepHandler/Api/Config.html +1 -1
- data/docs/Tasker/StepHandler/Api.html +1 -1
- data/docs/Tasker/StepHandler/AutomaticEventPublishing.html +1 -1
- data/docs/Tasker/StepHandler/Base.html +1 -1
- data/docs/Tasker/StepHandler.html +1 -1
- data/docs/Tasker/StepReadinessStatus.html +1 -1
- data/docs/Tasker/Task.html +210 -113
- data/docs/Tasker/TaskAnnotation.html +1 -1
- data/docs/Tasker/TaskAnnotationSerializer.html +1 -1
- data/docs/Tasker/TaskBuilder/StepNameValidator.html +1 -1
- data/docs/Tasker/TaskBuilder/StepTemplateDefiner.html +1 -1
- data/docs/Tasker/TaskBuilder.html +1 -1
- data/docs/Tasker/TaskDiagram/StepToStepEdgeBuilder.html +1 -1
- data/docs/Tasker/TaskDiagram/TaskToRootStepEdgeBuilder.html +1 -1
- data/docs/Tasker/TaskDiagram.html +1 -1
- data/docs/Tasker/TaskDiagramsController.html +1 -1
- data/docs/Tasker/TaskExecutionContext.html +1 -1
- data/docs/Tasker/TaskHandler/ClassMethods/StepTemplateDefiner/ClassBasedEventRegistrar.html +1 -1
- data/docs/Tasker/TaskHandler/ClassMethods/StepTemplateDefiner/YamlEventRegistrar.html +1 -1
- data/docs/Tasker/TaskHandler/ClassMethods/StepTemplateDefiner.html +1 -1
- data/docs/Tasker/TaskHandler/ClassMethods.html +6 -44
- data/docs/Tasker/TaskHandler/InstanceMethods.html +1 -1
- data/docs/Tasker/TaskHandler/StepGroup.html +1 -1
- data/docs/Tasker/TaskHandler.html +1 -1
- data/docs/Tasker/TaskNamespace.html +1 -1
- data/docs/Tasker/TaskRunnerJob.html +1 -1
- data/docs/Tasker/TaskSerializer.html +1 -1
- data/docs/Tasker/TaskTransition.html +1 -1
- data/docs/Tasker/TaskerRailsSchema/InvalidObjectTypeError.html +1 -1
- data/docs/Tasker/TaskerRailsSchema/TypeResolutionError.html +1 -1
- data/docs/Tasker/TaskerRailsSchema/UnknownInterfaceError.html +1 -1
- data/docs/Tasker/TaskerRailsSchema.html +1 -1
- data/docs/Tasker/TasksController.html +1 -1
- data/docs/Tasker/Telemetry/EventMapping.html +1 -1
- data/docs/Tasker/Telemetry/EventRouter.html +1 -1
- data/docs/Tasker/Telemetry/Events/ExportEvents.html +1 -1
- data/docs/Tasker/Telemetry/Events.html +1 -1
- data/docs/Tasker/Telemetry/ExportCoordinator.html +1 -1
- data/docs/Tasker/Telemetry/IntelligentCacheManager.html +2 -2
- data/docs/Tasker/Telemetry/LogBackend.html +1 -1
- data/docs/Tasker/Telemetry/MetricTypes/Counter.html +2 -2
- data/docs/Tasker/Telemetry/MetricTypes/Gauge.html +73 -73
- data/docs/Tasker/Telemetry/MetricTypes/Histogram.html +103 -103
- data/docs/Tasker/Telemetry/MetricTypes.html +1 -1
- data/docs/Tasker/Telemetry/MetricsBackend.html +1 -1
- data/docs/Tasker/Telemetry/MetricsExportService.html +1 -1
- data/docs/Tasker/Telemetry/PluginRegistry.html +1 -1
- data/docs/Tasker/Telemetry/Plugins/BaseExporter.html +1 -1
- data/docs/Tasker/Telemetry/Plugins/CsvExporter.html +1 -1
- data/docs/Tasker/Telemetry/Plugins/JsonExporter.html +1 -1
- data/docs/Tasker/Telemetry/Plugins.html +1 -1
- data/docs/Tasker/Telemetry/PrometheusExporter.html +1 -1
- data/docs/Tasker/Telemetry/TraceBackend.html +1 -1
- data/docs/Tasker/Telemetry.html +1 -1
- data/docs/Tasker/Types/AuthConfig.html +1 -1
- data/docs/Tasker/Types/BackoffConfig.html +1 -1
- data/docs/Tasker/Types/BaseConfig.html +1 -1
- data/docs/Tasker/Types/CacheConfig.html +1 -1
- data/docs/Tasker/Types/DatabaseConfig.html +1 -1
- data/docs/Tasker/Types/DependencyGraph.html +1 -1
- data/docs/Tasker/Types/DependencyGraphConfig.html +1 -1
- data/docs/Tasker/Types/EngineConfig.html +1 -1
- data/docs/Tasker/Types/ExecutionConfig.html +1 -1
- data/docs/Tasker/Types/GraphEdge.html +1 -1
- data/docs/Tasker/Types/GraphMetadata.html +1 -1
- data/docs/Tasker/Types/GraphNode.html +1 -1
- data/docs/Tasker/Types/HealthConfig.html +1 -1
- data/docs/Tasker/Types/StepSequence.html +1 -1
- data/docs/Tasker/Types/StepTemplate.html +1 -1
- data/docs/Tasker/Types/TaskRequest.html +1 -1
- data/docs/Tasker/Types/TelemetryConfig.html +2 -2
- data/docs/Tasker/Types.html +1 -1
- data/docs/Tasker/WorkflowStep/StepFinder.html +1 -1
- data/docs/Tasker/WorkflowStep.html +1 -1
- data/docs/Tasker/WorkflowStepEdge.html +4 -6
- data/docs/Tasker/WorkflowStepSerializer.html +1 -1
- data/docs/Tasker/WorkflowStepTransition/TransitionDescriptionFormatter.html +1 -1
- data/docs/Tasker/WorkflowStepTransition.html +1 -1
- data/docs/Tasker/WorkflowStepsController.html +1 -1
- data/docs/Tasker.html +5 -21
- data/docs/VISION.md +1 -1
- data/docs/_index.html +77 -21
- data/docs/class_list.html +1 -1
- data/docs/file.README.html +14 -10
- data/docs/index.html +14 -10
- data/docs/method_list.html +1433 -1105
- data/docs/top-level-namespace.html +1 -1
- data/lib/generators/tasker/authenticator_generator.rb +5 -5
- data/lib/generators/tasker/authorization_coordinator_generator.rb +1 -1
- data/lib/generators/tasker/events_generator.rb +1 -1
- data/lib/generators/tasker/task_handler_generator.rb +4 -4
- data/lib/generators/tasker/templates/api_token_authenticator.rb.erb +1 -1
- data/lib/generators/tasker/templates/authorization_coordinator.rb.erb +13 -0
- data/lib/generators/tasker/templates/authorization_coordinator_spec.rb.erb +7 -1
- data/lib/generators/tasker/templates/custom_authenticator.rb.erb +1 -1
- data/lib/generators/tasker/templates/devise_authenticator.rb.erb +1 -1
- data/lib/generators/tasker/templates/initialize.rb.erb +1 -1
- data/lib/generators/tasker/templates/jwt_authenticator.rb.erb +1 -1
- data/lib/generators/tasker/templates/omniauth_authenticator.rb.erb +1 -1
- data/lib/generators/tasker/templates/opentelemetry_initializer.rb +4 -4
- data/lib/generators/tasker/templates/task_config.yaml.erb +25 -25
- data/lib/generators/tasker/templates/task_handler.rb.erb +2 -3
- data/lib/generators/tasker/templates/task_handler_spec.rb.erb +43 -49
- data/lib/tasker/analysis/runtime_graph_analyzer.rb +1 -1
- data/lib/tasker/authentication/coordinator.rb +2 -2
- data/lib/tasker/authorization/base_coordinator.rb +1 -1
- data/lib/tasker/authorization/resource_constants.rb +2 -1
- data/lib/tasker/authorization/resource_registry.rb +7 -0
- data/lib/tasker/authorization.rb +1 -1
- data/lib/tasker/concerns/authenticatable.rb +1 -1
- data/lib/tasker/concerns/controller_authorizable.rb +3 -3
- data/lib/tasker/concerns/structured_logging.rb +2 -2
- data/lib/tasker/events/definition_loader.rb +1 -1
- data/lib/tasker/events/subscribers/metrics_subscriber.rb +1 -1
- data/lib/tasker/events/subscribers/telemetry_subscriber.rb +5 -5
- data/lib/tasker/handler_factory.rb +2 -7
- data/lib/tasker/health/readiness_checker.rb +1 -1
- data/lib/tasker/health/status_checker.rb +1 -1
- data/lib/tasker/logging/correlation_id_generator.rb +1 -1
- data/lib/tasker/orchestration/backoff_calculator.rb +1 -1
- data/lib/tasker/orchestration/connection_builder.rb +1 -1
- data/lib/tasker/orchestration/connection_pool_intelligence.rb +3 -3
- data/lib/tasker/orchestration/step_executor.rb +2 -2
- data/lib/tasker/orchestration/task_finalizer.rb +1 -1
- data/lib/tasker/registry/base_registry.rb +1 -1
- data/lib/tasker/task_builder.rb +1 -1
- data/lib/tasker/task_handler/class_methods.rb +1 -4
- data/lib/tasker/telemetry/intelligent_cache_manager.rb +1 -1
- data/lib/tasker/telemetry/metric_types.rb +9 -57
- data/lib/tasker/telemetry/metrics_backend.rb +3 -3
- data/lib/tasker/telemetry/metrics_export_service.rb +1 -1
- data/lib/tasker/telemetry/prometheus_exporter.rb +2 -2
- data/lib/tasker/types/telemetry_config.rb +1 -1
- data/lib/tasker/version.rb +1 -2
- data/lib/tasks/tasker_tasks.rake +4 -85
- metadata +11 -7
- data/db/functions/get_step_readiness_status_single_and_batch_v02.sql +0 -223
- data/db/migrate/20250710110830_step_readiness_sql_functions_v02.rb +0 -39
- data/docs/REVERSIONING.md +0 -404
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'erb'
|
|
4
|
+
require 'pathname'
|
|
5
|
+
|
|
6
|
+
module Tasker
|
|
7
|
+
class TaskDiagram
|
|
8
|
+
# Colors for different step statuses
|
|
9
|
+
STATUS_COLORS = {
|
|
10
|
+
Tasker::Constants::WorkflowStepStatuses::PENDING => 'lightblue',
|
|
11
|
+
Tasker::Constants::WorkflowStepStatuses::IN_PROGRESS => 'lightgreen',
|
|
12
|
+
Tasker::Constants::WorkflowStepStatuses::COMPLETE => 'green',
|
|
13
|
+
Tasker::Constants::WorkflowStepStatuses::ERROR => 'red',
|
|
14
|
+
Tasker::Constants::WorkflowStepStatuses::CANCELLED => 'gray'
|
|
15
|
+
}.freeze
|
|
16
|
+
|
|
17
|
+
# Create a new task diagram
|
|
18
|
+
#
|
|
19
|
+
# @param task [Tasker::Task] The task to create a diagram for
|
|
20
|
+
# @param base_url [String, nil] Optional base URL for REST endpoints
|
|
21
|
+
# @return [TaskDiagram] A new task diagram instance
|
|
22
|
+
def initialize(task, base_url = nil)
|
|
23
|
+
@task = task
|
|
24
|
+
@base_url = base_url
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Generate a Mermaid diagram string for the task
|
|
28
|
+
#
|
|
29
|
+
# @return [String] Mermaid flowchart diagram string
|
|
30
|
+
delegate :to_mermaid, to: :flowchart
|
|
31
|
+
|
|
32
|
+
# Generate a complete HTML document with embedded Mermaid diagram
|
|
33
|
+
#
|
|
34
|
+
# @return [String] HTML document with Mermaid diagram
|
|
35
|
+
def to_html
|
|
36
|
+
# Generate the mermaid diagram
|
|
37
|
+
@diagram = flowchart.to_mermaid
|
|
38
|
+
|
|
39
|
+
# Create binding with relevant variables
|
|
40
|
+
task = @task # Make task available to the template
|
|
41
|
+
diagram = @diagram # Make diagram available to the template
|
|
42
|
+
|
|
43
|
+
# Create a binding with the variables
|
|
44
|
+
b = binding
|
|
45
|
+
|
|
46
|
+
# Get the template path relative to this file
|
|
47
|
+
template_path = views_path.join('_diagram.html.erb')
|
|
48
|
+
|
|
49
|
+
# Load and render the template with ERB
|
|
50
|
+
begin
|
|
51
|
+
template = File.read(template_path)
|
|
52
|
+
ERB.new(template).result(b)
|
|
53
|
+
rescue Errno::ENOENT
|
|
54
|
+
raise TaskDiagramError, "Template file not found: #{template_path}"
|
|
55
|
+
rescue Errno::EACCES
|
|
56
|
+
raise TaskDiagramError, "Permission denied while accessing template file: #{template_path}"
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def to_json(pretty: false)
|
|
61
|
+
flowchart.to_json(pretty: pretty)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def flowchart
|
|
67
|
+
return @flowchart if @flowchart
|
|
68
|
+
|
|
69
|
+
# Preload workflow steps with scenic view relationships for efficiency
|
|
70
|
+
workflow_steps = @task.workflow_steps.includes(:named_step, :step_dag_relationship)
|
|
71
|
+
|
|
72
|
+
# Create a new flowchart
|
|
73
|
+
@flowchart = Tasker::Diagram::Flowchart.new(
|
|
74
|
+
direction: 'TD',
|
|
75
|
+
title: "Task #{@task.task_id}: #{@task.name}"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# Add task info node
|
|
79
|
+
@flowchart.add_node(build_task_node)
|
|
80
|
+
|
|
81
|
+
# Build nodes for all workflow steps
|
|
82
|
+
workflow_steps.each do |step|
|
|
83
|
+
@flowchart.add_node(build_step_node(step))
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Build all edges efficiently using scenic view data
|
|
87
|
+
build_all_step_edges(workflow_steps).each do |edge|
|
|
88
|
+
@flowchart.add_edge(edge)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
@flowchart
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Get the path to the view templates directory
|
|
95
|
+
#
|
|
96
|
+
# @return [Pathname] Path to view templates
|
|
97
|
+
def views_path
|
|
98
|
+
# Get the absolute path of the current file
|
|
99
|
+
current_file = Pathname.new(__FILE__)
|
|
100
|
+
|
|
101
|
+
# Navigate to the views directory relative to this file
|
|
102
|
+
# This file is in app/models/tasker/task_diagram.rb
|
|
103
|
+
# Views are in app/views/tasker/task/
|
|
104
|
+
current_file.dirname.parent.parent.parent.join('app', 'views', 'tasker', 'task')
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Build the task information node
|
|
108
|
+
#
|
|
109
|
+
# @return [Tasker::Diagram::Node] The task node
|
|
110
|
+
def build_task_node
|
|
111
|
+
Tasker::Diagram::Node.new(
|
|
112
|
+
id: "task_#{@task.task_id}",
|
|
113
|
+
label: "Task: #{@task.name}\nID: #{@task.task_id}\nStatus: #{@task.status}"
|
|
114
|
+
)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Build a node for a workflow step
|
|
118
|
+
#
|
|
119
|
+
# @param step [Tasker::WorkflowStep] The workflow step
|
|
120
|
+
# @return [Tasker::Diagram::Node] The step node
|
|
121
|
+
def build_step_node(step)
|
|
122
|
+
node_id = "step_#{step.workflow_step_id}"
|
|
123
|
+
color = STATUS_COLORS[step.status] || 'lightgray'
|
|
124
|
+
|
|
125
|
+
# Create label with step details
|
|
126
|
+
label = build_step_label(step)
|
|
127
|
+
|
|
128
|
+
# Create clickable URL if base_url is provided
|
|
129
|
+
url = @base_url ? "#{@base_url}/tasks/#{@task.task_id}/workflow_steps/#{step.workflow_step_id}" : nil
|
|
130
|
+
|
|
131
|
+
# Create node with styling
|
|
132
|
+
Tasker::Diagram::Node.new(
|
|
133
|
+
id: node_id,
|
|
134
|
+
label: label.join("\n"),
|
|
135
|
+
shape: 'box',
|
|
136
|
+
style: "fill:#{color};",
|
|
137
|
+
url: url
|
|
138
|
+
)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Build the label lines for a step node
|
|
142
|
+
#
|
|
143
|
+
# @param step [Tasker::WorkflowStep] The workflow step
|
|
144
|
+
# @return [Array<String>] Array of label lines
|
|
145
|
+
def build_step_label(step)
|
|
146
|
+
label = [
|
|
147
|
+
"Step: #{step.name}",
|
|
148
|
+
"Status: #{step.status}",
|
|
149
|
+
"Attempts: #{step.attempts || 0}"
|
|
150
|
+
]
|
|
151
|
+
|
|
152
|
+
# Add error info if applicable
|
|
153
|
+
if step.status == Tasker::Constants::WorkflowStepStatuses::ERROR && step.results&.key?('error')
|
|
154
|
+
error_msg = step.results['error'].to_s
|
|
155
|
+
# Truncate long error messages
|
|
156
|
+
error_msg = "#{error_msg[0..27]}..." if error_msg.length > 30
|
|
157
|
+
label << "Error: #{error_msg}"
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
label
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Build an edge between two nodes
|
|
164
|
+
#
|
|
165
|
+
# @param source_id [String] The source node ID
|
|
166
|
+
# @param target_id [String] The target node ID
|
|
167
|
+
# @param label [String] The edge label
|
|
168
|
+
# @return [Tasker::Diagram::Edge] The edge
|
|
169
|
+
def build_edge(source_id, target_id, label = '')
|
|
170
|
+
Tasker::Diagram::Edge.new(
|
|
171
|
+
source_id: source_id,
|
|
172
|
+
target_id: target_id,
|
|
173
|
+
label: label
|
|
174
|
+
)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Build all edges efficiently using scenic view data - eliminates N+1 queries
|
|
178
|
+
#
|
|
179
|
+
# @param workflow_steps [Array<Tasker::WorkflowStep>] All workflow steps for the task
|
|
180
|
+
# @return [Array<Tasker::Diagram::Edge>] All edges for the diagram
|
|
181
|
+
def build_all_step_edges(workflow_steps)
|
|
182
|
+
edges = []
|
|
183
|
+
|
|
184
|
+
# Add edges from task to root steps using dedicated builder
|
|
185
|
+
edges.concat(TaskToRootStepEdgeBuilder.build(@task, workflow_steps))
|
|
186
|
+
|
|
187
|
+
# Add edges between steps using dedicated builder
|
|
188
|
+
edges.concat(StepToStepEdgeBuilder.build(workflow_steps))
|
|
189
|
+
|
|
190
|
+
edges
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Service class to build edges from task to root steps
|
|
194
|
+
# Reduces complexity by organizing edge building logic
|
|
195
|
+
class TaskToRootStepEdgeBuilder
|
|
196
|
+
class << self
|
|
197
|
+
# Build edges from task node to root steps
|
|
198
|
+
#
|
|
199
|
+
# @param task [Tasker::Task] The task
|
|
200
|
+
# @param workflow_steps [Array<Tasker::WorkflowStep>] All workflow steps
|
|
201
|
+
# @return [Array<Tasker::Diagram::Edge>] Task to root step edges
|
|
202
|
+
def build(task, workflow_steps)
|
|
203
|
+
edges = []
|
|
204
|
+
|
|
205
|
+
workflow_steps.each do |step|
|
|
206
|
+
next unless step.step_dag_relationship&.is_root_step
|
|
207
|
+
|
|
208
|
+
edges << build_edge(
|
|
209
|
+
"task_#{task.task_id}",
|
|
210
|
+
"step_#{step.workflow_step_id}"
|
|
211
|
+
)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
edges
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
private
|
|
218
|
+
|
|
219
|
+
# Build an edge between two nodes
|
|
220
|
+
#
|
|
221
|
+
# @param source_id [String] The source node ID
|
|
222
|
+
# @param target_id [String] The target node ID
|
|
223
|
+
# @param label [String] The edge label
|
|
224
|
+
# @return [Tasker::Diagram::Edge] The edge
|
|
225
|
+
def build_edge(source_id, target_id, label = '')
|
|
226
|
+
Tasker::Diagram::Edge.new(
|
|
227
|
+
source_id: source_id,
|
|
228
|
+
target_id: target_id,
|
|
229
|
+
label: label
|
|
230
|
+
)
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Service class to build edges between workflow steps
|
|
236
|
+
# Reduces complexity by organizing edge building logic
|
|
237
|
+
class StepToStepEdgeBuilder
|
|
238
|
+
class << self
|
|
239
|
+
# Build edges between workflow steps
|
|
240
|
+
#
|
|
241
|
+
# @param workflow_steps [Array<Tasker::WorkflowStep>] All workflow steps
|
|
242
|
+
# @return [Array<Tasker::Diagram::Edge>] Step to step edges
|
|
243
|
+
def build(workflow_steps)
|
|
244
|
+
edge_data = collect_edge_data(workflow_steps)
|
|
245
|
+
return [] if edge_data.empty?
|
|
246
|
+
|
|
247
|
+
edge_records = batch_load_edge_records(edge_data)
|
|
248
|
+
build_edges_from_data(edge_data, edge_records)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
private
|
|
252
|
+
|
|
253
|
+
# Collect all edge relationships for efficient batch lookup
|
|
254
|
+
#
|
|
255
|
+
# @param workflow_steps [Array<Tasker::WorkflowStep>] All workflow steps
|
|
256
|
+
# @return [Array<Hash>] Edge data with from_step_id and to_step_id
|
|
257
|
+
def collect_edge_data(workflow_steps)
|
|
258
|
+
edge_data = []
|
|
259
|
+
|
|
260
|
+
workflow_steps.each do |step|
|
|
261
|
+
next unless step.step_dag_relationship
|
|
262
|
+
|
|
263
|
+
child_ids = step.step_dag_relationship.child_step_ids_array
|
|
264
|
+
child_ids.each do |child_id|
|
|
265
|
+
edge_data << {
|
|
266
|
+
from_step_id: step.workflow_step_id,
|
|
267
|
+
to_step_id: child_id
|
|
268
|
+
}
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
edge_data
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
# Batch load all WorkflowStepEdge records for edge labels
|
|
276
|
+
#
|
|
277
|
+
# @param edge_data [Array<Hash>] Edge data to load records for
|
|
278
|
+
# @return [Hash] Hash mapping edge keys to edge records
|
|
279
|
+
def batch_load_edge_records(edge_data)
|
|
280
|
+
edge_records = {}
|
|
281
|
+
|
|
282
|
+
conditions = edge_data.map do |data|
|
|
283
|
+
"(from_step_id = #{data[:from_step_id]} AND to_step_id = #{data[:to_step_id]})"
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
Tasker::WorkflowStepEdge.where(conditions.join(' OR ')).find_each do |edge_record|
|
|
287
|
+
key = "#{edge_record.from_step_id}_#{edge_record.to_step_id}"
|
|
288
|
+
edge_records[key] = edge_record
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
edge_records
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# Build edges using pre-calculated data and records
|
|
295
|
+
#
|
|
296
|
+
# @param edge_data [Array<Hash>] Edge data with IDs
|
|
297
|
+
# @param edge_records [Hash] Loaded edge records for labels
|
|
298
|
+
# @return [Array<Tasker::Diagram::Edge>] Built edges
|
|
299
|
+
def build_edges_from_data(edge_data, edge_records)
|
|
300
|
+
edges = []
|
|
301
|
+
|
|
302
|
+
edge_data.each do |data|
|
|
303
|
+
source_id = "step_#{data[:from_step_id]}"
|
|
304
|
+
target_id = "step_#{data[:to_step_id]}"
|
|
305
|
+
|
|
306
|
+
# Find edge label from batch-loaded records
|
|
307
|
+
key = "#{data[:from_step_id]}_#{data[:to_step_id]}"
|
|
308
|
+
edge_label = edge_records[key]&.name || ''
|
|
309
|
+
|
|
310
|
+
edges << build_edge(source_id, target_id, edge_label)
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
edges
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
# Build an edge between two nodes
|
|
317
|
+
#
|
|
318
|
+
# @param source_id [String] The source node ID
|
|
319
|
+
# @param target_id [String] The target node ID
|
|
320
|
+
# @param label [String] The edge label
|
|
321
|
+
# @return [Tasker::Diagram::Edge] The edge
|
|
322
|
+
def build_edge(source_id, target_id, label = '')
|
|
323
|
+
Tasker::Diagram::Edge.new(
|
|
324
|
+
source_id: source_id,
|
|
325
|
+
target_id: target_id,
|
|
326
|
+
label: label
|
|
327
|
+
)
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
end
|
|
@@ -11,27 +11,26 @@ module Tasker
|
|
|
11
11
|
|
|
12
12
|
scope :children_of, ->(step) { where(from_step: step) }
|
|
13
13
|
scope :parents_of, ->(step) { where(to_step: step) }
|
|
14
|
-
scope :siblings_of, ->(step) { find_by_sql(sibling_sql(step.
|
|
14
|
+
scope :siblings_of, ->(step) { find_by_sql(sibling_sql(step.id)) }
|
|
15
15
|
scope :provides_edges, -> { where(name: WorkflowStep::PROVIDES_EDGE_NAME) }
|
|
16
|
-
scope :provides_to_children, ->
|
|
16
|
+
scope :provides_to_children, -> { where(name: WorkflowStep::PROVIDES_EDGE_NAME, to_step: children_of(from_step)) }
|
|
17
17
|
|
|
18
18
|
def self.create_edge!(from_step, to_step, name)
|
|
19
19
|
create!(from_step: from_step, to_step: to_step, name: name)
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def self.sibling_sql(step_id)
|
|
23
|
-
sanitized_id = connection.quote(step_id)
|
|
24
23
|
<<~SQL.squish
|
|
25
24
|
WITH step_parents AS (
|
|
26
25
|
SELECT from_step_id
|
|
27
26
|
FROM tasker_workflow_step_edges
|
|
28
|
-
WHERE to_step_id = #{
|
|
27
|
+
WHERE to_step_id = #{step_id}
|
|
29
28
|
),
|
|
30
29
|
potential_siblings AS (
|
|
31
30
|
SELECT to_step_id
|
|
32
31
|
FROM tasker_workflow_step_edges
|
|
33
32
|
WHERE from_step_id IN (SELECT from_step_id FROM step_parents)
|
|
34
|
-
AND to_step_id != #{
|
|
33
|
+
AND to_step_id != #{step_id}
|
|
35
34
|
),
|
|
36
35
|
siblings AS (
|
|
37
36
|
SELECT to_step_id
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<title>Task <%= task.task_id %> Workflow Diagram</title>
|
|
6
|
+
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
|
|
7
|
+
<script>
|
|
8
|
+
mermaid.initialize({
|
|
9
|
+
startOnLoad: true,
|
|
10
|
+
theme: 'default'
|
|
11
|
+
});
|
|
12
|
+
</script>
|
|
13
|
+
<style>
|
|
14
|
+
body { font-family: Arial, sans-serif; margin: 20px; }
|
|
15
|
+
.mermaid { margin: 20px 0; }
|
|
16
|
+
.header { margin-bottom: 20px; }
|
|
17
|
+
</style>
|
|
18
|
+
</head>
|
|
19
|
+
<body>
|
|
20
|
+
<div class="header">
|
|
21
|
+
<h1>Task Workflow Diagram</h1>
|
|
22
|
+
<p>Task ID: <%= task.task_id %></p>
|
|
23
|
+
<p>Task Name: <%= task.name %></p>
|
|
24
|
+
<p>Status: <%= task.status %></p>
|
|
25
|
+
<p>Created: <%= task.created_at %></p>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<div class="tasker-diagram mermaid">
|
|
29
|
+
<%= diagram %>
|
|
30
|
+
</div>
|
|
31
|
+
</body>
|
|
32
|
+
</html>
|
data/config/routes.rb
CHANGED
|
@@ -24,11 +24,11 @@ Tasker::Engine.routes.draw do
|
|
|
24
24
|
get '/handlers/:namespace', to: 'handlers#show_namespace' # List handlers in namespace
|
|
25
25
|
get '/handlers/:namespace/:name', to: 'handlers#show' # Show specific handler with dependency graph
|
|
26
26
|
|
|
27
|
-
# GraphQL endpoint
|
|
28
27
|
post '/graphql', to: 'graphql#execute'
|
|
29
|
-
|
|
30
|
-
#
|
|
28
|
+
# mount Rswag::Ui::Engine => '/api-docs'
|
|
29
|
+
# mount Rswag::Api::Engine => '/api-docs'
|
|
31
30
|
resources :tasks do
|
|
32
31
|
resources :workflow_steps
|
|
32
|
+
resources :task_diagrams, only: %i[index]
|
|
33
33
|
end
|
|
34
34
|
end
|
data/db/init/schema.sql
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
SET statement_timeout = 0;
|
|
2
|
+
SET lock_timeout = 0;
|
|
3
|
+
SET idle_in_transaction_session_timeout = 0;
|
|
4
|
+
SET client_encoding = 'UTF8';
|
|
5
|
+
SET standard_conforming_strings = on;
|
|
6
|
+
SELECT pg_catalog.set_config('search_path', '', false);
|
|
7
|
+
SET check_function_bodies = false;
|
|
8
|
+
SET xmloption = content;
|
|
9
|
+
SET client_min_messages = warning;
|
|
10
|
+
SET row_security = off;
|
|
11
|
+
|
|
1
12
|
--
|
|
2
13
|
-- Name: calculate_dependency_levels(bigint); Type: FUNCTION; Schema: public; Owner: -
|
|
3
14
|
--
|
|
@@ -824,6 +835,11 @@ BEGIN
|
|
|
824
835
|
END;
|
|
825
836
|
$$;
|
|
826
837
|
|
|
838
|
+
|
|
839
|
+
SET default_tablespace = '';
|
|
840
|
+
|
|
841
|
+
SET default_table_access_method = heap;
|
|
842
|
+
|
|
827
843
|
--
|
|
828
844
|
-- Name: tasker_annotation_types; Type: TABLE; Schema: public; Owner: -
|
|
829
845
|
--
|
|
@@ -2252,3 +2268,10 @@ ALTER TABLE ONLY public.tasker_workflow_steps
|
|
|
2252
2268
|
|
|
2253
2269
|
ALTER TABLE ONLY public.tasker_workflow_steps
|
|
2254
2270
|
ADD CONSTRAINT workflow_steps_task_id_foreign FOREIGN KEY (task_id) REFERENCES public.tasker_tasks(task_id);
|
|
2271
|
+
|
|
2272
|
+
|
|
2273
|
+
--
|
|
2274
|
+
-- PostgreSQL database dump complete
|
|
2275
|
+
--
|
|
2276
|
+
|
|
2277
|
+
SET search_path TO "$user", public;
|
|
@@ -366,7 +366,7 @@ Once installed, developers can immediately:
|
|
|
366
366
|
task = Tasker::HandlerFactory.instance.get(
|
|
367
367
|
'order_processing',
|
|
368
368
|
namespace_name: 'ecommerce',
|
|
369
|
-
version: '1.0.
|
|
369
|
+
version: '1.0.0'
|
|
370
370
|
).initialize_task!(
|
|
371
371
|
Tasker::Types::TaskRequest.new(
|
|
372
372
|
name: 'order_processing',
|
data/docs/AUTH.md
CHANGED
|
@@ -57,7 +57,7 @@ By default, Tasker requires no authentication:
|
|
|
57
57
|
|
|
58
58
|
```ruby
|
|
59
59
|
# config/initializers/tasker.rb
|
|
60
|
-
Tasker
|
|
60
|
+
Tasker.configuration do |config|
|
|
61
61
|
config.auth do |auth|
|
|
62
62
|
auth.authentication_enabled = false # Default - no configuration needed
|
|
63
63
|
end
|
|
@@ -70,7 +70,7 @@ For any authentication system, enable authentication and specify your authentica
|
|
|
70
70
|
|
|
71
71
|
```ruby
|
|
72
72
|
# config/initializers/tasker.rb
|
|
73
|
-
Tasker
|
|
73
|
+
Tasker.configuration do |config|
|
|
74
74
|
config.auth do |auth|
|
|
75
75
|
auth.authentication_enabled = true
|
|
76
76
|
auth.authenticator_class = 'YourCustomAuthenticator'
|
|
@@ -85,7 +85,7 @@ Enable both authentication and authorization for complete security:
|
|
|
85
85
|
|
|
86
86
|
```ruby
|
|
87
87
|
# config/initializers/tasker.rb
|
|
88
|
-
Tasker
|
|
88
|
+
Tasker.configuration do |config|
|
|
89
89
|
config.auth do |auth|
|
|
90
90
|
auth.authentication_enabled = true
|
|
91
91
|
auth.authenticator_class = 'YourCustomAuthenticator'
|
|
@@ -104,7 +104,7 @@ Authorization in Tasker uses a **resource:action** permission model that works s
|
|
|
104
104
|
|
|
105
105
|
```ruby
|
|
106
106
|
# config/initializers/tasker.rb
|
|
107
|
-
Tasker
|
|
107
|
+
Tasker.configuration do |config|
|
|
108
108
|
config.auth do |auth|
|
|
109
109
|
auth.authorization_enabled = true
|
|
110
110
|
auth.authorization_coordinator_class = 'YourAuthorizationCoordinator'
|
|
@@ -126,6 +126,8 @@ class YourAuthorizationCoordinator < Tasker::Authorization::BaseCoordinator
|
|
|
126
126
|
authorize_task_action(action, context)
|
|
127
127
|
when Tasker::Authorization::ResourceConstants::RESOURCES::WORKFLOW_STEP
|
|
128
128
|
authorize_step_action(action, context)
|
|
129
|
+
when Tasker::Authorization::ResourceConstants::RESOURCES::TASK_DIAGRAM
|
|
130
|
+
authorize_diagram_action(action, context)
|
|
129
131
|
when Tasker::Authorization::ResourceConstants::RESOURCES::HEALTH_STATUS
|
|
130
132
|
authorize_health_status_action(action, context)
|
|
131
133
|
else
|
|
@@ -160,6 +162,15 @@ class YourAuthorizationCoordinator < Tasker::Authorization::BaseCoordinator
|
|
|
160
162
|
end
|
|
161
163
|
end
|
|
162
164
|
|
|
165
|
+
def authorize_diagram_action(action, context)
|
|
166
|
+
case action
|
|
167
|
+
when :index, :show
|
|
168
|
+
user.tasker_admin? || user.has_tasker_permission?("#{Tasker::Authorization::ResourceConstants::RESOURCES::TASK_DIAGRAM}:#{action}")
|
|
169
|
+
else
|
|
170
|
+
false
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
163
174
|
def authorize_health_status_action(action, context)
|
|
164
175
|
case action
|
|
165
176
|
when :index
|
|
@@ -232,7 +243,7 @@ Enable health status authorization:
|
|
|
232
243
|
|
|
233
244
|
```ruby
|
|
234
245
|
# config/initializers/tasker.rb
|
|
235
|
-
Tasker
|
|
246
|
+
Tasker.configuration do |config|
|
|
236
247
|
config.auth do |auth|
|
|
237
248
|
auth.authorization_enabled = true
|
|
238
249
|
auth.authorization_coordinator_class = 'YourAuthorizationCoordinator'
|
|
@@ -464,7 +475,7 @@ rails generate tasker:authenticator CompanyJWT --type=jwt --user-class=User
|
|
|
464
475
|
### Authentication Configuration Block
|
|
465
476
|
|
|
466
477
|
```ruby
|
|
467
|
-
Tasker
|
|
478
|
+
Tasker.configuration do |config|
|
|
468
479
|
config.auth do |auth|
|
|
469
480
|
# Authentication settings
|
|
470
481
|
auth.authentication_enabled = true | false # Enable/disable authentication
|
|
@@ -543,11 +554,13 @@ All authorization revolves around the central resource registry:
|
|
|
543
554
|
Resources:
|
|
544
555
|
- tasker.task (index, show, create, update, destroy, retry, cancel)
|
|
545
556
|
- tasker.workflow_step (index, show, update, destroy, retry, cancel)
|
|
557
|
+
- tasker.task_diagram (index, show)
|
|
546
558
|
|
|
547
559
|
# Permission Examples:
|
|
548
560
|
'tasker.task:index' # List all tasks
|
|
549
561
|
'tasker.task:create' # Create new tasks
|
|
550
562
|
'tasker.workflow_step:show' # View individual workflow steps
|
|
563
|
+
'tasker.task_diagram:index' # List task diagrams
|
|
551
564
|
```
|
|
552
565
|
|
|
553
566
|
### Authorization Coordinator Interface
|
|
@@ -609,6 +622,10 @@ end
|
|
|
609
622
|
- `retry` - Retry failed step
|
|
610
623
|
- `cancel` - Cancel running step
|
|
611
624
|
|
|
625
|
+
#### Task Diagrams (`tasker.task_diagram`)
|
|
626
|
+
- `index` - List task diagrams
|
|
627
|
+
- `show` - View specific diagram
|
|
628
|
+
|
|
612
629
|
## Building Authorization Coordinators
|
|
613
630
|
|
|
614
631
|
Authorization coordinators provide the business logic for permission checking. Here's how to build effective coordinators:
|
|
@@ -626,6 +643,8 @@ class CompanyAuthorizationCoordinator < Tasker::Authorization::BaseCoordinator
|
|
|
626
643
|
authorize_task(action, context)
|
|
627
644
|
when Tasker::Authorization::ResourceConstants::RESOURCES::WORKFLOW_STEP
|
|
628
645
|
authorize_workflow_step(action, context)
|
|
646
|
+
when Tasker::Authorization::ResourceConstants::RESOURCES::TASK_DIAGRAM
|
|
647
|
+
authorize_task_diagram(action, context)
|
|
629
648
|
else
|
|
630
649
|
false
|
|
631
650
|
end
|
|
@@ -658,6 +677,16 @@ class CompanyAuthorizationCoordinator < Tasker::Authorization::BaseCoordinator
|
|
|
658
677
|
false
|
|
659
678
|
end
|
|
660
679
|
end
|
|
680
|
+
|
|
681
|
+
def authorize_task_diagram(action, context)
|
|
682
|
+
case action
|
|
683
|
+
when :index, :show
|
|
684
|
+
# Diagram viewing
|
|
685
|
+
user.has_tasker_permission?("tasker.task_diagram:#{action}")
|
|
686
|
+
else
|
|
687
|
+
false
|
|
688
|
+
end
|
|
689
|
+
end
|
|
661
690
|
end
|
|
662
691
|
```
|
|
663
692
|
|
|
@@ -840,7 +869,7 @@ Our `ExampleJWTAuthenticator` demonstrates a production-ready JWT implementation
|
|
|
840
869
|
|
|
841
870
|
```ruby
|
|
842
871
|
# config/initializers/tasker.rb
|
|
843
|
-
Tasker
|
|
872
|
+
Tasker.configuration do |config|
|
|
844
873
|
config.auth do |auth|
|
|
845
874
|
auth.authentication_enabled = true
|
|
846
875
|
auth.authenticator_class = 'ExampleJWTAuthenticator'
|
|
@@ -864,7 +893,7 @@ end
|
|
|
864
893
|
|
|
865
894
|
```ruby
|
|
866
895
|
# config/initializers/tasker.rb
|
|
867
|
-
Tasker
|
|
896
|
+
Tasker.configuration do |config|
|
|
868
897
|
config.auth do |auth|
|
|
869
898
|
auth.authentication_enabled = true
|
|
870
899
|
auth.authenticator_class = 'ExampleJWTAuthenticator'
|
|
@@ -1092,6 +1121,9 @@ DELETE /tasker/tasks/123 → tasker.task:destroy
|
|
|
1092
1121
|
GET /tasker/tasks/123/workflow_steps → tasker.workflow_step:index
|
|
1093
1122
|
GET /tasker/workflow_steps/456 → tasker.workflow_step:show
|
|
1094
1123
|
PATCH /tasker/workflow_steps/456 → tasker.workflow_step:update
|
|
1124
|
+
|
|
1125
|
+
GET /tasker/tasks/123/task_diagrams → tasker.task_diagram:index
|
|
1126
|
+
GET /tasker/task_diagrams/789 → tasker.task_diagram:show
|
|
1095
1127
|
```
|
|
1096
1128
|
|
|
1097
1129
|
### GraphQL Integration
|
|
@@ -1284,7 +1316,7 @@ For authorization testing, use comprehensive integration tests:
|
|
|
1284
1316
|
# spec/support/shared_contexts/configuration_test_isolation.rb
|
|
1285
1317
|
RSpec.shared_context 'configuration test isolation' do
|
|
1286
1318
|
around(:each) do |example|
|
|
1287
|
-
original_config = Tasker
|
|
1319
|
+
original_config = Tasker.configuration
|
|
1288
1320
|
example.run
|
|
1289
1321
|
ensure
|
|
1290
1322
|
# Reset to clean state
|
|
@@ -1313,7 +1345,8 @@ RSpec.describe 'Authorization Integration', type: :request do
|
|
|
1313
1345
|
permissions: [
|
|
1314
1346
|
'tasker.task:index',
|
|
1315
1347
|
'tasker.task:show',
|
|
1316
|
-
'tasker.workflow_step:index'
|
|
1348
|
+
'tasker.workflow_step:index',
|
|
1349
|
+
'tasker.task_diagram:index'
|
|
1317
1350
|
],
|
|
1318
1351
|
roles: ['user'],
|
|
1319
1352
|
admin: false
|
|
@@ -1443,7 +1476,7 @@ RSpec.configure do |config|
|
|
|
1443
1476
|
config.after(:each) do
|
|
1444
1477
|
# Automatic cleanup of authentication/authorization state
|
|
1445
1478
|
if defined?(Tasker) && Tasker.respond_to?(:configuration)
|
|
1446
|
-
current_config = Tasker
|
|
1479
|
+
current_config = Tasker.configuration
|
|
1447
1480
|
if current_config&.auth&.authorization_enabled == true
|
|
1448
1481
|
needs_reset = true
|
|
1449
1482
|
end
|
|
@@ -1454,7 +1487,7 @@ RSpec.configure do |config|
|
|
|
1454
1487
|
end
|
|
1455
1488
|
|
|
1456
1489
|
if needs_reset
|
|
1457
|
-
Tasker
|
|
1490
|
+
Tasker.configuration do |config|
|
|
1458
1491
|
config.auth.authentication_enabled = false
|
|
1459
1492
|
config.auth.authorization_enabled = false
|
|
1460
1493
|
config.auth.authenticator_class = nil
|
|
@@ -1590,6 +1623,8 @@ class CompanyAuthorizationCoordinator < Tasker::Authorization::BaseCoordinator
|
|
|
1590
1623
|
authorize_task(action, context)
|
|
1591
1624
|
when ResourceConstants::RESOURCES::WORKFLOW_STEP
|
|
1592
1625
|
authorize_workflow_step(action, context)
|
|
1626
|
+
when ResourceConstants::RESOURCES::TASK_DIAGRAM
|
|
1627
|
+
authorize_task_diagram(action, context)
|
|
1593
1628
|
else
|
|
1594
1629
|
false
|
|
1595
1630
|
end
|
|
@@ -1605,6 +1640,10 @@ class CompanyAuthorizationCoordinator < Tasker::Authorization::BaseCoordinator
|
|
|
1605
1640
|
def authorize_workflow_step(action, context)
|
|
1606
1641
|
# Workflow step authorization logic
|
|
1607
1642
|
end
|
|
1643
|
+
|
|
1644
|
+
def authorize_task_diagram(action, context)
|
|
1645
|
+
# Diagram authorization logic
|
|
1646
|
+
end
|
|
1608
1647
|
end
|
|
1609
1648
|
```
|
|
1610
1649
|
|