UNPKG

@penkov/tasks_queue

Version:

A lightweight PostgreSQL-backed task queue system with scheduling, retries, backoff strategies, and priority handling. Designed for efficiency and observability in modern Node.js applications.

256 lines (189 loc) 12.5 kB
# Changelog ## 1.9.5 ### Added - Added `runScheduledTasksRegistrar` to `TasksQueueModule.forRootAsync(...)` so NestJS `@ScheduledTask(...)` auto-discovery and bootstrap provisioning can be disabled per module instance. - Added unit coverage for default and disabled scheduled-task registrar wiring. ### Changed - Updated README and NestJS scheduled-task documentation to describe disabling `ScheduledTasksRegistrar`, with test-focused guidance. ## 1.9.1 ### Added - Added `isPeriodic` filtering to `ManageTasksQueueService.findByParameters(...)`. - Added date-field sorting options for management task search results. - Added last heartbeat to management task DTOs and search sorting. - Added task id sorting for management task search results. - Added integration coverage for periodic filtering and management search sorting. ## 1.9.0 ### Added - Added pool runtime metrics for registered queue labels, slot usage, and polling loop health. - Added per-queue polling, fetch, and task lifecycle counters. - Added unit coverage for runtime metrics emitted through `application-metrics`. ## 1.8.0 ### Added - Added `ManageTasksQueueService.findChildrenTree(...)` for loading all direct and nested child tasks of a root task. - Added PostgreSQL integration coverage that verifies child tree lookup returns only descendants of the requested root and excludes unrelated branches. ## 1.7.9 ### Added - Added `ManagedWorkflowTask` as a policy-oriented orchestration base class on top of `MultiStepTask`. - Added constructor-only `maxRuns` configuration for managed workflows. - Added integration coverage for managed workflow scenarios: happy path, invalid run actions, child terminal failure, allow-failure continuation, invalid `runCount`, and `maxRuns` boundaries. - Added unit coverage for `maxRuns` defaults and constructor validation rules. - Added dedicated documentation for managed workflows in `docs/managed-workflow-task.md`. ### Changed - Changed managed workflow `maxRuns` validation to require a positive integer. - Changed managed workflow `runCount` validation to require a non-negative integer with explicit failure on invalid payload state. - Updated README and multi-step workflow docs to include `ManagedWorkflowTask` and reflect current orchestration semantics. ## 1.7.8 ### Added - Added declarative NestJS method-level worker registration with `@Worker({ queue, pool? })`. - Added automatic discovery and registration of decorated provider methods through Nest `DiscoveryModule`. - Added declarative periodic task provisioning in NestJS providers via `@ScheduledTask(...)` with cron, fixed-rate, and fixed-delay variants. - Added `replaceExisting` support for periodic scheduling APIs and DAO persistence flow. - Added unit coverage for decorated worker discovery and runtime method invocation adapter behavior. - Added unit coverage for scheduled task discovery and periodic replacement conflict handling. - Added documentation for the new decorator-based registration flow in `README.md` and `docs/nest-worker-decorator.md`. - Added documentation for `@ScheduledTask(...)` and `replaceExisting` behavior in `README.md` and `docs/nest-scheduled-task-decorator.md`. ### Changed - `TasksQueueModule` now wires discovery registrars that register decorated methods before pool startup while preserving existing `TasksPoolsService.registerWorker(...)` semantics. - `@ScheduledTask(...)` now auto-registers the decorated method as the queue worker and supports optional `pool` selection. - `@ScheduledTask(...)` worker registration now runs on module init, while schedule provisioning runs on application bootstrap to avoid early schema access. - Combining `@ScheduledTask(...)` and `@Worker(...)` on the same method now throws an initialization error. ## 1.7.6 ### Fixed - Fixed `SequentialTask` auto-continue semantics so steps that run after an intermediate local step do not retain stale `resolvedChildTask` from an earlier child completion. - Fixed `TasksPoolsService.stop()` to clear its shutdown timeout timer after successful stop, preventing Jest open-handle warnings in test runs. ### Added - Added unit coverage that verifies auto-continued sequential steps receive updated payload while stale child references are cleared. - Added unit coverage for shutdown timeout cleanup in `TasksPoolsService.stop()`. ## 1.7.5 ### Fixed - Fixed cross-pool parent-child notifications so child tasks scheduled into another pool start immediately instead of waiting for that pool's next polling interval. - Fixed blocked parent wake-up notifications so parents resume immediately even when the completed child ran in a different pool. ### Added - Added unit coverage for cross-pool queue notification dispatch in `TasksQueueWorker`. - Added an integration test that reproduces cross-pool parent-child execution with `loopInterval = 1 minute` and verifies prompt child start and parent wake-up. - Added unit and integration coverage for `SequentialTask` flows that contain intermediate steps without `spawnChild(...)`, including database assertions for persisted parent payload and final result. ### Changed - Changed `SequentialTask` so a step that finishes without `context.spawnChild(...)` automatically advances to the next configured step in the same parent execution. - Updated README and multi-step workflow documentation to describe mixed sequential flows such as `child -> local step -> child`. ## 1.7.4 ### Added - Added a real PostgreSQL integration test harness based on `testcontainers`. - Added integration coverage for task execution lifecycle, parent-child workflows, stalled-task handling, periodic scheduling, lifecycle callbacks, management APIs, DAO cleanup flows, and ownership race scenarios. - Added broader public API JSDoc across queue services, models, scheduling APIs, and NestJS integration types. ### Changed - Hardened task ownership checks so stale attempts cannot heartbeat, finish, fail, block, or wake tasks after ownership has moved to a newer attempt. - Refined `SequentialTask` payload handling and expanded workflow-specific coverage around parent-child continuations. - Enabled coverage reporting for the integration suite and aligned the repository with the new ESLint ruleset. - Expanded README and detailed documentation for heartbeat behavior, multi-step workflows, and operational usage. ## 1.7.3 ### Fixed - Fixed terminal failure persistence so submitted `result` is retained for terminal task failures instead of being cleared incorrectly. ## 1.7.2 ### Changed - Improved `MultiStepPayload` ergonomics for parent-child workflows. - Refined `SequentialTask` continuation behavior and expanded related workflow coverage and documentation. ## 1.7.1 ### Changed - Prevented deletion of finished tasks while any ancestor in the parent chain is still unfinished. ## 1.7.0 ### Added - Added optional `result jsonb` column to `tasks_queue` for explicit final task output persistence. - Added `TaskContext.submitResult(...)` for workers to submit final task output independently from `setPayload(...)`. ### Changed - `TaskStateSnapshot` and management task views now expose optional `result`. - Parent-child orchestration now reads child output from `childTask.result` instead of overloading `childTask.payload`. - Runtime persistence keeps `payload` as task input/runtime state and stores `result` only on completed runs or terminal failures. ### Migration Apply the following SQL to existing databases: ```sql ALTER TABLE tasks_queue ADD COLUMN IF NOT EXISTS result jsonb DEFAULT NULL; COMMENT ON COLUMN tasks_queue.result IS 'The optional final result submitted by the worker after task completion'; ``` ## 1.6.0 ### Added - Added `ActiveChildState` and `MultiStepPayload.activeChild` to persist active child orchestration metadata. - Added optional `allowFailure` flag to `TaskContext.spawnChild(...)` child scheduling details so parent workflows can continue from `childFailed(...)` without masking child `error` status. ### Changed - `MultiStepTask.childFinished(...)` and `MultiStepTask.childFailed(...)` now receive `activeChild` metadata, and `childFailed(...)` also receives `context` for continuation flows. - `TaskContext` now exposes `resolvedChildTask` as `Option<TaskStateSnapshot>` during parent continuation after child resolution. - `MultiStepPayload.fromJson(...)` now reads both the new `activeChild` structure and legacy `activeChildId` payloads for backward compatibility. ## 1.5.0 ### Added - Added support for parent-child task relations with `parent_id`. - Added `blocked` task status for multi-step orchestration flows. - Added `TaskContext.spawnChild(...)` for declarative child task scheduling from a parent task. - Added `TaskContext.taskId`, `TaskContext.setPayload(...)`, and `TaskContext.findTask(...)` for workflow-aware task execution. - Added `TaskContext.ping()` and persistent task heartbeats for long-running workers. - Added `MultiStepPayload` with separate `workflowPayload`, `userPayload`, and `activeChildId`. - Added `MultiStepTask` for custom state-machine workflows with one active child at a time. - Added `SequentialTask` for happy-path sequential workflows that either complete all configured steps or fail. ### Changed - Parent tasks are now automatically moved to `blocked` after successful child scheduling and woken up only when the child reaches a terminal state. - Stalled child tasks now wake blocked parents when they end in terminal `error`. - Stalled task detection now uses the latest heartbeat when available instead of relying only on `started`. ### Migration Apply the following SQL to existing databases: ```sql ALTER TABLE tasks_queue ADD COLUMN IF NOT EXISTS parent_id int4 DEFAULT NULL REFERENCES tasks_queue (id) ON DELETE SET NULL; ALTER TABLE tasks_queue ADD COLUMN IF NOT EXISTS last_heartbeat timestamp DEFAULT NULL; ALTER TABLE tasks_queue DROP CONSTRAINT IF EXISTS tasks_queue_status_check; ALTER TABLE tasks_queue ADD CONSTRAINT tasks_queue_status_check CHECK (status IN ('pending', 'in_progress', 'blocked', 'finished', 'error')); CREATE INDEX IF NOT EXISTS tasks_queue_parent_id_idx ON tasks_queue (parent_id); ``` ## 1.4.2 ### Added - Management service now provides `deleteTask(taskId)` for deleting tasks only in `pending`, `error`, or `finished` status. ## 1.4.1 ### Fixed - Management API task mapping now reads `missed_runs_strategy` from the database correctly, so `missedRunStrategy` is returned in task DTO/view payloads. ## 1.4.0 ### Added - Management methods to load a task by id and update pending task runtime settings. - Separate management method to update periodic schedule fields for pending periodic tasks. - Optional queue filter for task search parameters. ### Changed - Renamed management search method from `findByStatus(...)` to `findByParameters(...)`. ## 1.3.0 ### Added - Cron-based periodic scheduling support with `repeat_type='cron'`. - New `cron_expression` column in `tasks_queue` for storing cron schedules. ### Migration Apply the following SQL to existing databases: ```sql -- Add a dedicated column for cron schedules ALTER TABLE tasks_queue ADD COLUMN IF NOT EXISTS cron_expression text DEFAULT NULL; -- Recreate repeat_type check to allow cron ALTER TABLE tasks_queue DROP CONSTRAINT IF EXISTS tasks_queue_repeat_type_check; ALTER TABLE tasks_queue ADD CONSTRAINT tasks_queue_repeat_type_check CHECK (repeat_type IN ('fixed_rate', 'fixed_delay', 'cron')); -- Ensure cron expression is never blank when provided ALTER TABLE tasks_queue DROP CONSTRAINT IF EXISTS tasks_queue_cron_expression_not_blank; ALTER TABLE tasks_queue ADD CONSTRAINT tasks_queue_cron_expression_not_blank CHECK (cron_expression IS NULL OR btrim(cron_expression) <> ''); -- Keep interval and cron fields mutually exclusive and consistent with repeat_type ALTER TABLE tasks_queue DROP CONSTRAINT IF EXISTS tasks_queue_repeat_config_consistency; ALTER TABLE tasks_queue ADD CONSTRAINT tasks_queue_repeat_config_consistency CHECK ( (repeat_type IS NULL AND repeat_interval IS NULL AND cron_expression IS NULL) OR (repeat_type IN ('fixed_rate', 'fixed_delay') AND repeat_interval IS NOT NULL AND cron_expression IS NULL) OR (repeat_type = 'cron' AND cron_expression IS NOT NULL AND repeat_interval IS NULL) ); ```