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.
Files changed (605) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +443 -0
  4. data/Rakefile +10 -0
  5. data/app/controllers/tasker/analytics_controller.rb +179 -0
  6. data/app/controllers/tasker/application_controller.rb +45 -0
  7. data/app/controllers/tasker/graphql_controller.rb +193 -0
  8. data/app/controllers/tasker/handlers_controller.rb +217 -0
  9. data/app/controllers/tasker/health_controller.rb +229 -0
  10. data/app/controllers/tasker/metrics_controller.rb +111 -0
  11. data/app/controllers/tasker/page_sort.rb +97 -0
  12. data/app/controllers/tasker/task_diagrams_controller.rb +30 -0
  13. data/app/controllers/tasker/tasks_controller.rb +123 -0
  14. data/app/controllers/tasker/workflow_steps_controller.rb +69 -0
  15. data/app/graphql/examples/all_tasks.graphql +22 -0
  16. data/app/graphql/examples/pending_tasks.graphql +23 -0
  17. data/app/graphql/tasker/graph_ql_types/annotation_type.rb +14 -0
  18. data/app/graphql/tasker/graph_ql_types/base_argument.rb +9 -0
  19. data/app/graphql/tasker/graph_ql_types/base_connection.rb +11 -0
  20. data/app/graphql/tasker/graph_ql_types/base_edge.rb +10 -0
  21. data/app/graphql/tasker/graph_ql_types/base_enum.rb +9 -0
  22. data/app/graphql/tasker/graph_ql_types/base_field.rb +10 -0
  23. data/app/graphql/tasker/graph_ql_types/base_input_object.rb +10 -0
  24. data/app/graphql/tasker/graph_ql_types/base_interface.rb +14 -0
  25. data/app/graphql/tasker/graph_ql_types/base_object.rb +10 -0
  26. data/app/graphql/tasker/graph_ql_types/base_scalar.rb +9 -0
  27. data/app/graphql/tasker/graph_ql_types/base_union.rb +11 -0
  28. data/app/graphql/tasker/graph_ql_types/dependent_system_object_map_type.rb +18 -0
  29. data/app/graphql/tasker/graph_ql_types/dependent_system_type.rb +13 -0
  30. data/app/graphql/tasker/graph_ql_types/mutation_type.rb +16 -0
  31. data/app/graphql/tasker/graph_ql_types/named_step_type.rb +16 -0
  32. data/app/graphql/tasker/graph_ql_types/named_task_type.rb +14 -0
  33. data/app/graphql/tasker/graph_ql_types/named_tasks_named_step_type.rb +19 -0
  34. data/app/graphql/tasker/graph_ql_types/node_type.rb +12 -0
  35. data/app/graphql/tasker/graph_ql_types/query_type.rb +20 -0
  36. data/app/graphql/tasker/graph_ql_types/task_annotation_type.rb +17 -0
  37. data/app/graphql/tasker/graph_ql_types/task_interface.rb +17 -0
  38. data/app/graphql/tasker/graph_ql_types/task_type.rb +26 -0
  39. data/app/graphql/tasker/graph_ql_types/workflow_step_type.rb +154 -0
  40. data/app/graphql/tasker/graph_ql_types.rb +42 -0
  41. data/app/graphql/tasker/mutations/base_mutation.rb +13 -0
  42. data/app/graphql/tasker/mutations/cancel_step.rb +29 -0
  43. data/app/graphql/tasker/mutations/cancel_task.rb +29 -0
  44. data/app/graphql/tasker/mutations/create_task.rb +52 -0
  45. data/app/graphql/tasker/mutations/update_step.rb +36 -0
  46. data/app/graphql/tasker/mutations/update_task.rb +41 -0
  47. data/app/graphql/tasker/queries/all_annotation_types.rb +17 -0
  48. data/app/graphql/tasker/queries/all_tasks.rb +23 -0
  49. data/app/graphql/tasker/queries/base_query.rb +9 -0
  50. data/app/graphql/tasker/queries/helpers.rb +16 -0
  51. data/app/graphql/tasker/queries/one_step.rb +24 -0
  52. data/app/graphql/tasker/queries/one_task.rb +18 -0
  53. data/app/graphql/tasker/queries/tasks_by_annotation.rb +31 -0
  54. data/app/graphql/tasker/queries/tasks_by_status.rb +30 -0
  55. data/app/graphql/tasker/tasker_rails_schema.rb +52 -0
  56. data/app/jobs/tasker/application_job.rb +8 -0
  57. data/app/jobs/tasker/metrics_export_job.rb +252 -0
  58. data/app/jobs/tasker/task_runner_job.rb +224 -0
  59. data/app/models/tasker/annotation_type.rb +26 -0
  60. data/app/models/tasker/application_record.rb +70 -0
  61. data/app/models/tasker/dependent_system.rb +26 -0
  62. data/app/models/tasker/dependent_system_object_map.rb +64 -0
  63. data/app/models/tasker/diagram/edge.rb +106 -0
  64. data/app/models/tasker/diagram/flowchart.rb +137 -0
  65. data/app/models/tasker/diagram/node.rb +99 -0
  66. data/app/models/tasker/named_step.rb +41 -0
  67. data/app/models/tasker/named_task.rb +121 -0
  68. data/app/models/tasker/named_tasks_named_step.rb +82 -0
  69. data/app/models/tasker/step_dag_relationship.rb +65 -0
  70. data/app/models/tasker/step_readiness_status.rb +59 -0
  71. data/app/models/tasker/task.rb +424 -0
  72. data/app/models/tasker/task_annotation.rb +36 -0
  73. data/app/models/tasker/task_diagram.rb +332 -0
  74. data/app/models/tasker/task_execution_context.rb +29 -0
  75. data/app/models/tasker/task_namespace.rb +41 -0
  76. data/app/models/tasker/task_transition.rb +235 -0
  77. data/app/models/tasker/workflow_step.rb +461 -0
  78. data/app/models/tasker/workflow_step_edge.rb +94 -0
  79. data/app/models/tasker/workflow_step_transition.rb +434 -0
  80. data/app/serializers/tasker/annotation_type_serializer.rb +8 -0
  81. data/app/serializers/tasker/handler_serializer.rb +109 -0
  82. data/app/serializers/tasker/task_annotation_serializer.rb +32 -0
  83. data/app/serializers/tasker/task_serializer.rb +168 -0
  84. data/app/serializers/tasker/workflow_step_serializer.rb +27 -0
  85. data/app/services/tasker/analytics_service.rb +409 -0
  86. data/app/views/tasker/task/_diagram.html.erb +32 -0
  87. data/config/initializers/dry_struct.rb +11 -0
  88. data/config/initializers/statesman.rb +6 -0
  89. data/config/initializers/tasker_orchestration.rb +17 -0
  90. data/config/initializers/time_formats.rb +4 -0
  91. data/config/routes.rb +34 -0
  92. data/config/tasker/subscriptions/example_integrations.yml +67 -0
  93. data/config/tasker/system_events.yml +305 -0
  94. data/db/functions/calculate_dependency_levels_v01.sql +45 -0
  95. data/db/functions/get_analytics_metrics_v01.sql +137 -0
  96. data/db/functions/get_slowest_steps_v01.sql +82 -0
  97. data/db/functions/get_slowest_tasks_v01.sql +96 -0
  98. data/db/functions/get_step_readiness_status_batch_v01.sql +140 -0
  99. data/db/functions/get_step_readiness_status_v01.sql +139 -0
  100. data/db/functions/get_system_health_counts_v01.sql +108 -0
  101. data/db/functions/get_task_execution_context_v01.sql +108 -0
  102. data/db/functions/get_task_execution_contexts_batch_v01.sql +104 -0
  103. data/db/init/schema.sql +2277 -0
  104. data/db/migrate/20250701165431_initial_tasker_schema.rb +116 -0
  105. data/db/views/tasker_step_dag_relationships_v01.sql +69 -0
  106. data/docs/APPLICATION_GENERATOR.md +384 -0
  107. data/docs/AUTH.md +1780 -0
  108. data/docs/CIRCUIT_BREAKER.md +224 -0
  109. data/docs/DEVELOPER_GUIDE.md +2665 -0
  110. data/docs/EVENT_SYSTEM.md +637 -0
  111. data/docs/EXECUTION_CONFIGURATION.md +341 -0
  112. data/docs/FLOW_CHART.md +149 -0
  113. data/docs/HEALTH.md +542 -0
  114. data/docs/METRICS.md +731 -0
  115. data/docs/OPTIMIZATION_PLAN.md +1479 -0
  116. data/docs/OVERVIEW.md +552 -0
  117. data/docs/QUICK_START.md +270 -0
  118. data/docs/REGISTRY_SYSTEMS.md +373 -0
  119. data/docs/REST_API.md +632 -0
  120. data/docs/ROADMAP.md +221 -0
  121. data/docs/SQL_FUNCTIONS.md +1408 -0
  122. data/docs/TASK_DIAGRAM.md +252 -0
  123. data/docs/TASK_EXECUTION_CONTROL_FLOW.md +237 -0
  124. data/docs/TELEMETRY.md +795 -0
  125. data/docs/TROUBLESHOOTING.md +756 -0
  126. data/docs/TaskHandlerGenerator.html +255 -0
  127. data/docs/Tasker/Analysis/RuntimeGraphAnalyzer.html +907 -0
  128. data/docs/Tasker/Analysis/TemplateGraphAnalyzer.html +1236 -0
  129. data/docs/Tasker/Analysis.html +117 -0
  130. data/docs/Tasker/AnalyticsController.html +450 -0
  131. data/docs/Tasker/AnalyticsService/BottleneckAnalytics.html +816 -0
  132. data/docs/Tasker/AnalyticsService/PerformanceAnalytics.html +586 -0
  133. data/docs/Tasker/AnalyticsService.html +2221 -0
  134. data/docs/Tasker/AnnotationType.html +137 -0
  135. data/docs/Tasker/AnnotationTypeSerializer.html +124 -0
  136. data/docs/Tasker/ApplicationController.html +147 -0
  137. data/docs/Tasker/ApplicationJob.html +128 -0
  138. data/docs/Tasker/ApplicationRecord.html +378 -0
  139. data/docs/Tasker/Authentication/AuthenticationError.html +124 -0
  140. data/docs/Tasker/Authentication/ConfigurationError.html +124 -0
  141. data/docs/Tasker/Authentication/Coordinator.html +242 -0
  142. data/docs/Tasker/Authentication/Interface.html +560 -0
  143. data/docs/Tasker/Authentication/InterfaceError.html +124 -0
  144. data/docs/Tasker/Authentication/NoneAuthenticator.html +338 -0
  145. data/docs/Tasker/Authentication.html +119 -0
  146. data/docs/Tasker/Authorization/AuthorizationError.html +139 -0
  147. data/docs/Tasker/Authorization/BaseCoordinator.html +927 -0
  148. data/docs/Tasker/Authorization/ConfigurationError.html +153 -0
  149. data/docs/Tasker/Authorization/ResourceConstants/ACTIONS.html +428 -0
  150. data/docs/Tasker/Authorization/ResourceConstants/RESOURCES.html +365 -0
  151. data/docs/Tasker/Authorization/ResourceConstants.html +146 -0
  152. data/docs/Tasker/Authorization/ResourceRegistry.html +882 -0
  153. data/docs/Tasker/Authorization/UnauthorizedError.html +153 -0
  154. data/docs/Tasker/Authorization.html +582 -0
  155. data/docs/Tasker/CacheCapabilities.html +167 -0
  156. data/docs/Tasker/CacheStrategy.html +1297 -0
  157. data/docs/Tasker/Concerns/Authenticatable.html +116 -0
  158. data/docs/Tasker/Concerns/Authorizable/AdminStatusChecker.html +256 -0
  159. data/docs/Tasker/Concerns/Authorizable.html +816 -0
  160. data/docs/Tasker/Concerns/ControllerAuthorizable.html +157 -0
  161. data/docs/Tasker/Concerns/EventPublisher.html +4023 -0
  162. data/docs/Tasker/Concerns/IdempotentStateTransitions.html +806 -0
  163. data/docs/Tasker/Concerns/LifecycleEventHelpers.html +129 -0
  164. data/docs/Tasker/Concerns/OrchestrationPublisher.html +129 -0
  165. data/docs/Tasker/Concerns/StateMachineBase/ClassMethods.html +1075 -0
  166. data/docs/Tasker/Concerns/StateMachineBase/StateMachineBase/ClassMethods.html +191 -0
  167. data/docs/Tasker/Concerns/StateMachineBase/StateMachineBase.html +126 -0
  168. data/docs/Tasker/Concerns/StateMachineBase.html +153 -0
  169. data/docs/Tasker/Concerns/StructuredLogging.html +1413 -0
  170. data/docs/Tasker/Concerns.html +117 -0
  171. data/docs/Tasker/Configuration/AuthConfiguration.html +1023 -0
  172. data/docs/Tasker/Configuration/ConfigurationProxy.html +581 -0
  173. data/docs/Tasker/Configuration/DatabaseConfiguration.html +475 -0
  174. data/docs/Tasker/Configuration/EngineConfiguration.html +1265 -0
  175. data/docs/Tasker/Configuration/HealthConfiguration.html +791 -0
  176. data/docs/Tasker/Configuration/TelemetryConfiguration.html +1308 -0
  177. data/docs/Tasker/Configuration/TelemetryConfigurationProxy.html +388 -0
  178. data/docs/Tasker/Configuration.html +1669 -0
  179. data/docs/Tasker/ConfigurationError.html +143 -0
  180. data/docs/Tasker/ConfiguredTask.html +514 -0
  181. data/docs/Tasker/Constants/EventDefinitions.html +590 -0
  182. data/docs/Tasker/Constants/LifecycleEvents.html +137 -0
  183. data/docs/Tasker/Constants/ObservabilityEvents/Step.html +152 -0
  184. data/docs/Tasker/Constants/ObservabilityEvents/Task.html +142 -0
  185. data/docs/Tasker/Constants/ObservabilityEvents.html +126 -0
  186. data/docs/Tasker/Constants/RegistryEvents.html +285 -0
  187. data/docs/Tasker/Constants/StepEvents.html +177 -0
  188. data/docs/Tasker/Constants/TaskEvents.html +167 -0
  189. data/docs/Tasker/Constants/TaskExecution/ExecutionStatus.html +207 -0
  190. data/docs/Tasker/Constants/TaskExecution/HealthStatus.html +191 -0
  191. data/docs/Tasker/Constants/TaskExecution/RecommendedAction.html +207 -0
  192. data/docs/Tasker/Constants/TaskExecution.html +126 -0
  193. data/docs/Tasker/Constants/TaskFinalization/ErrorMessages.html +132 -0
  194. data/docs/Tasker/Constants/TaskFinalization/PendingReasons.html +207 -0
  195. data/docs/Tasker/Constants/TaskFinalization/ReenqueueReasons.html +239 -0
  196. data/docs/Tasker/Constants/TaskFinalization.html +126 -0
  197. data/docs/Tasker/Constants/TaskStatuses.html +223 -0
  198. data/docs/Tasker/Constants/TestEvents.html +163 -0
  199. data/docs/Tasker/Constants/WorkflowEvents.html +222 -0
  200. data/docs/Tasker/Constants/WorkflowStepStatuses.html +223 -0
  201. data/docs/Tasker/Constants.html +561 -0
  202. data/docs/Tasker/DependentSystem.html +137 -0
  203. data/docs/Tasker/DependentSystemObjectMap.html +250 -0
  204. data/docs/Tasker/DetectorRegistry.html +598 -0
  205. data/docs/Tasker/Diagram/Edge.html +1191 -0
  206. data/docs/Tasker/Diagram/Flowchart.html +1539 -0
  207. data/docs/Tasker/Diagram/Node.html +1165 -0
  208. data/docs/Tasker/Diagram.html +117 -0
  209. data/docs/Tasker/Engine.html +215 -0
  210. data/docs/Tasker/Error.html +139 -0
  211. data/docs/Tasker/Events/Bus.html +1226 -0
  212. data/docs/Tasker/Events/Catalog/CatalogPrinter.html +258 -0
  213. data/docs/Tasker/Events/Catalog/CustomEventRegistrar.html +276 -0
  214. data/docs/Tasker/Events/Catalog/ExamplePayloadGenerator.html +294 -0
  215. data/docs/Tasker/Events/Catalog.html +1291 -0
  216. data/docs/Tasker/Events/CustomRegistry.html +943 -0
  217. data/docs/Tasker/Events/DefinitionLoader.html +575 -0
  218. data/docs/Tasker/Events/EventPayloadBuilder/ErrorInfoExtractor.html +286 -0
  219. data/docs/Tasker/Events/EventPayloadBuilder/StepPayloadBuilder.html +312 -0
  220. data/docs/Tasker/Events/EventPayloadBuilder.html +664 -0
  221. data/docs/Tasker/Events/Publisher.html +365 -0
  222. data/docs/Tasker/Events/Subscribers/BaseSubscriber/ErrorCategorizer/ErrorTypeClassifier.html +1128 -0
  223. data/docs/Tasker/Events/Subscribers/BaseSubscriber/ErrorCategorizer.html +270 -0
  224. data/docs/Tasker/Events/Subscribers/BaseSubscriber/MetricTagsExtractor.html +266 -0
  225. data/docs/Tasker/Events/Subscribers/BaseSubscriber.html +2556 -0
  226. data/docs/Tasker/Events/Subscribers/MetricsSubscriber.html +723 -0
  227. data/docs/Tasker/Events/Subscribers/TelemetrySubscriber.html +2251 -0
  228. data/docs/Tasker/Events/Subscribers.html +117 -0
  229. data/docs/Tasker/Events/SubscriptionLoader.html +493 -0
  230. data/docs/Tasker/Events.html +294 -0
  231. data/docs/Tasker/EventsGenerator.html +459 -0
  232. data/docs/Tasker/Functions/FunctionBasedAnalyticsMetrics/AnalyticsMetrics.html +135 -0
  233. data/docs/Tasker/Functions/FunctionBasedAnalyticsMetrics.html +412 -0
  234. data/docs/Tasker/Functions/FunctionBasedDependencyLevels.html +598 -0
  235. data/docs/Tasker/Functions/FunctionBasedSlowestSteps/SlowestStep.html +135 -0
  236. data/docs/Tasker/Functions/FunctionBasedSlowestSteps.html +453 -0
  237. data/docs/Tasker/Functions/FunctionBasedSlowestTasks/SlowestTask.html +135 -0
  238. data/docs/Tasker/Functions/FunctionBasedSlowestTasks.html +453 -0
  239. data/docs/Tasker/Functions/FunctionBasedStepReadinessStatus.html +1457 -0
  240. data/docs/Tasker/Functions/FunctionBasedSystemHealthCounts/HealthMetrics.html +135 -0
  241. data/docs/Tasker/Functions/FunctionBasedSystemHealthCounts.html +370 -0
  242. data/docs/Tasker/Functions/FunctionBasedTaskExecutionContext.html +1250 -0
  243. data/docs/Tasker/Functions/FunctionWrapper.html +479 -0
  244. data/docs/Tasker/Functions.html +117 -0
  245. data/docs/Tasker/Generators/AuthenticatorGenerator/UsageInstructionsFormatter.html +244 -0
  246. data/docs/Tasker/Generators/AuthenticatorGenerator.html +373 -0
  247. data/docs/Tasker/Generators/AuthorizationCoordinatorGenerator.html +430 -0
  248. data/docs/Tasker/Generators/SubscriberGenerator.html +377 -0
  249. data/docs/Tasker/Generators/TaskHandlerGenerator.html +263 -0
  250. data/docs/Tasker/Generators.html +117 -0
  251. data/docs/Tasker/GraphQLTypes/AnnotationType.html +132 -0
  252. data/docs/Tasker/GraphQLTypes/BaseArgument.html +124 -0
  253. data/docs/Tasker/GraphQLTypes/BaseConnection.html +124 -0
  254. data/docs/Tasker/GraphQLTypes/BaseEdge.html +130 -0
  255. data/docs/Tasker/GraphQLTypes/BaseEnum.html +124 -0
  256. data/docs/Tasker/GraphQLTypes/BaseField.html +124 -0
  257. data/docs/Tasker/GraphQLTypes/BaseInputObject.html +124 -0
  258. data/docs/Tasker/GraphQLTypes/BaseInterface.html +116 -0
  259. data/docs/Tasker/GraphQLTypes/BaseObject.html +128 -0
  260. data/docs/Tasker/GraphQLTypes/BaseScalar.html +124 -0
  261. data/docs/Tasker/GraphQLTypes/BaseUnion.html +124 -0
  262. data/docs/Tasker/GraphQLTypes/DependentSystemObjectMapType.html +132 -0
  263. data/docs/Tasker/GraphQLTypes/DependentSystemType.html +132 -0
  264. data/docs/Tasker/GraphQLTypes/MutationType.html +132 -0
  265. data/docs/Tasker/GraphQLTypes/NamedStepType.html +132 -0
  266. data/docs/Tasker/GraphQLTypes/NamedTaskType.html +132 -0
  267. data/docs/Tasker/GraphQLTypes/NamedTasksNamedStepType.html +132 -0
  268. data/docs/Tasker/GraphQLTypes/NodeType.html +118 -0
  269. data/docs/Tasker/GraphQLTypes/QueryType.html +139 -0
  270. data/docs/Tasker/GraphQLTypes/TaskAnnotationType.html +132 -0
  271. data/docs/Tasker/GraphQLTypes/TaskInterface.html +111 -0
  272. data/docs/Tasker/GraphQLTypes/TaskType.html +201 -0
  273. data/docs/Tasker/GraphQLTypes/WorkflowStepType.html +694 -0
  274. data/docs/Tasker/GraphQLTypes.html +130 -0
  275. data/docs/Tasker/GraphqlController.html +251 -0
  276. data/docs/Tasker/HandlerFactory.html +1518 -0
  277. data/docs/Tasker/HandlerSerializer.html +682 -0
  278. data/docs/Tasker/HandlersController.html +574 -0
  279. data/docs/Tasker/HashIdentityStrategy.html +278 -0
  280. data/docs/Tasker/Health/ReadinessChecker.html +712 -0
  281. data/docs/Tasker/Health/StatusChecker.html +653 -0
  282. data/docs/Tasker/Health.html +117 -0
  283. data/docs/Tasker/HealthController.html +523 -0
  284. data/docs/Tasker/IdentityStrategy.html +276 -0
  285. data/docs/Tasker/InvalidTaskHandlerConfig.html +135 -0
  286. data/docs/Tasker/LifecycleEvents/Events/Step.html +162 -0
  287. data/docs/Tasker/LifecycleEvents/Events/Task.html +162 -0
  288. data/docs/Tasker/LifecycleEvents/Events.html +204 -0
  289. data/docs/Tasker/LifecycleEvents/Publisher.html +132 -0
  290. data/docs/Tasker/LifecycleEvents.html +799 -0
  291. data/docs/Tasker/Logging/CorrelationIdGenerator.html +688 -0
  292. data/docs/Tasker/Logging.html +115 -0
  293. data/docs/Tasker/MetricsController.html +293 -0
  294. data/docs/Tasker/MetricsExportJob.html +414 -0
  295. data/docs/Tasker/Mutations/BaseMutation.html +128 -0
  296. data/docs/Tasker/Mutations/CancelStep.html +219 -0
  297. data/docs/Tasker/Mutations/CancelTask.html +221 -0
  298. data/docs/Tasker/Mutations/CreateTask.html +243 -0
  299. data/docs/Tasker/Mutations/UpdateStep.html +243 -0
  300. data/docs/Tasker/Mutations/UpdateTask.html +243 -0
  301. data/docs/Tasker/Mutations.html +117 -0
  302. data/docs/Tasker/NamedStep.html +216 -0
  303. data/docs/Tasker/NamedTask.html +910 -0
  304. data/docs/Tasker/NamedTasksNamedStep.html +435 -0
  305. data/docs/Tasker/Orchestration/BackoffCalculator.html +404 -0
  306. data/docs/Tasker/Orchestration/ConnectionBuilder/ConfigValidator.html +258 -0
  307. data/docs/Tasker/Orchestration/ConnectionBuilder.html +435 -0
  308. data/docs/Tasker/Orchestration/ConnectionPoolIntelligence.html +513 -0
  309. data/docs/Tasker/Orchestration/Coordinator.html +641 -0
  310. data/docs/Tasker/Orchestration/FutureStateAnalyzer.html +1045 -0
  311. data/docs/Tasker/Orchestration/Orchestrator.html +679 -0
  312. data/docs/Tasker/Orchestration/PluginIntegration.html +1127 -0
  313. data/docs/Tasker/Orchestration/ResponseProcessor.html +504 -0
  314. data/docs/Tasker/Orchestration/RetryHeaderParser.html +304 -0
  315. data/docs/Tasker/Orchestration/StepExecutor.html +995 -0
  316. data/docs/Tasker/Orchestration/StepSequenceFactory.html +644 -0
  317. data/docs/Tasker/Orchestration/TaskFinalizer/BlockageChecker.html +264 -0
  318. data/docs/Tasker/Orchestration/TaskFinalizer/ContextManager.html +254 -0
  319. data/docs/Tasker/Orchestration/TaskFinalizer/DelayCalculator.html +556 -0
  320. data/docs/Tasker/Orchestration/TaskFinalizer/FinalizationDecisionMaker.html +348 -0
  321. data/docs/Tasker/Orchestration/TaskFinalizer/FinalizationProcessor.html +286 -0
  322. data/docs/Tasker/Orchestration/TaskFinalizer/ReasonDeterminer.html +432 -0
  323. data/docs/Tasker/Orchestration/TaskFinalizer/ReenqueueManager.html +296 -0
  324. data/docs/Tasker/Orchestration/TaskFinalizer/UnclearStateHandler.html +314 -0
  325. data/docs/Tasker/Orchestration/TaskFinalizer.html +1212 -0
  326. data/docs/Tasker/Orchestration/TaskInitializer.html +766 -0
  327. data/docs/Tasker/Orchestration/TaskReenqueuer.html +506 -0
  328. data/docs/Tasker/Orchestration/ViableStepDiscovery.html +442 -0
  329. data/docs/Tasker/Orchestration/WorkflowCoordinator.html +510 -0
  330. data/docs/Tasker/Orchestration.html +130 -0
  331. data/docs/Tasker/PageSort/PageSortParamsBuilder.html +296 -0
  332. data/docs/Tasker/PageSort.html +247 -0
  333. data/docs/Tasker/PermanentError.html +518 -0
  334. data/docs/Tasker/ProceduralError.html +147 -0
  335. data/docs/Tasker/Queries/AllAnnotationTypes.html +217 -0
  336. data/docs/Tasker/Queries/AllTasks.html +221 -0
  337. data/docs/Tasker/Queries/BaseQuery.html +128 -0
  338. data/docs/Tasker/Queries/Helpers.html +187 -0
  339. data/docs/Tasker/Queries/OneStep.html +225 -0
  340. data/docs/Tasker/Queries/OneTask.html +217 -0
  341. data/docs/Tasker/Queries/TasksByAnnotation.html +231 -0
  342. data/docs/Tasker/Queries/TasksByStatus.html +233 -0
  343. data/docs/Tasker/Queries.html +119 -0
  344. data/docs/Tasker/Railtie.html +124 -0
  345. data/docs/Tasker/Registry/BaseRegistry.html +1690 -0
  346. data/docs/Tasker/Registry/EventPublisher.html +667 -0
  347. data/docs/Tasker/Registry/InterfaceValidator.html +569 -0
  348. data/docs/Tasker/Registry/RegistrationError.html +132 -0
  349. data/docs/Tasker/Registry/RegistryError.html +139 -0
  350. data/docs/Tasker/Registry/StatisticsCollector.html +841 -0
  351. data/docs/Tasker/Registry/SubscriberRegistry.html +1504 -0
  352. data/docs/Tasker/Registry/ValidationError.html +132 -0
  353. data/docs/Tasker/Registry.html +119 -0
  354. data/docs/Tasker/RetryableError.html +515 -0
  355. data/docs/Tasker/StateMachine/Compatibility.html +282 -0
  356. data/docs/Tasker/StateMachine/InvalidStateTransition.html +135 -0
  357. data/docs/Tasker/StateMachine/StepStateMachine/StandardizedPayloadBuilder.html +260 -0
  358. data/docs/Tasker/StateMachine/StepStateMachine.html +2215 -0
  359. data/docs/Tasker/StateMachine/TaskStateMachine.html +734 -0
  360. data/docs/Tasker/StateMachine.html +602 -0
  361. data/docs/Tasker/StepDagRelationship.html +657 -0
  362. data/docs/Tasker/StepHandler/Api/Config.html +1091 -0
  363. data/docs/Tasker/StepHandler/Api.html +884 -0
  364. data/docs/Tasker/StepHandler/AutomaticEventPublishing.html +321 -0
  365. data/docs/Tasker/StepHandler/Base.html +970 -0
  366. data/docs/Tasker/StepHandler.html +119 -0
  367. data/docs/Tasker/StepReadinessStatus.html +836 -0
  368. data/docs/Tasker/Task.html +2575 -0
  369. data/docs/Tasker/TaskAnnotation.html +137 -0
  370. data/docs/Tasker/TaskAnnotationSerializer.html +124 -0
  371. data/docs/Tasker/TaskBuilder/StepNameValidator.html +264 -0
  372. data/docs/Tasker/TaskBuilder/StepTemplateDefiner.html +264 -0
  373. data/docs/Tasker/TaskBuilder.html +764 -0
  374. data/docs/Tasker/TaskDiagram/StepToStepEdgeBuilder.html +260 -0
  375. data/docs/Tasker/TaskDiagram/TaskToRootStepEdgeBuilder.html +290 -0
  376. data/docs/Tasker/TaskDiagram.html +548 -0
  377. data/docs/Tasker/TaskDiagramsController.html +240 -0
  378. data/docs/Tasker/TaskExecutionContext.html +469 -0
  379. data/docs/Tasker/TaskHandler/ClassMethods/StepTemplateDefiner/ClassBasedEventRegistrar.html +238 -0
  380. data/docs/Tasker/TaskHandler/ClassMethods/StepTemplateDefiner/YamlEventRegistrar.html +254 -0
  381. data/docs/Tasker/TaskHandler/ClassMethods/StepTemplateDefiner.html +988 -0
  382. data/docs/Tasker/TaskHandler/ClassMethods.html +357 -0
  383. data/docs/Tasker/TaskHandler/InstanceMethods.html +1396 -0
  384. data/docs/Tasker/TaskHandler/StepGroup.html +1748 -0
  385. data/docs/Tasker/TaskHandler.html +271 -0
  386. data/docs/Tasker/TaskNamespace.html +312 -0
  387. data/docs/Tasker/TaskRunnerJob.html +406 -0
  388. data/docs/Tasker/TaskSerializer.html +474 -0
  389. data/docs/Tasker/TaskTransition.html +1517 -0
  390. data/docs/Tasker/TaskWorkflowSummary.html +988 -0
  391. data/docs/Tasker/TaskerRailsSchema/InvalidObjectTypeError.html +132 -0
  392. data/docs/Tasker/TaskerRailsSchema/TypeResolutionError.html +139 -0
  393. data/docs/Tasker/TaskerRailsSchema/UnknownInterfaceError.html +132 -0
  394. data/docs/Tasker/TaskerRailsSchema.html +384 -0
  395. data/docs/Tasker/TasksController.html +595 -0
  396. data/docs/Tasker/Telemetry/EventMapping.html +1307 -0
  397. data/docs/Tasker/Telemetry/EventRouter.html +2178 -0
  398. data/docs/Tasker/Telemetry/Events/ExportEvents.html +246 -0
  399. data/docs/Tasker/Telemetry/Events.html +115 -0
  400. data/docs/Tasker/Telemetry/ExportCoordinator/DistributedLockTimeoutError.html +135 -0
  401. data/docs/Tasker/Telemetry/ExportCoordinator.html +2137 -0
  402. data/docs/Tasker/Telemetry/IntelligentCacheManager.html +1083 -0
  403. data/docs/Tasker/Telemetry/LogBackend.html +1088 -0
  404. data/docs/Tasker/Telemetry/MetricTypes/Counter.html +1054 -0
  405. data/docs/Tasker/Telemetry/MetricTypes/Gauge.html +1270 -0
  406. data/docs/Tasker/Telemetry/MetricTypes/Histogram.html +1492 -0
  407. data/docs/Tasker/Telemetry/MetricTypes.html +153 -0
  408. data/docs/Tasker/Telemetry/MetricsBackend.html +2510 -0
  409. data/docs/Tasker/Telemetry/MetricsExportService.html +578 -0
  410. data/docs/Tasker/Telemetry/PluginRegistry.html +1774 -0
  411. data/docs/Tasker/Telemetry/Plugins/BaseExporter.html +1835 -0
  412. data/docs/Tasker/Telemetry/Plugins/CsvExporter.html +768 -0
  413. data/docs/Tasker/Telemetry/Plugins/JsonExporter.html +747 -0
  414. data/docs/Tasker/Telemetry/Plugins.html +117 -0
  415. data/docs/Tasker/Telemetry/PrometheusExporter.html +481 -0
  416. data/docs/Tasker/Telemetry/TraceBackend.html +891 -0
  417. data/docs/Tasker/Telemetry.html +130 -0
  418. data/docs/Tasker/Types/AuthConfig.html +886 -0
  419. data/docs/Tasker/Types/BackoffConfig.html +1063 -0
  420. data/docs/Tasker/Types/BaseConfig.html +227 -0
  421. data/docs/Tasker/Types/CacheConfig.html +1731 -0
  422. data/docs/Tasker/Types/DatabaseConfig.html +388 -0
  423. data/docs/Tasker/Types/DependencyGraph.html +526 -0
  424. data/docs/Tasker/Types/DependencyGraphConfig.html +753 -0
  425. data/docs/Tasker/Types/EngineConfig.html +1181 -0
  426. data/docs/Tasker/Types/ExecutionConfig.html +1963 -0
  427. data/docs/Tasker/Types/GraphEdge.html +517 -0
  428. data/docs/Tasker/Types/GraphMetadata.html +781 -0
  429. data/docs/Tasker/Types/GraphNode.html +694 -0
  430. data/docs/Tasker/Types/HealthConfig.html +784 -0
  431. data/docs/Tasker/Types/StepSequence.html +353 -0
  432. data/docs/Tasker/Types/StepTemplate.html +1193 -0
  433. data/docs/Tasker/Types/TaskRequest.html +1179 -0
  434. data/docs/Tasker/Types/TelemetryConfig.html +2746 -0
  435. data/docs/Tasker/Types.html +154 -0
  436. data/docs/Tasker/WorkflowStep/StepFinder.html +282 -0
  437. data/docs/Tasker/WorkflowStep.html +2724 -0
  438. data/docs/Tasker/WorkflowStepEdge.html +304 -0
  439. data/docs/Tasker/WorkflowStepSerializer.html +305 -0
  440. data/docs/Tasker/WorkflowStepTransition/TransitionDescriptionFormatter.html +282 -0
  441. data/docs/Tasker/WorkflowStepTransition.html +2201 -0
  442. data/docs/Tasker/WorkflowStepsController.html +462 -0
  443. data/docs/Tasker.html +452 -0
  444. data/docs/VISION.md +584 -0
  445. data/docs/WHY.md +21 -0
  446. data/docs/_index.html +2375 -0
  447. data/docs/class_list.html +54 -0
  448. data/docs/css/common.css +1 -0
  449. data/docs/css/full_list.css +58 -0
  450. data/docs/css/style.css +503 -0
  451. data/docs/events/migration_plan_outcomes.md +80 -0
  452. data/docs/file.README.html +541 -0
  453. data/docs/file_list.html +59 -0
  454. data/docs/frames.html +22 -0
  455. data/docs/index.html +541 -0
  456. data/docs/js/app.js +344 -0
  457. data/docs/js/full_list.js +242 -0
  458. data/docs/js/jquery.js +4 -0
  459. data/docs/method_list.html +9182 -0
  460. data/docs/top-level-namespace.html +110 -0
  461. data/lib/generators/tasker/authenticator_generator.rb +301 -0
  462. data/lib/generators/tasker/authorization_coordinator_generator.rb +139 -0
  463. data/lib/generators/tasker/events_generator.rb +91 -0
  464. data/lib/generators/tasker/subscriber_generator.rb +107 -0
  465. data/lib/generators/tasker/task_handler_generator.rb +138 -0
  466. data/lib/generators/tasker/templates/api_token_authenticator.rb.erb +113 -0
  467. data/lib/generators/tasker/templates/api_token_authenticator_spec.rb.erb +144 -0
  468. data/lib/generators/tasker/templates/authorization_coordinator.rb.erb +95 -0
  469. data/lib/generators/tasker/templates/authorization_coordinator_spec.rb.erb +142 -0
  470. data/lib/generators/tasker/templates/custom_authenticator.rb.erb +108 -0
  471. data/lib/generators/tasker/templates/custom_authenticator_spec.rb.erb +162 -0
  472. data/lib/generators/tasker/templates/custom_events.yml.erb +62 -0
  473. data/lib/generators/tasker/templates/custom_subscriber.rb.erb +72 -0
  474. data/lib/generators/tasker/templates/devise_authenticator.rb.erb +101 -0
  475. data/lib/generators/tasker/templates/devise_authenticator_spec.rb.erb +126 -0
  476. data/lib/generators/tasker/templates/initialize.rb.erb +202 -0
  477. data/lib/generators/tasker/templates/jwt_authenticator.rb.erb +144 -0
  478. data/lib/generators/tasker/templates/jwt_authenticator_spec.rb.erb +298 -0
  479. data/lib/generators/tasker/templates/metrics_subscriber.rb.erb +258 -0
  480. data/lib/generators/tasker/templates/metrics_subscriber_spec.rb.erb +308 -0
  481. data/lib/generators/tasker/templates/omniauth_authenticator.rb.erb +135 -0
  482. data/lib/generators/tasker/templates/omniauth_authenticator_spec.rb.erb +196 -0
  483. data/lib/generators/tasker/templates/opentelemetry_initializer.rb +52 -0
  484. data/lib/generators/tasker/templates/subscriber.rb.erb +64 -0
  485. data/lib/generators/tasker/templates/subscriber_spec.rb.erb +80 -0
  486. data/lib/generators/tasker/templates/task_config.yaml.erb +117 -0
  487. data/lib/generators/tasker/templates/task_handler.rb.erb +59 -0
  488. data/lib/generators/tasker/templates/task_handler_spec.rb.erb +159 -0
  489. data/lib/tasker/analysis/runtime_graph_analyzer.rb +1168 -0
  490. data/lib/tasker/analysis/template_graph_analyzer.rb +328 -0
  491. data/lib/tasker/authentication/coordinator.rb +78 -0
  492. data/lib/tasker/authentication/errors.rb +9 -0
  493. data/lib/tasker/authentication/interface.rb +36 -0
  494. data/lib/tasker/authentication/none_authenticator.rb +26 -0
  495. data/lib/tasker/authorization/base_coordinator.rb +112 -0
  496. data/lib/tasker/authorization/errors.rb +26 -0
  497. data/lib/tasker/authorization/resource_constants.rb +74 -0
  498. data/lib/tasker/authorization/resource_registry.rb +143 -0
  499. data/lib/tasker/authorization.rb +75 -0
  500. data/lib/tasker/cache_capabilities.rb +131 -0
  501. data/lib/tasker/cache_strategy.rb +469 -0
  502. data/lib/tasker/concerns/authenticatable.rb +41 -0
  503. data/lib/tasker/concerns/authorizable.rb +204 -0
  504. data/lib/tasker/concerns/controller_authorizable.rb +124 -0
  505. data/lib/tasker/concerns/event_publisher.rb +716 -0
  506. data/lib/tasker/concerns/idempotent_state_transitions.rb +128 -0
  507. data/lib/tasker/concerns/state_machine_base.rb +218 -0
  508. data/lib/tasker/concerns/structured_logging.rb +387 -0
  509. data/lib/tasker/configuration.rb +325 -0
  510. data/lib/tasker/constants/event_definitions.rb +147 -0
  511. data/lib/tasker/constants/registry_events.rb +54 -0
  512. data/lib/tasker/constants.rb +417 -0
  513. data/lib/tasker/engine.rb +90 -0
  514. data/lib/tasker/errors.rb +90 -0
  515. data/lib/tasker/events/catalog.rb +432 -0
  516. data/lib/tasker/events/custom_registry.rb +175 -0
  517. data/lib/tasker/events/definition_loader.rb +199 -0
  518. data/lib/tasker/events/event_payload_builder.rb +461 -0
  519. data/lib/tasker/events/publisher.rb +149 -0
  520. data/lib/tasker/events/subscribers/base_subscriber.rb +601 -0
  521. data/lib/tasker/events/subscribers/metrics_subscriber.rb +120 -0
  522. data/lib/tasker/events/subscribers/telemetry_subscriber.rb +462 -0
  523. data/lib/tasker/events/subscription_loader.rb +161 -0
  524. data/lib/tasker/events.rb +37 -0
  525. data/lib/tasker/functions/function_based_analytics_metrics.rb +103 -0
  526. data/lib/tasker/functions/function_based_dependency_levels.rb +54 -0
  527. data/lib/tasker/functions/function_based_slowest_steps.rb +84 -0
  528. data/lib/tasker/functions/function_based_slowest_tasks.rb +84 -0
  529. data/lib/tasker/functions/function_based_step_readiness_status.rb +183 -0
  530. data/lib/tasker/functions/function_based_system_health_counts.rb +94 -0
  531. data/lib/tasker/functions/function_based_task_execution_context.rb +148 -0
  532. data/lib/tasker/functions/function_wrapper.rb +42 -0
  533. data/lib/tasker/functions.rb +12 -0
  534. data/lib/tasker/handler_factory.rb +322 -0
  535. data/lib/tasker/health/readiness_checker.rb +186 -0
  536. data/lib/tasker/health/status_checker.rb +203 -0
  537. data/lib/tasker/identity_strategy.rb +38 -0
  538. data/lib/tasker/logging/correlation_id_generator.rb +120 -0
  539. data/lib/tasker/orchestration/backoff_calculator.rb +184 -0
  540. data/lib/tasker/orchestration/connection_builder.rb +122 -0
  541. data/lib/tasker/orchestration/connection_pool_intelligence.rb +177 -0
  542. data/lib/tasker/orchestration/coordinator.rb +119 -0
  543. data/lib/tasker/orchestration/future_state_analyzer.rb +137 -0
  544. data/lib/tasker/orchestration/plugin_integration.rb +124 -0
  545. data/lib/tasker/orchestration/response_processor.rb +168 -0
  546. data/lib/tasker/orchestration/retry_header_parser.rb +78 -0
  547. data/lib/tasker/orchestration/step_executor.rb +941 -0
  548. data/lib/tasker/orchestration/step_sequence_factory.rb +67 -0
  549. data/lib/tasker/orchestration/task_finalizer.rb +564 -0
  550. data/lib/tasker/orchestration/task_initializer.rb +140 -0
  551. data/lib/tasker/orchestration/task_reenqueuer.rb +71 -0
  552. data/lib/tasker/orchestration/viable_step_discovery.rb +65 -0
  553. data/lib/tasker/orchestration/workflow_coordinator.rb +294 -0
  554. data/lib/tasker/orchestration.rb +45 -0
  555. data/lib/tasker/railtie.rb +9 -0
  556. data/lib/tasker/registry/base_registry.rb +177 -0
  557. data/lib/tasker/registry/event_publisher.rb +91 -0
  558. data/lib/tasker/registry/interface_validator.rb +140 -0
  559. data/lib/tasker/registry/statistics_collector.rb +381 -0
  560. data/lib/tasker/registry/subscriber_registry.rb +285 -0
  561. data/lib/tasker/registry.rb +22 -0
  562. data/lib/tasker/state_machine/step_state_machine.rb +508 -0
  563. data/lib/tasker/state_machine/task_state_machine.rb +192 -0
  564. data/lib/tasker/state_machine.rb +83 -0
  565. data/lib/tasker/step_handler/api.rb +410 -0
  566. data/lib/tasker/step_handler/base.rb +206 -0
  567. data/lib/tasker/task_builder.rb +432 -0
  568. data/lib/tasker/task_handler/class_methods.rb +324 -0
  569. data/lib/tasker/task_handler/instance_methods.rb +293 -0
  570. data/lib/tasker/task_handler/step_group.rb +182 -0
  571. data/lib/tasker/task_handler.rb +43 -0
  572. data/lib/tasker/telemetry/event_mapping.rb +126 -0
  573. data/lib/tasker/telemetry/event_router.rb +318 -0
  574. data/lib/tasker/telemetry/events/export_events.rb +38 -0
  575. data/lib/tasker/telemetry/export_coordinator.rb +497 -0
  576. data/lib/tasker/telemetry/intelligent_cache_manager.rb +508 -0
  577. data/lib/tasker/telemetry/log_backend.rb +224 -0
  578. data/lib/tasker/telemetry/metric_types.rb +368 -0
  579. data/lib/tasker/telemetry/metrics_backend.rb +1227 -0
  580. data/lib/tasker/telemetry/metrics_export_service.rb +392 -0
  581. data/lib/tasker/telemetry/plugin_registry.rb +333 -0
  582. data/lib/tasker/telemetry/plugins/base_exporter.rb +246 -0
  583. data/lib/tasker/telemetry/plugins/csv_exporter.rb +198 -0
  584. data/lib/tasker/telemetry/plugins/json_exporter.rb +141 -0
  585. data/lib/tasker/telemetry/prometheus_exporter.rb +249 -0
  586. data/lib/tasker/telemetry/trace_backend.rb +186 -0
  587. data/lib/tasker/telemetry.rb +59 -0
  588. data/lib/tasker/types/auth_config.rb +81 -0
  589. data/lib/tasker/types/backoff_config.rb +142 -0
  590. data/lib/tasker/types/cache_config.rb +257 -0
  591. data/lib/tasker/types/database_config.rb +39 -0
  592. data/lib/tasker/types/dependency_graph.rb +225 -0
  593. data/lib/tasker/types/dependency_graph_config.rb +149 -0
  594. data/lib/tasker/types/engine_config.rb +131 -0
  595. data/lib/tasker/types/execution_config.rb +289 -0
  596. data/lib/tasker/types/health_config.rb +84 -0
  597. data/lib/tasker/types/step_sequence.rb +24 -0
  598. data/lib/tasker/types/step_template.rb +63 -0
  599. data/lib/tasker/types/task_request.rb +60 -0
  600. data/lib/tasker/types/telemetry_config.rb +273 -0
  601. data/lib/tasker/types.rb +64 -0
  602. data/lib/tasker/version.rb +7 -0
  603. data/lib/tasker.rb +82 -0
  604. data/lib/tasks/tasker_tasks.rake +302 -0
  605. metadata +958 -0
@@ -0,0 +1,203 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tasker
4
+ module Health
5
+ # StatusChecker provides comprehensive system status information
6
+ #
7
+ # Gathers detailed metrics about tasks, workflow steps, and system health.
8
+ # Uses Rails caching to avoid expensive database queries on frequent requests.
9
+ #
10
+ # @example Basic usage
11
+ # checker = Tasker::Health::StatusChecker.new
12
+ # status = checker.check
13
+ # puts status[:healthy]
14
+ #
15
+ # @example Force refresh (bypass cache)
16
+ # status = checker.check(force_refresh: true)
17
+ class StatusChecker
18
+ # @return [Integer] Cache duration in seconds
19
+ attr_reader :cache_duration
20
+
21
+ # Cache key for status data
22
+ CACHE_KEY = 'tasker:health:status'
23
+
24
+ # Initialize status checker
25
+ #
26
+ # @param cache_duration [Integer] Cache duration in seconds (default from config)
27
+ def initialize(cache_duration: nil)
28
+ @cache_duration = cache_duration || Tasker.configuration.health.cache_duration_seconds
29
+ end
30
+
31
+ # Class method for status check
32
+ #
33
+ # @return [Hash] Comprehensive status information
34
+ def self.status
35
+ new.check
36
+ end
37
+
38
+ # Perform comprehensive status check
39
+ #
40
+ # @param force_refresh [Boolean] Whether to bypass cache and force fresh data
41
+ # @return [Hash] Comprehensive status information
42
+ # - :healthy [Boolean] Overall system health
43
+ # - :status [String] Status description
44
+ # - :data [Hash] Detailed metrics
45
+ # - :cached [Boolean] Whether data came from cache
46
+ # - :timestamp [Time] When data was generated
47
+ def check(force_refresh: false)
48
+ if force_refresh
49
+ result = generate_status_data
50
+ result[:cached] = false
51
+ result
52
+ else
53
+ begin
54
+ # Check if we have cached data first
55
+ cached_data = Rails.cache.read(CACHE_KEY)
56
+ if cached_data.nil?
57
+ # No cached data, generate fresh and cache it
58
+ result = generate_status_data
59
+ # Create a copy for caching (without the cached flag)
60
+ cache_data = result.dup
61
+ cache_data.delete(:cached)
62
+ Rails.cache.write(CACHE_KEY, cache_data, expires_in: @cache_duration.seconds)
63
+ result[:cached] = false
64
+ else
65
+ # Return cached data with cached flag set
66
+ result = cached_data.dup
67
+ result[:cached] = true
68
+ end
69
+ result
70
+ rescue StandardError => e
71
+ # If cache fails, generate fresh data
72
+ result = generate_status_data
73
+ result[:cached] = false
74
+ result[:cache_error] = "Cache error: #{e.message}"
75
+ result
76
+ end
77
+ end
78
+ end
79
+
80
+ private
81
+
82
+ # Generate fresh status data
83
+ #
84
+ # @return [Hash] Fresh status information
85
+ def generate_status_data
86
+ start_time = Time.current
87
+
88
+ begin
89
+ # Get health metrics from SQL function
90
+ health_data = Tasker::Functions::FunctionBasedSystemHealthCounts.call
91
+
92
+ # Determine overall health status
93
+ healthy = assess_system_health(health_data)
94
+
95
+ formatted_data = format_health_data(health_data)
96
+
97
+ {
98
+ healthy: healthy,
99
+ status: healthy ? 'healthy' : 'unhealthy',
100
+ metrics: formatted_data[:metrics],
101
+ database: formatted_data[:database],
102
+ cached: false,
103
+ timestamp: start_time,
104
+ generation_duration: Time.current - start_time
105
+ }
106
+ rescue StandardError => e
107
+ {
108
+ healthy: false,
109
+ status: 'error',
110
+ error: e.message,
111
+ error_class: e.class.name,
112
+ cached: false,
113
+ timestamp: start_time,
114
+ generation_duration: Time.current - start_time
115
+ }
116
+ end
117
+ end
118
+
119
+ # Assess overall system health based on metrics
120
+ #
121
+ # @param health_data [FunctionBasedSystemHealthCounts::HealthMetrics] Health metrics from SQL function
122
+ # @return [Boolean] Whether system is healthy
123
+ def assess_system_health(health_data)
124
+ # System is healthy if:
125
+ # 1. Database is responding (we got data)
126
+ # 2. Connection utilization is reasonable (< 90%)
127
+ # 3. No excessive error accumulation (< 50% error rate)
128
+
129
+ return false if health_data.nil?
130
+
131
+ # Check database connection utilization
132
+ if health_data.max_connections.positive?
133
+ connection_utilization = (health_data.active_connections.to_f / health_data.max_connections) * 100
134
+ return false if connection_utilization > 90.0
135
+ end
136
+
137
+ # Check task error rate (only if we have tasks)
138
+ if health_data.total_tasks.positive?
139
+ task_error_rate = (health_data.error_tasks.to_f / health_data.total_tasks) * 100
140
+ return false if task_error_rate > 50.0
141
+ end
142
+
143
+ # Check step error rate (only if we have steps)
144
+ if health_data.total_steps.positive?
145
+ step_error_rate = (health_data.error_steps.to_f / health_data.total_steps) * 100
146
+ return false if step_error_rate > 50.0
147
+ end
148
+
149
+ true
150
+ end
151
+
152
+ # Format health data for API response
153
+ #
154
+ # @param health_data [FunctionBasedSystemHealthCounts::HealthMetrics] Raw health metrics
155
+ # @return [Hash] Formatted health data with :metrics and :database keys
156
+ def format_health_data(health_data)
157
+ {
158
+ metrics: {
159
+ tasks: {
160
+ total: health_data.total_tasks,
161
+ pending: health_data.pending_tasks,
162
+ in_progress: health_data.in_progress_tasks,
163
+ complete: health_data.complete_tasks,
164
+ error: health_data.error_tasks,
165
+ cancelled: health_data.cancelled_tasks
166
+ },
167
+ steps: {
168
+ total: health_data.total_steps,
169
+ pending: health_data.pending_steps,
170
+ in_progress: health_data.in_progress_steps,
171
+ complete: health_data.complete_steps,
172
+ error: health_data.error_steps
173
+ },
174
+ retries: {
175
+ retryable_errors: health_data.retryable_error_steps,
176
+ exhausted_retries: health_data.exhausted_retry_steps,
177
+ in_backoff: health_data.in_backoff_steps
178
+ }
179
+ },
180
+ database: {
181
+ active_connections: health_data.active_connections,
182
+ max_connections: health_data.max_connections,
183
+ connection_utilization: calculate_utilization_percentage(
184
+ health_data.active_connections,
185
+ health_data.max_connections
186
+ ) # Return as percentage (e.g., 5.0 for 5%)
187
+ }
188
+ }
189
+ end
190
+
191
+ # Calculate connection utilization percentage
192
+ #
193
+ # @param active [Integer] Active connections
194
+ # @param max [Integer] Maximum connections
195
+ # @return [Float] Utilization percentage
196
+ def calculate_utilization_percentage(active, max)
197
+ return 0.0 if max.zero?
198
+
199
+ ((active.to_f / max) * 100).round(2)
200
+ end
201
+ end
202
+ end
203
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+ require 'digest'
5
+
6
+ module Tasker
7
+ # Base identity strategy class that generates a GUID by default
8
+ #
9
+ # Identity strategies are used to generate unique identifiers for tasks.
10
+ # This allows for customizing how task identity is determined and tracked.
11
+ class IdentityStrategy
12
+ # Generate a unique identity hash for a task
13
+ #
14
+ # The default implementation generates a random UUID.
15
+ #
16
+ # @param _task [Tasker::Task] The task to generate an identity for
17
+ # @param _task_options [Hash] Additional options for identity generation
18
+ # @return [String] A unique identity hash
19
+ def generate_identity_hash(_task, _task_options)
20
+ SecureRandom.uuid
21
+ end
22
+ end
23
+
24
+ # Strategy that uses SHA256 hash of task identity options
25
+ #
26
+ # This strategy is useful when you want identical tasks (with the same
27
+ # options/parameters) to have the same identity hash.
28
+ class HashIdentityStrategy < IdentityStrategy
29
+ # Generate a deterministic identity hash based on task options
30
+ #
31
+ # @param _task [Tasker::Task] The task to generate an identity for
32
+ # @param task_options [Hash] Task options to hash for identity
33
+ # @return [String] A SHA256 hash of the task options
34
+ def generate_identity_hash(_task, task_options)
35
+ Digest::SHA256.hexdigest(task_options.to_json)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tasker
4
+ module Logging
5
+ # CorrelationIdGenerator creates unique correlation IDs for distributed tracing
6
+ #
7
+ # Generates correlation IDs that are:
8
+ # - Unique across distributed systems
9
+ # - URL-safe and log-friendly
10
+ # - Sortable by generation time
11
+ # - Human-readable length
12
+ #
13
+ # Format: tsk_[timestamp_base36][random_suffix]
14
+ # Example: tsk_l7k9m2p4_a8x3f9
15
+ class CorrelationIdGenerator
16
+ # Prefix for all Tasker correlation IDs
17
+ PREFIX = 'tsk'
18
+
19
+ # Length of random suffix
20
+ RANDOM_SUFFIX_LENGTH = 6
21
+
22
+ class << self
23
+ # Generate a new correlation ID
24
+ #
25
+ # @return [String] A unique correlation ID
26
+ #
27
+ # @example
28
+ # id = Tasker::Logging::CorrelationIdGenerator.generate
29
+ # # => "tsk_l7k9m2p4_a8x3f9"
30
+ def generate
31
+ timestamp_part = generate_timestamp_component
32
+ random_part = generate_random_component
33
+
34
+ "#{PREFIX}_#{timestamp_part}_#{random_part}"
35
+ end
36
+
37
+ # Generate correlation ID from an existing ID (for HTTP propagation)
38
+ #
39
+ # @param existing_id [String, nil] Existing correlation ID from headers
40
+ # @return [String] Valid correlation ID (existing or newly generated)
41
+ #
42
+ # @example
43
+ # # With existing valid ID
44
+ # id = from_existing("req_abc123")
45
+ # # => "req_abc123"
46
+ #
47
+ # # With invalid/missing ID
48
+ # id = from_existing(nil)
49
+ # # => "tsk_l7k9m2p4_a8x3f9"
50
+ def from_existing(existing_id)
51
+ return generate if existing_id.blank?
52
+ return existing_id if valid_correlation_id?(existing_id)
53
+
54
+ # If existing ID is invalid, create a new one but log the attempt
55
+ Rails.logger.debug { "Invalid correlation ID received: #{existing_id}. Generating new ID." }
56
+ generate
57
+ end
58
+
59
+ # Extract correlation ID from HTTP headers
60
+ #
61
+ # @param headers [Hash] HTTP headers hash
62
+ # @param header_name [String] Header name to check (defaults to config)
63
+ # @return [String, nil] Correlation ID if found and valid
64
+ #
65
+ # @example
66
+ # id = from_headers(request.headers)
67
+ # id = from_headers(env, 'X-Request-ID')
68
+ def from_headers(headers, header_name = nil)
69
+ header_name ||= Tasker.configuration.telemetry.correlation_id_header
70
+
71
+ # Handle different header formats (rack vs rails)
72
+ header_value = headers[header_name] ||
73
+ headers["HTTP_#{header_name.upcase.tr('-', '_')}"] ||
74
+ headers[header_name.downcase]
75
+
76
+ from_existing(header_value)
77
+ end
78
+
79
+ # Validate if a string is a valid correlation ID format
80
+ #
81
+ # @param id [String] The ID to validate
82
+ # @return [Boolean] Whether the ID is valid
83
+ #
84
+ # @example
85
+ # valid_correlation_id?("tsk_l7k9m2p4_a8x3f9") # => true
86
+ # valid_correlation_id?("invalid") # => false
87
+ # valid_correlation_id?("") # => false
88
+ def valid_correlation_id?(id)
89
+ return false if id.blank?
90
+ return false if id.length > 100 # Reasonable max length
91
+
92
+ # Allow various prefixes for external system compatibility
93
+ # But ensure it's alphanumeric with underscores/hyphens only
94
+ id.match?(/\A[a-zA-Z0-9][a-zA-Z0-9_\-]*\z/)
95
+ end
96
+
97
+ private
98
+
99
+ # Generate timestamp component in base36 for compactness
100
+ #
101
+ # @return [String] Timestamp component
102
+ def generate_timestamp_component
103
+ # Use millisecond precision timestamp
104
+ timestamp_ms = (Time.current.to_f * 1000).to_i
105
+ timestamp_ms.to_s(36)
106
+ end
107
+
108
+ # Generate random component using secure random
109
+ #
110
+ # @return [String] Random component
111
+ def generate_random_component
112
+ # Use URL-safe base64 character set: A-Z, a-z, 0-9
113
+ chars = ('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a
114
+
115
+ Array.new(RANDOM_SUFFIX_LENGTH) { chars.sample }.join
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,184 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../concerns/event_publisher'
4
+ require_relative 'retry_header_parser'
5
+
6
+ module Tasker
7
+ module Orchestration
8
+ # BackoffCalculator handles all backoff logic for API retries
9
+ #
10
+ # This component provides unified handling of both server-requested backoff
11
+ # (via Retry-After headers) and exponential backoff calculations.
12
+ # It publishes appropriate events for observability.
13
+ class BackoffCalculator
14
+ include Tasker::Concerns::EventPublisher
15
+
16
+ # Initialize the backoff calculator
17
+ #
18
+ # @param config [Object] Configuration object with backoff settings
19
+ # @param retry_parser [RetryHeaderParser] Parser for Retry-After headers (injectable for testing)
20
+ def initialize(config: nil, retry_parser: RetryHeaderParser.new)
21
+ @config = config
22
+ @retry_parser = retry_parser
23
+ end
24
+
25
+ # Calculate and apply backoff for a step based on response context
26
+ #
27
+ # This method determines whether to use server-requested backoff or
28
+ # exponential backoff, calculates the appropriate delay, and updates
29
+ # the step with backoff information.
30
+ #
31
+ # @param step [Tasker::WorkflowStep] The step requiring backoff
32
+ # @param context [Hash] Response context containing headers and metadata
33
+ def calculate_and_apply_backoff(step, context)
34
+ retry_after = extract_retry_after_header(context)
35
+
36
+ if retry_after.present?
37
+ apply_server_requested_backoff(step, retry_after)
38
+ elsif backoff_enabled?
39
+ apply_exponential_backoff(step, context)
40
+ else
41
+ Rails.logger.warn(
42
+ "BackoffCalculator: No backoff strategy available for step #{step.name} (#{step.workflow_step_id})"
43
+ )
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ # Get backoff configuration with memoization
50
+ #
51
+ # @return [Tasker::Types::BackoffConfig] The backoff configuration
52
+ def backoff_config
53
+ @backoff_config ||= Tasker.configuration.backoff
54
+ end
55
+
56
+ # Extract Retry-After header from response context
57
+ #
58
+ # @param context [Hash] Response context
59
+ # @return [String, nil] Retry-After header value if present
60
+ def extract_retry_after_header(context)
61
+ headers = context[:headers] || {}
62
+ headers['Retry-After'] || headers['retry-after']
63
+ end
64
+
65
+ # Apply server-requested backoff using Retry-After header
66
+ #
67
+ # @param step [Tasker::WorkflowStep] The step to apply backoff to
68
+ # @param retry_after [String] The Retry-After header value
69
+ def apply_server_requested_backoff(step, retry_after)
70
+ backoff_seconds = @retry_parser.parse_retry_after(retry_after)
71
+
72
+ # Apply configurable cap for server-requested backoff
73
+ max_server_backoff = backoff_config.max_backoff_seconds
74
+ backoff_seconds = [backoff_seconds, max_server_backoff].min
75
+
76
+ # Update step with backoff information
77
+ step.backoff_request_seconds = backoff_seconds
78
+
79
+ # Publish backoff event for observability
80
+ publish_step_backoff(
81
+ step,
82
+ backoff_seconds: backoff_seconds,
83
+ backoff_type: 'server_requested',
84
+ retry_after: retry_after
85
+ )
86
+
87
+ Rails.logger.info(
88
+ "BackoffCalculator: Applied server-requested backoff of #{backoff_seconds} seconds " \
89
+ "for step #{step.name} (#{step.workflow_step_id})"
90
+ )
91
+ end
92
+
93
+ # Apply exponential backoff calculation
94
+ #
95
+ # @param step [Tasker::WorkflowStep] The step to apply backoff to
96
+ # @param context [Hash] Response context for event publishing
97
+ def apply_exponential_backoff(step, context)
98
+ # Ensure attempts is properly initialized
99
+ step.attempts ||= 0
100
+
101
+ # Convert 0-based attempts to 1-based for backoff calculation
102
+ # (step.attempts = 0 means first attempt, should get backoff[0])
103
+ attempt_for_calculation = step.attempts + 1
104
+ backoff_seconds = calculate_exponential_delay(attempt_for_calculation)
105
+
106
+ # Update step with backoff information
107
+ step.backoff_request_seconds = backoff_seconds
108
+ step.last_attempted_at = Time.zone.now
109
+
110
+ # Publish backoff event for observability
111
+ publish_exponential_backoff_event(step, backoff_seconds, context, attempt_for_calculation)
112
+
113
+ Rails.logger.info(
114
+ "BackoffCalculator: Applied exponential backoff of #{backoff_seconds} seconds " \
115
+ "for step #{step.name} (#{step.workflow_step_id}), attempt #{step.attempts}"
116
+ )
117
+ end
118
+
119
+ # Calculate exponential delay with jitter
120
+ #
121
+ # @param attempt_number [Integer] The 1-based attempt number
122
+ # @return [Float] Calculated backoff delay in seconds
123
+ def calculate_exponential_delay(attempt_number)
124
+ # Use BackoffConfig's calculate_backoff_seconds method
125
+ backoff_seconds = backoff_config.calculate_backoff_seconds(attempt_number)
126
+
127
+ # Ensure minimum delay of at least half the first backoff value
128
+ min_delay = backoff_config.default_backoff_seconds.first * 0.5
129
+ [backoff_seconds, min_delay].max
130
+ end
131
+
132
+ # Publish exponential backoff event with detailed information
133
+ #
134
+ # @param step [Tasker::WorkflowStep] The step being backed off
135
+ # @param backoff_seconds [Float] Calculated backoff delay
136
+ # @param context [Hash] Response context
137
+ # @param attempt_number [Integer] The 1-based attempt number
138
+ def publish_exponential_backoff_event(step, backoff_seconds, _context, attempt_number)
139
+ publish_step_backoff(
140
+ step,
141
+ backoff_seconds: backoff_seconds,
142
+ backoff_type: 'exponential',
143
+ attempt: step.attempts,
144
+ calculated_attempt: attempt_number,
145
+ base_delay: backoff_config.default_backoff_seconds.first,
146
+ multiplier: backoff_config.backoff_multiplier,
147
+ jitter_enabled: backoff_config.jitter_enabled,
148
+ jitter_max_percentage: backoff_config.jitter_max_percentage
149
+ )
150
+ end
151
+
152
+ # Check if exponential backoff is enabled
153
+ #
154
+ # @return [Boolean] True if exponential backoff should be used
155
+ def backoff_enabled?
156
+ return true unless @config # Default to enabled if no config
157
+
158
+ if @config.respond_to?(:enable_exponential_backoff)
159
+ @config.enable_exponential_backoff
160
+ else
161
+ true
162
+ end
163
+ end
164
+
165
+ # Get retry delay from configuration
166
+ #
167
+ # @return [Float] Base retry delay in seconds
168
+ def retry_delay
169
+ return backoff_config.default_backoff_seconds.first.to_f unless @config.respond_to?(:retry_delay)
170
+
171
+ @config.retry_delay || backoff_config.default_backoff_seconds.first.to_f
172
+ end
173
+
174
+ # Get jitter factor from configuration
175
+ #
176
+ # @return [Float] Jitter factor for randomness (0.0-1.0)
177
+ def jitter_factor_value
178
+ return rand unless @config.respond_to?(:jitter_factor)
179
+
180
+ @config.jitter_factor || rand
181
+ end
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+
5
+ module Tasker
6
+ module Orchestration
7
+ # ConnectionBuilder handles Faraday connection configuration and building
8
+ #
9
+ # This component provides focused responsibility for building and configuring
10
+ # Faraday connections based on API handler configuration, with support for
11
+ # custom connection block configuration.
12
+ class ConnectionBuilder
13
+ # Build a Faraday connection from configuration
14
+ #
15
+ # @param config [Object] Configuration object with connection settings
16
+ # @yield [Faraday::Connection] Optional block for custom connection configuration
17
+ # @return [Faraday::Connection] Configured Faraday connection
18
+ def build_connection(config, &connection_block)
19
+ validate_config(config)
20
+
21
+ Rails.logger.debug do
22
+ "ConnectionBuilder: Building connection to #{config.url} " \
23
+ "with #{config.params.keys.size} params and #{config.headers.keys.size} headers"
24
+ end
25
+
26
+ connection = Faraday.new(
27
+ url: config.url,
28
+ params: config.params || {},
29
+ headers: config.headers || {},
30
+ ssl: config.ssl
31
+ )
32
+
33
+ # Apply custom configuration block if provided
34
+ if connection_block
35
+ Rails.logger.debug('ConnectionBuilder: Applying custom connection configuration')
36
+ yield(connection)
37
+ end
38
+
39
+ connection
40
+ rescue StandardError => e
41
+ Rails.logger.error(
42
+ "ConnectionBuilder: Failed to build connection to #{config&.url}: #{e.message}"
43
+ )
44
+ raise
45
+ end
46
+
47
+ # Validate configuration has required fields
48
+ #
49
+ # @param config [Object] Configuration to validate
50
+ # @raise [ArgumentError] If configuration is invalid
51
+ def validate_config(config)
52
+ ConfigValidator.validate(config)
53
+ end
54
+
55
+ # Service class to validate connection configuration
56
+ # Reduces complexity by organizing validation logic
57
+ class ConfigValidator
58
+ class << self
59
+ # Validate configuration object
60
+ #
61
+ # @param config [Object] Configuration to validate
62
+ # @raise [ArgumentError] If configuration is invalid
63
+ def validate(config)
64
+ validate_config_presence(config)
65
+ validate_config_interface(config)
66
+ validate_url_presence(config)
67
+ validate_url_format(config)
68
+ end
69
+
70
+ private
71
+
72
+ # Validate configuration is present
73
+ #
74
+ # @param config [Object] Configuration to validate
75
+ # @raise [ArgumentError] If configuration is nil
76
+ def validate_config_presence(config)
77
+ raise ArgumentError, 'Configuration cannot be nil' if config.nil?
78
+ end
79
+
80
+ # Validate configuration has required interface
81
+ #
82
+ # @param config [Object] Configuration to validate
83
+ # @raise [ArgumentError] If configuration doesn't respond to :url
84
+ def validate_config_interface(config)
85
+ raise ArgumentError, 'Configuration must respond to :url' unless config.respond_to?(:url)
86
+ end
87
+
88
+ # Validate URL is present and non-empty
89
+ #
90
+ # @param config [Object] Configuration to validate
91
+ # @raise [ArgumentError] If URL is nil or empty
92
+ def validate_url_presence(config)
93
+ return unless config.url.nil? || config.url.strip.empty?
94
+
95
+ raise ArgumentError, 'Configuration URL cannot be nil or empty'
96
+ end
97
+
98
+ # Validate URL format using URI parsing
99
+ #
100
+ # @param config [Object] Configuration to validate
101
+ # @raise [ArgumentError] If URL format is invalid
102
+ def validate_url_format(config)
103
+ uri = URI.parse(config.url)
104
+ validate_uri_components(uri)
105
+ rescue URI::InvalidURIError => e
106
+ raise ArgumentError, "Configuration URL is not a valid URI: #{e.message}"
107
+ end
108
+
109
+ # Validate URI has required components
110
+ #
111
+ # @param uri [URI] Parsed URI to validate
112
+ # @raise [ArgumentError] If URI lacks scheme or host
113
+ def validate_uri_components(uri)
114
+ return if uri.scheme && uri.host
115
+
116
+ raise ArgumentError, 'Configuration URL must be a valid URI with scheme and host'
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end