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,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base_subscriber'
|
4
|
+
|
5
|
+
module Tasker
|
6
|
+
module Events
|
7
|
+
module Subscribers
|
8
|
+
# MetricsSubscriber bridges events to the EventRouter for automatic metrics collection
|
9
|
+
#
|
10
|
+
# This subscriber is the critical bridge between Tasker's event publishing system
|
11
|
+
# and the EventRouter-based metrics collection. It subscribes to all events that
|
12
|
+
# should route to metrics and forwards them to EventRouter.route_event().
|
13
|
+
#
|
14
|
+
# Architecture:
|
15
|
+
# - TelemetrySubscriber: Creates OpenTelemetry spans for debugging
|
16
|
+
# - MetricsSubscriber: Routes events to EventRouter for metrics collection
|
17
|
+
# - EventRouter: Intelligent routing to MetricsBackend based on configuration
|
18
|
+
# - MetricsBackend: Thread-safe native metrics storage
|
19
|
+
#
|
20
|
+
# This subscriber automatically subscribes to all events configured in EventRouter
|
21
|
+
# that route to metrics, ensuring zero-configuration metrics collection.
|
22
|
+
class MetricsSubscriber < BaseSubscriber
|
23
|
+
def initialize
|
24
|
+
super
|
25
|
+
@event_router = Tasker::Telemetry::EventRouter.instance
|
26
|
+
|
27
|
+
# Dynamically subscribe to all events that route to metrics
|
28
|
+
subscribe_to_metrics_events
|
29
|
+
end
|
30
|
+
|
31
|
+
# Handle any event by routing it through EventRouter
|
32
|
+
#
|
33
|
+
# This is a catch-all handler that routes events to the EventRouter
|
34
|
+
# based on the configured mappings.
|
35
|
+
#
|
36
|
+
# @param event_name [String] The event name
|
37
|
+
# @param event [Hash, Dry::Events::Event] The event payload
|
38
|
+
# @return [void]
|
39
|
+
def handle_event(event_name, event)
|
40
|
+
return unless should_process_event?(event_name)
|
41
|
+
|
42
|
+
# Extract payload from event object if needed
|
43
|
+
payload = event.respond_to?(:payload) ? event.payload : event
|
44
|
+
|
45
|
+
# Route to EventRouter for intelligent backend routing
|
46
|
+
@event_router.route_event(event_name, payload)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Override method_missing to handle dynamic event methods
|
50
|
+
#
|
51
|
+
# Since we subscribe to events dynamically, we need to handle
|
52
|
+
# the resulting method calls dynamically as well.
|
53
|
+
#
|
54
|
+
# @param method_name [Symbol] The method name
|
55
|
+
# @param args [Array] Method arguments
|
56
|
+
# @return [void]
|
57
|
+
def method_missing(method_name, *args)
|
58
|
+
if method_name.to_s.start_with?('handle_')
|
59
|
+
# Extract event name from method name
|
60
|
+
event_name = method_name.to_s.sub(/^handle_/, '').tr('_', '.')
|
61
|
+
handle_event(event_name, args.first)
|
62
|
+
else
|
63
|
+
super
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Check if we respond to dynamic event handler methods
|
68
|
+
#
|
69
|
+
# @param method_name [Symbol] The method name
|
70
|
+
# @param include_private [Boolean] Whether to include private methods
|
71
|
+
# @return [Boolean] True if we respond to the method
|
72
|
+
def respond_to_missing?(method_name, include_private = false)
|
73
|
+
method_name.to_s.start_with?('handle_') || super
|
74
|
+
end
|
75
|
+
|
76
|
+
# Override BaseSubscriber to check EventRouter configuration
|
77
|
+
#
|
78
|
+
# @param event_constant [String] The event constant or name
|
79
|
+
# @return [Boolean] True if the event should be processed
|
80
|
+
def should_process_event?(event_constant)
|
81
|
+
# Only process if telemetry is enabled
|
82
|
+
return false unless Tasker.configuration.telemetry.enabled
|
83
|
+
|
84
|
+
# Convert constant to event name if needed
|
85
|
+
event_name = event_constant.respond_to?(:name) ? event_constant.name : event_constant.to_s
|
86
|
+
|
87
|
+
# Check if EventRouter routes this event to metrics
|
88
|
+
@event_router.routes_to_metrics?(event_name)
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
# Subscribe to all events that route to metrics
|
94
|
+
#
|
95
|
+
# This method dynamically subscribes to events based on EventRouter configuration
|
96
|
+
# @return [void]
|
97
|
+
def subscribe_to_metrics_events
|
98
|
+
metrics_events = @event_router.events_for_backend(:metrics)
|
99
|
+
|
100
|
+
# Convert event names to constants and subscribe
|
101
|
+
event_constants = metrics_events.filter_map do |event_name|
|
102
|
+
# Convert dot notation to constant path
|
103
|
+
constant_path = event_name.split('.').map(&:upcase).join('::')
|
104
|
+
|
105
|
+
begin
|
106
|
+
# Try to resolve the constant
|
107
|
+
Tasker::Constants.const_get(constant_path)
|
108
|
+
rescue NameError
|
109
|
+
# If constant doesn't exist, use the string directly
|
110
|
+
event_name
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Subscribe to the events
|
115
|
+
self.class.subscribe_to(*event_constants) unless event_constants.empty?
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,462 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../constants'
|
4
|
+
require_relative 'base_subscriber'
|
5
|
+
|
6
|
+
module Tasker
|
7
|
+
module Events
|
8
|
+
module Subscribers
|
9
|
+
# TelemetrySubscriber handles telemetry events for observability
|
10
|
+
#
|
11
|
+
# This subscriber creates OpenTelemetry spans with proper hierarchical context
|
12
|
+
# for distributed tracing in systems like Jaeger. It follows OpenTelemetry
|
13
|
+
# best practices by creating detailed spans for debugging while allowing
|
14
|
+
# metrics to be derived from span data.
|
15
|
+
#
|
16
|
+
# Architecture Decision:
|
17
|
+
# - SPANS: Individual trace records for detailed debugging (this class)
|
18
|
+
# - METRICS: Aggregated data for dashboards/alerts (derived from spans or separate collectors)
|
19
|
+
class TelemetrySubscriber < BaseSubscriber
|
20
|
+
attr_accessor :tracer
|
21
|
+
|
22
|
+
# Use actual constants for consistent subscription (no string literals)
|
23
|
+
subscribe_to Tasker::Constants::TaskEvents::INITIALIZE_REQUESTED,
|
24
|
+
Tasker::Constants::TaskEvents::START_REQUESTED,
|
25
|
+
Tasker::Constants::TaskEvents::COMPLETED,
|
26
|
+
Tasker::Constants::TaskEvents::FAILED,
|
27
|
+
Tasker::Constants::StepEvents::EXECUTION_REQUESTED,
|
28
|
+
Tasker::Constants::StepEvents::COMPLETED,
|
29
|
+
Tasker::Constants::StepEvents::FAILED,
|
30
|
+
Tasker::Constants::StepEvents::RETRY_REQUESTED
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
super
|
34
|
+
@tracer = create_tracer
|
35
|
+
end
|
36
|
+
|
37
|
+
# Handle task initialization events
|
38
|
+
def handle_task_initialize_requested(event)
|
39
|
+
return unless should_process_event?(Tasker::Constants::TaskEvents::INITIALIZE_REQUESTED)
|
40
|
+
|
41
|
+
attributes = extract_core_attributes(event).merge(
|
42
|
+
task_name: safe_get(event, :task_name, 'unknown_task')
|
43
|
+
)
|
44
|
+
|
45
|
+
# Only create basic span for initialization - task.start_requested will create the main span
|
46
|
+
create_simple_span(event, 'tasker.task.initialize', attributes)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Handle task start events
|
50
|
+
def handle_task_start_requested(event)
|
51
|
+
return unless should_process_event?(Tasker::Constants::TaskEvents::START_REQUESTED)
|
52
|
+
|
53
|
+
attributes = extract_core_attributes(event).merge(
|
54
|
+
task_name: safe_get(event, :task_name, 'unknown_task')
|
55
|
+
)
|
56
|
+
|
57
|
+
# Create root span for task and store it for child spans
|
58
|
+
create_task_span(event, 'tasker.task.execution', attributes)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Handle task completion events
|
62
|
+
def handle_task_completed(event)
|
63
|
+
return unless should_process_event?(Tasker::Constants::TaskEvents::COMPLETED)
|
64
|
+
|
65
|
+
attributes = extract_core_attributes(event).merge(
|
66
|
+
task_name: safe_get(event, :task_name, 'unknown_task'),
|
67
|
+
duration: calculate_duration(event),
|
68
|
+
total_execution_duration: safe_get(event, :total_execution_duration, 0.0),
|
69
|
+
current_execution_duration: safe_get(event, :current_execution_duration, 0.0),
|
70
|
+
total_steps: safe_get(event, :total_steps, 0),
|
71
|
+
completed_steps: safe_get(event, :completed_steps, 0)
|
72
|
+
)
|
73
|
+
|
74
|
+
# Finish the task span with success status
|
75
|
+
finish_task_span(event, :ok, attributes)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Handle task failure events
|
79
|
+
def handle_task_failed(event)
|
80
|
+
return unless should_process_event?(Tasker::Constants::TaskEvents::FAILED)
|
81
|
+
|
82
|
+
attributes = extract_core_attributes(event).merge(
|
83
|
+
task_name: safe_get(event, :task_name, 'unknown_task'),
|
84
|
+
error: safe_get(event, :error_message, safe_get(event, :error, 'Unknown error')),
|
85
|
+
exception_class: safe_get(event, :exception_class, 'StandardError'),
|
86
|
+
failed_steps: safe_get(event, :failed_steps, 0)
|
87
|
+
)
|
88
|
+
|
89
|
+
# Finish the task span with error status
|
90
|
+
finish_task_span(event, :error, attributes)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Handle step execution requested events
|
94
|
+
def handle_step_execution_requested(event)
|
95
|
+
return unless should_process_event?(Tasker::Constants::StepEvents::EXECUTION_REQUESTED)
|
96
|
+
|
97
|
+
attributes = extract_step_attributes(event).merge(
|
98
|
+
attempt_number: safe_get(event, :attempt_number, 1)
|
99
|
+
)
|
100
|
+
|
101
|
+
# Create a simple span for step queuing
|
102
|
+
create_simple_span(event, 'tasker.step.queued', attributes)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Handle step completion events
|
106
|
+
def handle_step_completed(event)
|
107
|
+
return unless should_process_event?(Tasker::Constants::StepEvents::COMPLETED)
|
108
|
+
|
109
|
+
attributes = extract_step_attributes(event).merge(
|
110
|
+
execution_duration: safe_get(event, :execution_duration, 0.0),
|
111
|
+
attempt_number: safe_get(event, :attempt_number, 1)
|
112
|
+
)
|
113
|
+
|
114
|
+
# Create step span as child of task span
|
115
|
+
create_step_span(event, 'tasker.step.execution', attributes, :ok)
|
116
|
+
end
|
117
|
+
|
118
|
+
# Handle step failure events
|
119
|
+
def handle_step_failed(event)
|
120
|
+
return unless should_process_event?(Tasker::Constants::StepEvents::FAILED)
|
121
|
+
|
122
|
+
attributes = extract_step_attributes(event).merge(
|
123
|
+
error: safe_get(event, :error_message, safe_get(event, :error, 'Unknown error')),
|
124
|
+
attempt_number: safe_get(event, :attempt_number, 1),
|
125
|
+
exception_class: safe_get(event, :exception_class, 'StandardError'),
|
126
|
+
retry_limit: safe_get(event, :retry_limit, 3)
|
127
|
+
)
|
128
|
+
|
129
|
+
# Create step span as child of task span with error status
|
130
|
+
create_step_span(event, 'tasker.step.execution', attributes, :error)
|
131
|
+
end
|
132
|
+
|
133
|
+
# Handle step retry events
|
134
|
+
def handle_step_retry_requested(event)
|
135
|
+
return unless should_process_event?(Tasker::Constants::StepEvents::RETRY_REQUESTED)
|
136
|
+
|
137
|
+
attributes = extract_step_attributes(event).merge(
|
138
|
+
attempt_number: safe_get(event, :attempt_number, 1),
|
139
|
+
retry_limit: safe_get(event, :retry_limit, 3)
|
140
|
+
)
|
141
|
+
|
142
|
+
# Create a simple span for retry events
|
143
|
+
create_simple_span(event, 'tasker.step.retry', attributes)
|
144
|
+
end
|
145
|
+
|
146
|
+
# Override BaseSubscriber to add telemetry-specific filtering
|
147
|
+
def should_process_event?(event_constant)
|
148
|
+
# Get configuration once for efficiency
|
149
|
+
config = Tasker.configuration
|
150
|
+
|
151
|
+
# Only process if telemetry is enabled
|
152
|
+
return false unless config.telemetry.enabled
|
153
|
+
|
154
|
+
super
|
155
|
+
end
|
156
|
+
|
157
|
+
# Extract step-specific attributes (enhanced from BaseSubscriber)
|
158
|
+
def extract_step_attributes(event)
|
159
|
+
super.merge(
|
160
|
+
step_name: safe_get(event, :step_name, 'unknown_step')
|
161
|
+
)
|
162
|
+
end
|
163
|
+
|
164
|
+
# Check if telemetry is enabled
|
165
|
+
def telemetry_enabled?
|
166
|
+
Tasker.configuration.telemetry.enabled != false
|
167
|
+
end
|
168
|
+
|
169
|
+
# Create a simple span for events that don't need complex hierarchy
|
170
|
+
#
|
171
|
+
# @param event [Hash] The event data
|
172
|
+
# @param span_name [String] The name for the span
|
173
|
+
# @param attributes [Hash] Span attributes
|
174
|
+
def create_simple_span(event, span_name, attributes)
|
175
|
+
return unless opentelemetry_available?
|
176
|
+
|
177
|
+
otel_attributes = convert_attributes_for_otel(attributes)
|
178
|
+
|
179
|
+
tracer.in_span(span_name, attributes: otel_attributes) do |span|
|
180
|
+
# Add event annotation
|
181
|
+
span.add_event(event_to_annotation_name(event), attributes: otel_attributes)
|
182
|
+
end
|
183
|
+
rescue StandardError => e
|
184
|
+
Rails.logger.warn("Failed to create simple span: #{e.message}")
|
185
|
+
end
|
186
|
+
|
187
|
+
# Create a root span for a task and store it for child spans
|
188
|
+
#
|
189
|
+
# @param event [Hash] The event data
|
190
|
+
# @param span_name [String] The name for the span
|
191
|
+
# @param attributes [Hash] Span attributes
|
192
|
+
def create_task_span(event, span_name, attributes)
|
193
|
+
return unless opentelemetry_available?
|
194
|
+
|
195
|
+
task_id = safe_get(event, :task_id)
|
196
|
+
return unless task_id
|
197
|
+
|
198
|
+
otel_attributes = convert_attributes_for_otel(attributes)
|
199
|
+
|
200
|
+
span = tracer.start_root_span(span_name, attributes: otel_attributes)
|
201
|
+
store_task_span(task_id, span)
|
202
|
+
|
203
|
+
# Add an event to mark the task start
|
204
|
+
span.add_event('task.started', attributes: otel_attributes)
|
205
|
+
rescue StandardError => e
|
206
|
+
Rails.logger.warn("Failed to create task span: #{e.message}")
|
207
|
+
end
|
208
|
+
|
209
|
+
# Finish a task span with the appropriate status
|
210
|
+
#
|
211
|
+
# @param event [Hash] The event data
|
212
|
+
# @param status [Symbol] The span status (:ok or :error)
|
213
|
+
# @param attributes [Hash] Final span attributes
|
214
|
+
def finish_task_span(event, status, attributes)
|
215
|
+
return unless opentelemetry_available?
|
216
|
+
|
217
|
+
task_id = safe_get(event, :task_id)
|
218
|
+
return unless task_id
|
219
|
+
|
220
|
+
span = get_task_span(task_id)
|
221
|
+
return unless span
|
222
|
+
|
223
|
+
otel_attributes = convert_attributes_for_otel(attributes)
|
224
|
+
|
225
|
+
# Add completion event
|
226
|
+
event_name = status == :error ? 'task.failed' : 'task.completed'
|
227
|
+
span.add_event(event_name, attributes: otel_attributes)
|
228
|
+
|
229
|
+
# Set span status
|
230
|
+
set_span_status(span, status, attributes)
|
231
|
+
|
232
|
+
# Finish the span
|
233
|
+
span.finish
|
234
|
+
remove_task_span(task_id)
|
235
|
+
rescue StandardError => e
|
236
|
+
Rails.logger.warn("Failed to finish task span: #{e.message}")
|
237
|
+
end
|
238
|
+
|
239
|
+
# Create a step span as a child of the task span
|
240
|
+
#
|
241
|
+
# @param event [Hash] The event data
|
242
|
+
# @param span_name [String] The name for the span
|
243
|
+
# @param attributes [Hash] Span attributes
|
244
|
+
# @param status [Symbol] The span status (:ok or :error)
|
245
|
+
def create_step_span(event, span_name, attributes, status)
|
246
|
+
return unless opentelemetry_available?
|
247
|
+
|
248
|
+
task_id = safe_get(event, :task_id)
|
249
|
+
step_id = safe_get(event, :step_id)
|
250
|
+
return unless task_id && step_id
|
251
|
+
|
252
|
+
task_span = get_task_span(task_id)
|
253
|
+
return unless task_span
|
254
|
+
|
255
|
+
otel_attributes = convert_attributes_for_otel(attributes)
|
256
|
+
|
257
|
+
# Create child span context
|
258
|
+
span_context = ::OpenTelemetry::Trace.context_with_span(task_span)
|
259
|
+
|
260
|
+
::OpenTelemetry::Context.with_current(span_context) do
|
261
|
+
tracer.in_span(span_name, attributes: otel_attributes) do |step_span|
|
262
|
+
# Add step event
|
263
|
+
event_name = status == :error ? 'step.failed' : 'step.completed'
|
264
|
+
step_span.add_event(event_name, attributes: otel_attributes)
|
265
|
+
|
266
|
+
# Set span status
|
267
|
+
set_span_status(step_span, status, attributes)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
rescue StandardError => e
|
271
|
+
Rails.logger.warn("Failed to create step span: #{e.message}")
|
272
|
+
end
|
273
|
+
|
274
|
+
# Event type to annotation name mapping
|
275
|
+
EVENT_ANNOTATION_MAP = {
|
276
|
+
'initialize_requested' => 'task.initialize',
|
277
|
+
'execution_requested' => 'step.queued',
|
278
|
+
'retry_requested' => 'step.retry'
|
279
|
+
}.freeze
|
280
|
+
|
281
|
+
# Convert event to annotation name
|
282
|
+
def event_to_annotation_name(event)
|
283
|
+
# Simple mapping from event to annotation
|
284
|
+
event_type = safe_get(event, :event_type)
|
285
|
+
EVENT_ANNOTATION_MAP.fetch(event_type, 'event.processed')
|
286
|
+
end
|
287
|
+
|
288
|
+
# Check if OpenTelemetry is available and configured
|
289
|
+
#
|
290
|
+
# @return [Boolean] True if OpenTelemetry is available
|
291
|
+
def opentelemetry_available?
|
292
|
+
defined?(::OpenTelemetry) && ::OpenTelemetry.tracer_provider
|
293
|
+
end
|
294
|
+
|
295
|
+
# Create the OpenTelemetry tracer
|
296
|
+
#
|
297
|
+
# @return [OpenTelemetry::Tracer] The tracer instance
|
298
|
+
def create_tracer
|
299
|
+
config = Tasker.configuration
|
300
|
+
::OpenTelemetry.tracer_provider.tracer(
|
301
|
+
config.telemetry.service_name,
|
302
|
+
config.telemetry.service_version
|
303
|
+
)
|
304
|
+
end
|
305
|
+
|
306
|
+
# Convert event attributes to OpenTelemetry format
|
307
|
+
#
|
308
|
+
# @param attributes [Hash] The attributes to convert
|
309
|
+
# @return [Hash] OpenTelemetry-compatible attributes
|
310
|
+
def convert_attributes_for_otel(attributes)
|
311
|
+
result = {}
|
312
|
+
config = Tasker.configuration
|
313
|
+
service_name = config.telemetry.service_name
|
314
|
+
|
315
|
+
# Filter sensitive data first
|
316
|
+
filtered_attributes = filter_sensitive_attributes(attributes)
|
317
|
+
|
318
|
+
# Ensure attributes are properly formatted for OpenTelemetry
|
319
|
+
filtered_attributes.each do |key, value|
|
320
|
+
# Skip exception_object as it can't be properly serialized
|
321
|
+
next if key == :exception_object
|
322
|
+
|
323
|
+
# Use the configured service name as prefix for all attributes
|
324
|
+
attr_prefix = "#{service_name}."
|
325
|
+
attr_key = key.to_s.start_with?(attr_prefix) ? key.to_s : "#{attr_prefix}#{key}"
|
326
|
+
|
327
|
+
# Convert values based on their type
|
328
|
+
result[attr_key] = convert_value_for_otel(value)
|
329
|
+
end
|
330
|
+
|
331
|
+
result
|
332
|
+
end
|
333
|
+
|
334
|
+
private
|
335
|
+
|
336
|
+
# Convert value to OpenTelemetry-compatible format
|
337
|
+
#
|
338
|
+
# @param value [Object] The value to convert
|
339
|
+
# @return [String] OpenTelemetry-compatible value
|
340
|
+
def convert_value_for_otel(value)
|
341
|
+
case value
|
342
|
+
when Hash, Array
|
343
|
+
value.to_json
|
344
|
+
when nil
|
345
|
+
''
|
346
|
+
else
|
347
|
+
value.to_s
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
# Set the span status based on the event status
|
352
|
+
#
|
353
|
+
# @param span [OpenTelemetry::Trace::Span] The span to set status on
|
354
|
+
# @param status [Symbol] The status (:ok or :error)
|
355
|
+
# @param attributes [Hash] The event attributes (for error message)
|
356
|
+
def set_span_status(span, status, attributes)
|
357
|
+
return unless defined?(::OpenTelemetry::Trace::Status)
|
358
|
+
|
359
|
+
if status == :error
|
360
|
+
error_msg = attributes[:error] || attributes[:error_message] || 'Unknown error'
|
361
|
+
span.status = ::OpenTelemetry::Trace::Status.error(error_msg)
|
362
|
+
elsif status == :ok
|
363
|
+
span.status = ::OpenTelemetry::Trace::Status.ok
|
364
|
+
end
|
365
|
+
rescue StandardError => e
|
366
|
+
Rails.logger.debug { "Failed to set span status: #{e.message}" }
|
367
|
+
end
|
368
|
+
|
369
|
+
# Filter sensitive data from attributes
|
370
|
+
#
|
371
|
+
# @param attributes [Hash] The attributes to filter
|
372
|
+
# @return [Hash] The filtered attributes
|
373
|
+
def filter_sensitive_attributes(attributes)
|
374
|
+
filter = Tasker.configuration.telemetry.parameter_filter
|
375
|
+
return attributes unless filter
|
376
|
+
|
377
|
+
filtered_data = {}
|
378
|
+
attributes.each do |key, value|
|
379
|
+
filtered_data[key] = if key == :exception_object
|
380
|
+
# Skip exception objects for filtering but preserve them
|
381
|
+
value
|
382
|
+
else
|
383
|
+
filter.filter_param(key.to_s, value)
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
filtered_data
|
388
|
+
end
|
389
|
+
|
390
|
+
# Get a hash of active spans for tasks
|
391
|
+
#
|
392
|
+
# @return [Hash<String, OpenTelemetry::Trace::Span>] Task spans
|
393
|
+
def task_spans
|
394
|
+
@task_spans ||= {}
|
395
|
+
end
|
396
|
+
|
397
|
+
# Store a span for a task
|
398
|
+
#
|
399
|
+
# @param task_id [String, Integer] The task ID
|
400
|
+
# @param span [OpenTelemetry::Trace::Span] The span to store
|
401
|
+
def store_task_span(task_id, span)
|
402
|
+
return unless task_id && span
|
403
|
+
|
404
|
+
task_spans[task_id.to_s] = span
|
405
|
+
end
|
406
|
+
|
407
|
+
# Get a span for a task
|
408
|
+
#
|
409
|
+
# @param task_id [String, Integer] The task ID
|
410
|
+
# @return [OpenTelemetry::Trace::Span, nil] The span or nil if not found
|
411
|
+
def get_task_span(task_id)
|
412
|
+
return nil unless task_id
|
413
|
+
|
414
|
+
task_spans[task_id.to_s]
|
415
|
+
end
|
416
|
+
|
417
|
+
# Remove a span for a task
|
418
|
+
#
|
419
|
+
# @param task_id [String, Integer] The task ID
|
420
|
+
def remove_task_span(task_id)
|
421
|
+
return unless task_id
|
422
|
+
|
423
|
+
task_spans.delete(task_id.to_s)
|
424
|
+
end
|
425
|
+
|
426
|
+
# Calculate duration from event timestamps with fallbacks
|
427
|
+
def calculate_duration(event)
|
428
|
+
started_at = safe_get(event, :started_at)
|
429
|
+
completed_at = safe_get(event, :completed_at)
|
430
|
+
|
431
|
+
return nil unless started_at && completed_at
|
432
|
+
|
433
|
+
# Handle different timestamp formats
|
434
|
+
start_time = parse_timestamp(started_at)
|
435
|
+
end_time = parse_timestamp(completed_at)
|
436
|
+
|
437
|
+
return nil unless start_time && end_time
|
438
|
+
|
439
|
+
(end_time - start_time).round(3)
|
440
|
+
rescue StandardError => e
|
441
|
+
Rails.logger.warn("Failed to calculate duration for telemetry: #{e.message}")
|
442
|
+
nil
|
443
|
+
end
|
444
|
+
|
445
|
+
# Parse timestamp in various formats
|
446
|
+
#
|
447
|
+
# @param timestamp [String, Time, DateTime] The timestamp to parse
|
448
|
+
# @return [Time, nil] The parsed time or nil if parsing fails
|
449
|
+
def parse_timestamp(timestamp)
|
450
|
+
return timestamp.to_time if timestamp.is_a?(Time) || timestamp.is_a?(DateTime)
|
451
|
+
if timestamp.is_a?(String) && timestamp.match?(/\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/)
|
452
|
+
return Time.zone.parse(timestamp)
|
453
|
+
end
|
454
|
+
|
455
|
+
nil
|
456
|
+
rescue StandardError
|
457
|
+
nil
|
458
|
+
end
|
459
|
+
end
|
460
|
+
end
|
461
|
+
end
|
462
|
+
end
|