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,381 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative '../concerns/structured_logging'
|
5
|
+
|
6
|
+
module Tasker
|
7
|
+
module Registry
|
8
|
+
# Comprehensive statistics collection for all registry systems
|
9
|
+
#
|
10
|
+
# Provides unified observability, performance monitoring, and
|
11
|
+
# health checking across all registry components.
|
12
|
+
class StatisticsCollector
|
13
|
+
include Tasker::Concerns::StructuredLogging
|
14
|
+
|
15
|
+
class << self
|
16
|
+
# Collect comprehensive statistics from all registries
|
17
|
+
#
|
18
|
+
# @return [Hash] Complete statistics for all registries
|
19
|
+
def collect_all_registry_stats
|
20
|
+
registries = discover_all_registries
|
21
|
+
|
22
|
+
stats = {
|
23
|
+
collection_timestamp: Time.current,
|
24
|
+
total_registries: registries.size,
|
25
|
+
registries: {}
|
26
|
+
}
|
27
|
+
|
28
|
+
registries.each do |registry|
|
29
|
+
registry_stats = collect_registry_stats(registry)
|
30
|
+
stats[:registries][registry_stats[:registry_name]] = registry_stats
|
31
|
+
end
|
32
|
+
|
33
|
+
# Calculate aggregated metrics
|
34
|
+
stats[:aggregated] = calculate_aggregated_metrics(stats[:registries])
|
35
|
+
|
36
|
+
stats
|
37
|
+
end
|
38
|
+
|
39
|
+
# Collect statistics from a specific registry
|
40
|
+
#
|
41
|
+
# @param registry [BaseRegistry] Registry to collect stats from
|
42
|
+
# @return [Hash] Registry statistics with performance metrics
|
43
|
+
def collect_registry_stats(registry)
|
44
|
+
base_stats = registry.stats
|
45
|
+
health_check = registry.health_check
|
46
|
+
|
47
|
+
{
|
48
|
+
**base_stats,
|
49
|
+
health: health_check,
|
50
|
+
performance: measure_registry_performance(registry),
|
51
|
+
usage_patterns: analyze_usage_patterns(registry),
|
52
|
+
recommendations: generate_recommendations(registry)
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
# Get health status for all registries
|
57
|
+
#
|
58
|
+
# @return [Hash] Health status summary
|
59
|
+
def health_summary
|
60
|
+
registries = discover_all_registries
|
61
|
+
|
62
|
+
health_results = registries.map do |registry|
|
63
|
+
{
|
64
|
+
registry_name: registry.class.name.demodulize.underscore,
|
65
|
+
healthy: registry.healthy?,
|
66
|
+
health_details: registry.health_check
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
{
|
71
|
+
overall_healthy: health_results.all? { |result| result[:healthy] },
|
72
|
+
registry_count: registries.size,
|
73
|
+
healthy_registries: health_results.count { |result| result[:healthy] },
|
74
|
+
unhealthy_registries: health_results.reject { |result| result[:healthy] },
|
75
|
+
registries: health_results,
|
76
|
+
checked_at: Time.current
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
# Find registries matching criteria
|
81
|
+
#
|
82
|
+
# @param criteria [Hash] Search criteria
|
83
|
+
# @option criteria [String] :name_pattern Registry name pattern
|
84
|
+
# @option criteria [Symbol] :health_status Health status filter (:healthy, :unhealthy)
|
85
|
+
# @option criteria [Integer] :min_items Minimum item count
|
86
|
+
# @return [Array<BaseRegistry>] Matching registries
|
87
|
+
def find_registries(criteria = {})
|
88
|
+
registries = discover_all_registries
|
89
|
+
|
90
|
+
if criteria[:name_pattern]
|
91
|
+
pattern = Regexp.new(criteria[:name_pattern], Regexp::IGNORECASE)
|
92
|
+
registries = registries.select { |registry| registry.class.name.match?(pattern) }
|
93
|
+
end
|
94
|
+
|
95
|
+
if criteria[:health_status]
|
96
|
+
case criteria[:health_status]
|
97
|
+
when :healthy
|
98
|
+
registries = registries.select(&:healthy?)
|
99
|
+
when :unhealthy
|
100
|
+
registries = registries.reject(&:healthy?)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
if criteria[:min_items]
|
105
|
+
registries = registries.select do |registry|
|
106
|
+
registry.stats[:total_handlers] ||
|
107
|
+
registry.stats[:total_plugins] ||
|
108
|
+
registry.stats[:total_subscribers] || criteria[:min_items] <= 0
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
registries
|
113
|
+
end
|
114
|
+
|
115
|
+
# Generate performance report
|
116
|
+
#
|
117
|
+
# @return [Hash] Performance analysis across all registries
|
118
|
+
def performance_report
|
119
|
+
registries = discover_all_registries
|
120
|
+
|
121
|
+
performance_data = registries.map do |registry|
|
122
|
+
{
|
123
|
+
registry_name: registry.class.name.demodulize.underscore,
|
124
|
+
performance: measure_registry_performance(registry),
|
125
|
+
item_count: calculate_registry_item_count(registry)
|
126
|
+
}
|
127
|
+
end
|
128
|
+
|
129
|
+
{
|
130
|
+
report_timestamp: Time.current,
|
131
|
+
total_registries: registries.size,
|
132
|
+
performance_data: performance_data,
|
133
|
+
performance_summary: calculate_performance_summary(performance_data)
|
134
|
+
}
|
135
|
+
end
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
# Discover all available registries
|
140
|
+
#
|
141
|
+
# @return [Array<BaseRegistry>] All registry instances
|
142
|
+
def discover_all_registries
|
143
|
+
registries = []
|
144
|
+
|
145
|
+
# Core registries
|
146
|
+
registries << Tasker::HandlerFactory.instance if defined?(Tasker::HandlerFactory)
|
147
|
+
registries << Tasker::Registry::SubscriberRegistry.instance if defined?(Tasker::Registry::SubscriberRegistry)
|
148
|
+
|
149
|
+
# Telemetry registries
|
150
|
+
if defined?(Tasker::Telemetry)
|
151
|
+
registries << Tasker::Telemetry::PluginRegistry.instance if defined?(Tasker::Telemetry::PluginRegistry)
|
152
|
+
if defined?(Tasker::Telemetry::ExportCoordinator)
|
153
|
+
registries << Tasker::Telemetry::ExportCoordinator.instance
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
registries.compact
|
158
|
+
end
|
159
|
+
|
160
|
+
# Measure performance metrics for a registry
|
161
|
+
#
|
162
|
+
# @param registry [BaseRegistry] Registry to measure
|
163
|
+
# @return [Hash] Performance metrics
|
164
|
+
def measure_registry_performance(registry)
|
165
|
+
# Measure stats collection time
|
166
|
+
stats_start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
167
|
+
registry.stats
|
168
|
+
stats_duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - stats_start
|
169
|
+
|
170
|
+
# Measure health check time
|
171
|
+
health_start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
172
|
+
registry.health_check
|
173
|
+
health_duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - health_start
|
174
|
+
|
175
|
+
{
|
176
|
+
stats_response_time_ms: (stats_duration * 1000).round(2),
|
177
|
+
health_check_time_ms: (health_duration * 1000).round(2),
|
178
|
+
thread_safe: true,
|
179
|
+
last_measured: Time.current
|
180
|
+
}
|
181
|
+
end
|
182
|
+
|
183
|
+
# Analyze usage patterns for a registry
|
184
|
+
#
|
185
|
+
# @param registry [BaseRegistry] Registry to analyze
|
186
|
+
# @return [Hash] Usage pattern analysis
|
187
|
+
def analyze_usage_patterns(registry)
|
188
|
+
stats = registry.stats
|
189
|
+
|
190
|
+
{
|
191
|
+
utilization: calculate_utilization(stats),
|
192
|
+
distribution: calculate_distribution(stats),
|
193
|
+
growth_trend: 'stable', # Would track over time in production
|
194
|
+
efficiency_score: calculate_efficiency_score(stats)
|
195
|
+
}
|
196
|
+
end
|
197
|
+
|
198
|
+
# Calculate utilization level
|
199
|
+
#
|
200
|
+
# @param stats [Hash] Registry statistics
|
201
|
+
# @return [String] Utilization level
|
202
|
+
def calculate_utilization(stats)
|
203
|
+
total_items = stats[:total_handlers] || stats[:total_plugins] || stats[:total_subscribers] || 0
|
204
|
+
|
205
|
+
case total_items
|
206
|
+
when 0 then 'empty'
|
207
|
+
when 1..5 then 'low'
|
208
|
+
when 6..20 then 'medium'
|
209
|
+
when 21..50 then 'high'
|
210
|
+
else 'very_high'
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# Calculate distribution pattern
|
215
|
+
#
|
216
|
+
# @param stats [Hash] Registry statistics
|
217
|
+
# @return [String] Distribution pattern
|
218
|
+
def calculate_distribution(stats)
|
219
|
+
if stats[:handlers_by_namespace]
|
220
|
+
analyze_namespace_distribution(stats[:handlers_by_namespace])
|
221
|
+
elsif stats[:plugins_by_format]
|
222
|
+
analyze_format_distribution(stats[:plugins_by_format])
|
223
|
+
elsif stats[:subscribers_by_event]
|
224
|
+
analyze_event_distribution(stats[:subscribers_by_event])
|
225
|
+
else
|
226
|
+
'unknown'
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
# Analyze namespace distribution for handlers
|
231
|
+
#
|
232
|
+
# @param handlers_by_namespace [Hash] Handler distribution data
|
233
|
+
# @return [String] Distribution pattern
|
234
|
+
def analyze_namespace_distribution(handlers_by_namespace)
|
235
|
+
return 'empty' if handlers_by_namespace.empty?
|
236
|
+
|
237
|
+
values = handlers_by_namespace.values
|
238
|
+
return 'single' if values.size == 1
|
239
|
+
|
240
|
+
avg = values.sum.to_f / values.size
|
241
|
+
variance = values.sum { |v| (v - avg)**2 } / values.size
|
242
|
+
|
243
|
+
variance < 2 ? 'even' : 'skewed'
|
244
|
+
end
|
245
|
+
|
246
|
+
# Analyze format distribution for plugins
|
247
|
+
#
|
248
|
+
# @param plugins_by_format [Hash] Plugin distribution data
|
249
|
+
# @return [String] Distribution pattern
|
250
|
+
def analyze_format_distribution(plugins_by_format)
|
251
|
+
return 'empty' if plugins_by_format.empty?
|
252
|
+
|
253
|
+
values = plugins_by_format.values
|
254
|
+
values.uniq.size == 1 ? 'uniform' : 'varied'
|
255
|
+
end
|
256
|
+
|
257
|
+
# Analyze event distribution for subscribers
|
258
|
+
#
|
259
|
+
# @param subscribers_by_event [Hash] Subscriber distribution data
|
260
|
+
# @return [String] Distribution pattern
|
261
|
+
def analyze_event_distribution(subscribers_by_event)
|
262
|
+
return 'empty' if subscribers_by_event.empty?
|
263
|
+
|
264
|
+
values = subscribers_by_event.values
|
265
|
+
avg = values.sum.to_f / values.size
|
266
|
+
variance = values.sum { |v| (v - avg)**2 } / values.size
|
267
|
+
|
268
|
+
variance < 1 ? 'balanced' : 'unbalanced'
|
269
|
+
end
|
270
|
+
|
271
|
+
# Calculate efficiency score
|
272
|
+
#
|
273
|
+
# @param stats [Hash] Registry statistics
|
274
|
+
# @return [Float] Efficiency score (0.0 - 1.0)
|
275
|
+
def calculate_efficiency_score(stats)
|
276
|
+
# Simple efficiency calculation based on utilization and distribution
|
277
|
+
base_score = 0.5
|
278
|
+
|
279
|
+
# Adjust for utilization
|
280
|
+
utilization = calculate_utilization(stats)
|
281
|
+
utilization_bonus = case utilization
|
282
|
+
when 'empty' then -0.3
|
283
|
+
when 'low' then 0.0
|
284
|
+
when 'medium' then 0.2
|
285
|
+
when 'high' then 0.3
|
286
|
+
when 'very_high' then 0.1
|
287
|
+
end
|
288
|
+
|
289
|
+
# Adjust for distribution
|
290
|
+
distribution = calculate_distribution(stats)
|
291
|
+
distribution_bonus = case distribution
|
292
|
+
when 'even', 'balanced', 'uniform' then 0.2
|
293
|
+
when 'skewed', 'unbalanced', 'varied' then -0.1
|
294
|
+
else 0.0
|
295
|
+
end
|
296
|
+
|
297
|
+
[0.0, [1.0, base_score + utilization_bonus + distribution_bonus].min].max
|
298
|
+
end
|
299
|
+
|
300
|
+
# Generate recommendations for a registry
|
301
|
+
#
|
302
|
+
# @param registry [BaseRegistry] Registry to analyze
|
303
|
+
# @return [Array<String>] Recommendations
|
304
|
+
def generate_recommendations(registry)
|
305
|
+
recommendations = []
|
306
|
+
stats = registry.stats
|
307
|
+
|
308
|
+
# Health recommendations
|
309
|
+
recommendations << 'Registry health check failed - investigate immediately' unless registry.healthy?
|
310
|
+
|
311
|
+
# Utilization recommendations
|
312
|
+
utilization = calculate_utilization(stats)
|
313
|
+
case utilization
|
314
|
+
when 'empty'
|
315
|
+
recommendations << "Registry is empty - consider if it's needed"
|
316
|
+
when 'very_high'
|
317
|
+
recommendations << 'High utilization - monitor performance and consider optimization'
|
318
|
+
end
|
319
|
+
|
320
|
+
# Distribution recommendations
|
321
|
+
distribution = calculate_distribution(stats)
|
322
|
+
case distribution
|
323
|
+
when 'skewed', 'unbalanced'
|
324
|
+
recommendations << 'Uneven distribution detected - consider rebalancing'
|
325
|
+
end
|
326
|
+
|
327
|
+
recommendations.empty? ? ['Registry is operating optimally'] : recommendations
|
328
|
+
end
|
329
|
+
|
330
|
+
# Calculate aggregated metrics across all registries
|
331
|
+
#
|
332
|
+
# @param registries_stats [Hash] Statistics for all registries
|
333
|
+
# @return [Hash] Aggregated metrics
|
334
|
+
def calculate_aggregated_metrics(registries_stats)
|
335
|
+
total_items = 0
|
336
|
+
healthy_count = 0
|
337
|
+
efficiency_scores = []
|
338
|
+
|
339
|
+
registries_stats.each_value do |stats|
|
340
|
+
total_items += stats[:total_handlers] || stats[:total_plugins] || stats[:total_subscribers] || 0
|
341
|
+
healthy_count += 1 if stats[:health][:healthy]
|
342
|
+
efficiency_scores << stats[:usage_patterns][:efficiency_score]
|
343
|
+
end
|
344
|
+
|
345
|
+
{
|
346
|
+
total_registered_items: total_items,
|
347
|
+
overall_health_percentage: registries_stats.empty? ? 0 : (healthy_count.to_f / registries_stats.size * 100).round(1),
|
348
|
+
average_efficiency_score: efficiency_scores.empty? ? 0 : (efficiency_scores.sum / efficiency_scores.size).round(3),
|
349
|
+
registry_count: registries_stats.size
|
350
|
+
}
|
351
|
+
end
|
352
|
+
|
353
|
+
# Calculate item count for a registry
|
354
|
+
#
|
355
|
+
# @param registry [BaseRegistry] Registry to count items for
|
356
|
+
# @return [Integer] Total item count
|
357
|
+
def calculate_registry_item_count(registry)
|
358
|
+
stats = registry.stats
|
359
|
+
stats[:total_handlers] || stats[:total_plugins] || stats[:total_subscribers] || 0
|
360
|
+
end
|
361
|
+
|
362
|
+
# Calculate performance summary
|
363
|
+
#
|
364
|
+
# @param performance_data [Array<Hash>] Performance data for all registries
|
365
|
+
# @return [Hash] Performance summary
|
366
|
+
def calculate_performance_summary(performance_data)
|
367
|
+
response_times = performance_data.map { |data| data[:performance][:stats_response_time_ms] }
|
368
|
+
|
369
|
+
return { summary: 'no_data' } if response_times.empty?
|
370
|
+
|
371
|
+
{
|
372
|
+
average_response_time_ms: (response_times.sum / response_times.size).round(2),
|
373
|
+
max_response_time_ms: response_times.max,
|
374
|
+
min_response_time_ms: response_times.min,
|
375
|
+
total_items_managed: performance_data.sum { |data| data[:item_count] }
|
376
|
+
}
|
377
|
+
end
|
378
|
+
end
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
@@ -0,0 +1,285 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative 'base_registry'
|
5
|
+
require_relative 'interface_validator'
|
6
|
+
require 'concurrent-ruby'
|
7
|
+
|
8
|
+
module Tasker
|
9
|
+
module Registry
|
10
|
+
# Registry for managing event subscribers
|
11
|
+
#
|
12
|
+
# Provides centralized management of event subscribers with discovery,
|
13
|
+
# registration, and event-based lookup capabilities. Integrates with
|
14
|
+
# the existing event system to provide comprehensive subscriber coordination.
|
15
|
+
#
|
16
|
+
# @example Register a subscriber
|
17
|
+
# registry = Tasker::Registry::SubscriberRegistry.instance
|
18
|
+
# registry.register(MySubscriber, events: ['task.created', 'task.completed'])
|
19
|
+
#
|
20
|
+
# @example Find subscribers for an event
|
21
|
+
# subscribers = registry.subscribers_for_event('task.created')
|
22
|
+
#
|
23
|
+
# @example Auto-discover subscribers
|
24
|
+
# registry.auto_discover_subscribers
|
25
|
+
class SubscriberRegistry < BaseRegistry
|
26
|
+
include Singleton
|
27
|
+
|
28
|
+
def initialize
|
29
|
+
super
|
30
|
+
@subscribers = Concurrent::Hash.new
|
31
|
+
@event_mappings = Concurrent::Hash.new
|
32
|
+
log_registry_operation('initialized', total_subscribers: 0, total_events: 0)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Register an event subscriber
|
36
|
+
#
|
37
|
+
# @param subscriber_class [Class] The subscriber class to register
|
38
|
+
# @param events [Array<String>] Events this subscriber handles
|
39
|
+
# @param replace [Boolean] Whether to replace existing subscriber
|
40
|
+
# @param options [Hash] Additional registration options
|
41
|
+
# @return [Boolean] True if registration successful
|
42
|
+
# @raise [ArgumentError] If subscriber already exists and replace is false
|
43
|
+
def register(subscriber_class, events: [], replace: false, **options)
|
44
|
+
subscriber_name = subscriber_class.name.demodulize.underscore
|
45
|
+
|
46
|
+
thread_safe_operation do
|
47
|
+
# Validate subscriber interface
|
48
|
+
begin
|
49
|
+
Registry::InterfaceValidator.validate_subscriber!(subscriber_class)
|
50
|
+
rescue ArgumentError => e
|
51
|
+
log_validation_failure('event_subscriber', subscriber_name, e.message)
|
52
|
+
raise
|
53
|
+
end
|
54
|
+
|
55
|
+
# Check for existing subscriber
|
56
|
+
if @subscribers.key?(subscriber_name) && !replace
|
57
|
+
raise ArgumentError, "Subscriber '#{subscriber_name}' already registered. Use replace: true to override."
|
58
|
+
end
|
59
|
+
|
60
|
+
# Remove existing subscriber if replacing
|
61
|
+
if @subscribers.key?(subscriber_name)
|
62
|
+
existing_config = @subscribers[subscriber_name]
|
63
|
+
unregister_event_mappings(subscriber_name, existing_config[:events])
|
64
|
+
log_unregistration('event_subscriber', subscriber_name, existing_config[:subscriber_class])
|
65
|
+
end
|
66
|
+
|
67
|
+
# Register subscriber
|
68
|
+
subscriber_config = {
|
69
|
+
subscriber_class: subscriber_class,
|
70
|
+
events: events,
|
71
|
+
registered_at: Time.current,
|
72
|
+
options: options.merge(replace: replace)
|
73
|
+
}
|
74
|
+
|
75
|
+
@subscribers[subscriber_name] = subscriber_config
|
76
|
+
|
77
|
+
# Index by events
|
78
|
+
register_event_mappings(subscriber_name, events)
|
79
|
+
|
80
|
+
log_registration('event_subscriber', subscriber_name, subscriber_class,
|
81
|
+
{ events: events, event_count: events.size, **options })
|
82
|
+
|
83
|
+
true
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Unregister an event subscriber
|
88
|
+
#
|
89
|
+
# @param subscriber_class [Class, String] The subscriber class or name to unregister
|
90
|
+
# @return [Boolean] True if unregistered successfully
|
91
|
+
def unregister(subscriber_class)
|
92
|
+
subscriber_name = if subscriber_class.is_a?(Class)
|
93
|
+
subscriber_class.name.demodulize.underscore
|
94
|
+
else
|
95
|
+
subscriber_class.to_s
|
96
|
+
end
|
97
|
+
|
98
|
+
thread_safe_operation do
|
99
|
+
subscriber_config = @subscribers.delete(subscriber_name)
|
100
|
+
|
101
|
+
if subscriber_config
|
102
|
+
# Remove from event mappings
|
103
|
+
unregister_event_mappings(subscriber_name, subscriber_config[:events])
|
104
|
+
|
105
|
+
log_unregistration('event_subscriber', subscriber_name, subscriber_config[:subscriber_class])
|
106
|
+
true
|
107
|
+
else
|
108
|
+
false
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Get subscribers for a specific event
|
114
|
+
#
|
115
|
+
# @param event_name [String] The event name to find subscribers for
|
116
|
+
# @return [Array<Hash>] Array of subscriber configurations
|
117
|
+
def subscribers_for_event(event_name)
|
118
|
+
subscriber_names = @event_mappings[event_name.to_s] || []
|
119
|
+
subscriber_names.filter_map { |name| @subscribers[name] }
|
120
|
+
end
|
121
|
+
|
122
|
+
# Get all registered subscribers
|
123
|
+
#
|
124
|
+
# @return [Hash] All registered subscribers
|
125
|
+
def all_subscribers
|
126
|
+
@subscribers.dup
|
127
|
+
end
|
128
|
+
|
129
|
+
# Get all registered subscribers (required by BaseRegistry)
|
130
|
+
#
|
131
|
+
# @return [Hash] All registered subscribers
|
132
|
+
def all_items
|
133
|
+
all_subscribers
|
134
|
+
end
|
135
|
+
|
136
|
+
# Get supported events across all subscribers
|
137
|
+
#
|
138
|
+
# @return [Array<String>] Array of supported event names
|
139
|
+
def supported_events
|
140
|
+
@event_mappings.keys.sort
|
141
|
+
end
|
142
|
+
|
143
|
+
# Check if an event has any subscribers
|
144
|
+
#
|
145
|
+
# @param event_name [String] Event name to check
|
146
|
+
# @return [Boolean] True if event has subscribers
|
147
|
+
def has_subscribers?(event_name)
|
148
|
+
@event_mappings.key?(event_name.to_s) && !@event_mappings[event_name.to_s].empty?
|
149
|
+
end
|
150
|
+
|
151
|
+
# Auto-discover subscribers in the subscribers directory
|
152
|
+
#
|
153
|
+
# @param directory [String] Directory to search for subscribers
|
154
|
+
# @return [Integer] Number of subscribers discovered
|
155
|
+
def auto_discover_subscribers(directory = nil)
|
156
|
+
directory ||= File.join(File.dirname(__FILE__), '..', 'events', 'subscribers')
|
157
|
+
|
158
|
+
return 0 unless Dir.exist?(directory)
|
159
|
+
|
160
|
+
discovered_count = 0
|
161
|
+
|
162
|
+
Dir.glob(File.join(directory, '*_subscriber.rb')).each do |file|
|
163
|
+
require file
|
164
|
+
|
165
|
+
# Extract class name from filename
|
166
|
+
class_name = File.basename(file, '.rb').camelize
|
167
|
+
full_class_name = "Tasker::Events::Subscribers::#{class_name}"
|
168
|
+
|
169
|
+
begin
|
170
|
+
# Try to instantiate the subscriber
|
171
|
+
subscriber_class = full_class_name.constantize
|
172
|
+
|
173
|
+
# Auto-discover events from class methods or constants
|
174
|
+
events = discover_subscriber_events(subscriber_class)
|
175
|
+
|
176
|
+
register(subscriber_class, events: events, auto_discovered: true)
|
177
|
+
discovered_count += 1
|
178
|
+
|
179
|
+
log_registry_operation('auto_discovered_subscriber',
|
180
|
+
subscriber_name: subscriber_class.name,
|
181
|
+
events: events,
|
182
|
+
file_path: file)
|
183
|
+
rescue StandardError => e
|
184
|
+
log_registry_error('auto_discovery_failed', e,
|
185
|
+
file_path: file,
|
186
|
+
class_name: full_class_name)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
discovered_count
|
191
|
+
end
|
192
|
+
|
193
|
+
# Get comprehensive registry statistics
|
194
|
+
#
|
195
|
+
# @return [Hash] Detailed statistics about the registry
|
196
|
+
def stats
|
197
|
+
base_stats.merge(
|
198
|
+
total_subscribers: @subscribers.size,
|
199
|
+
total_events: @event_mappings.size,
|
200
|
+
events_covered: @event_mappings.keys.sort,
|
201
|
+
subscribers_by_event: @event_mappings.transform_values(&:size),
|
202
|
+
average_events_per_subscriber: calculate_average_events_per_subscriber,
|
203
|
+
most_popular_events: find_most_popular_events
|
204
|
+
)
|
205
|
+
end
|
206
|
+
|
207
|
+
# Clear all registered subscribers (required by BaseRegistry)
|
208
|
+
#
|
209
|
+
# @return [Boolean] True if cleared successfully
|
210
|
+
def clear!
|
211
|
+
thread_safe_operation do
|
212
|
+
@subscribers.clear
|
213
|
+
@event_mappings.clear
|
214
|
+
log_registry_operation('cleared_all')
|
215
|
+
true
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
private
|
220
|
+
|
221
|
+
# Register event mappings for a subscriber
|
222
|
+
#
|
223
|
+
# @param subscriber_name [String] Name of the subscriber
|
224
|
+
# @param events [Array<String>] Events to map
|
225
|
+
def register_event_mappings(subscriber_name, events)
|
226
|
+
events.each do |event|
|
227
|
+
event_key = event.to_s
|
228
|
+
@event_mappings[event_key] ||= []
|
229
|
+
@event_mappings[event_key] << subscriber_name unless @event_mappings[event_key].include?(subscriber_name)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# Unregister event mappings for a subscriber
|
234
|
+
#
|
235
|
+
# @param subscriber_name [String] Name of the subscriber
|
236
|
+
# @param events [Array<String>] Events to unmap
|
237
|
+
def unregister_event_mappings(subscriber_name, events)
|
238
|
+
events.each do |event|
|
239
|
+
event_key = event.to_s
|
240
|
+
@event_mappings[event_key]&.delete(subscriber_name)
|
241
|
+
@event_mappings.delete(event_key) if @event_mappings[event_key] && @event_mappings[event_key].empty?
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
# Discover events that a subscriber handles
|
246
|
+
#
|
247
|
+
# @param subscriber_class [Class] The subscriber class to analyze
|
248
|
+
# @return [Array<String>] Array of event names
|
249
|
+
def discover_subscriber_events(subscriber_class)
|
250
|
+
events = []
|
251
|
+
|
252
|
+
# Check for EVENTS constant
|
253
|
+
events.concat(Array(subscriber_class::EVENTS)) if subscriber_class.const_defined?(:EVENTS)
|
254
|
+
|
255
|
+
# Check for events class method
|
256
|
+
events.concat(Array(subscriber_class.events)) if subscriber_class.respond_to?(:events)
|
257
|
+
|
258
|
+
# Check for event_patterns class method
|
259
|
+
events.concat(Array(subscriber_class.event_patterns)) if subscriber_class.respond_to?(:event_patterns)
|
260
|
+
|
261
|
+
events.map(&:to_s).uniq
|
262
|
+
end
|
263
|
+
|
264
|
+
# Calculate average events per subscriber
|
265
|
+
#
|
266
|
+
# @return [Float] Average number of events per subscriber
|
267
|
+
def calculate_average_events_per_subscriber
|
268
|
+
return 0.0 if @subscribers.empty?
|
269
|
+
|
270
|
+
total_events = @subscribers.values.sum { |config| config[:events].size }
|
271
|
+
(total_events.to_f / @subscribers.size).round(2)
|
272
|
+
end
|
273
|
+
|
274
|
+
# Find the most popular events (top 5)
|
275
|
+
#
|
276
|
+
# @return [Array<Hash>] Array of event popularity data
|
277
|
+
def find_most_popular_events
|
278
|
+
@event_mappings
|
279
|
+
.map { |event, subscribers| { event: event, subscriber_count: subscribers.size } }
|
280
|
+
.sort_by { |data| -data[:subscriber_count] }
|
281
|
+
.first(5)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Registry module for Tasker
|
5
|
+
#
|
6
|
+
# Provides unified registry management with thread-safe operations,
|
7
|
+
# validation, observability, and coordination capabilities.
|
8
|
+
module Tasker
|
9
|
+
module Registry
|
10
|
+
# Registry-related errors
|
11
|
+
class RegistryError < StandardError; end
|
12
|
+
class ValidationError < RegistryError; end
|
13
|
+
class RegistrationError < RegistryError; end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Require all registry components
|
18
|
+
require_relative 'registry/base_registry'
|
19
|
+
require_relative 'registry/interface_validator'
|
20
|
+
require_relative 'registry/event_publisher'
|
21
|
+
require_relative 'registry/subscriber_registry'
|
22
|
+
require_relative 'registry/statistics_collector'
|