@decaf-ts/core 0.28.1 → 0.30.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 (60) hide show
  1. package/README.md +15 -7
  2. package/dist/core.cjs +1 -1
  3. package/dist/core.cjs.map +1 -1
  4. package/dist/core.js +1 -1
  5. package/dist/core.js.map +1 -1
  6. package/lib/cjs/index.cjs +3 -3
  7. package/lib/cjs/migrations/MigrationService.cjs +32 -4
  8. package/lib/cjs/migrations/MigrationService.cjs.map +1 -1
  9. package/lib/cjs/migrations/SemverMigrationVersioning.cjs +15 -0
  10. package/lib/cjs/migrations/SemverMigrationVersioning.cjs.map +1 -1
  11. package/lib/cjs/migrations/StandardMigrationVersioning.cjs +11 -0
  12. package/lib/cjs/migrations/StandardMigrationVersioning.cjs.map +1 -1
  13. package/lib/cjs/tasks/TaskContext.cjs +3 -0
  14. package/lib/cjs/tasks/TaskContext.cjs.map +1 -1
  15. package/lib/cjs/tasks/TaskEngine.cjs +148 -69
  16. package/lib/cjs/tasks/TaskEngine.cjs.map +1 -1
  17. package/lib/cjs/tasks/builder.cjs +4 -0
  18. package/lib/cjs/tasks/builder.cjs.map +1 -1
  19. package/lib/cjs/tasks/constants.cjs +1 -0
  20. package/lib/cjs/tasks/constants.cjs.map +1 -1
  21. package/lib/cjs/tasks/models/TaskStepSpecModel.cjs +6 -0
  22. package/lib/cjs/tasks/models/TaskStepSpecModel.cjs.map +1 -1
  23. package/lib/esm/index.js +3 -3
  24. package/lib/esm/migrations/MigrationService.js +32 -4
  25. package/lib/esm/migrations/MigrationService.js.map +1 -1
  26. package/lib/esm/migrations/SemverMigrationVersioning.js +15 -0
  27. package/lib/esm/migrations/SemverMigrationVersioning.js.map +1 -1
  28. package/lib/esm/migrations/StandardMigrationVersioning.js +11 -0
  29. package/lib/esm/migrations/StandardMigrationVersioning.js.map +1 -1
  30. package/lib/esm/tasks/TaskContext.js +3 -0
  31. package/lib/esm/tasks/TaskContext.js.map +1 -1
  32. package/lib/esm/tasks/TaskEngine.js +148 -69
  33. package/lib/esm/tasks/TaskEngine.js.map +1 -1
  34. package/lib/esm/tasks/builder.js +4 -0
  35. package/lib/esm/tasks/builder.js.map +1 -1
  36. package/lib/esm/tasks/constants.js +1 -0
  37. package/lib/esm/tasks/constants.js.map +1 -1
  38. package/lib/esm/tasks/models/TaskStepSpecModel.js +6 -0
  39. package/lib/esm/tasks/models/TaskStepSpecModel.js.map +1 -1
  40. package/lib/types/index.d.cts +3 -3
  41. package/lib/types/index.d.mts +3 -3
  42. package/lib/types/migrations/MigrationService.d.cts +13 -0
  43. package/lib/types/migrations/MigrationService.d.mts +13 -0
  44. package/lib/types/migrations/MigrationVersioning.d.cts +9 -0
  45. package/lib/types/migrations/MigrationVersioning.d.mts +9 -0
  46. package/lib/types/migrations/SemverMigrationVersioning.d.cts +10 -0
  47. package/lib/types/migrations/SemverMigrationVersioning.d.mts +10 -0
  48. package/lib/types/migrations/StandardMigrationVersioning.d.cts +1 -0
  49. package/lib/types/migrations/StandardMigrationVersioning.d.mts +1 -0
  50. package/lib/types/tasks/TaskContext.d.cts +2 -0
  51. package/lib/types/tasks/TaskContext.d.mts +2 -0
  52. package/lib/types/tasks/TaskEngine.d.cts +5 -0
  53. package/lib/types/tasks/TaskEngine.d.mts +5 -0
  54. package/lib/types/tasks/builder.d.cts +1 -0
  55. package/lib/types/tasks/builder.d.mts +1 -0
  56. package/lib/types/tasks/models/TaskStepSpecModel.d.cts +1 -0
  57. package/lib/types/tasks/models/TaskStepSpecModel.d.mts +1 -0
  58. package/lib/types/tasks/types.d.cts +4 -0
  59. package/lib/types/tasks/types.d.mts +4 -0
  60. package/package.json +1 -1
package/README.md CHANGED
@@ -11,7 +11,7 @@ Decaf Core provides the foundational building blocks for the Decaf TypeScript ec
11
11
  * **`Repository`**: A class that implements the repository pattern, providing a consistent API for CRUD operations and querying.
12
12
  * **`Adapter`**: An abstract class that defines the interface for connecting to different database backends.
13
13
  * **`Statement`**: A query builder for creating complex database queries in a fluent, type-safe manner.
14
- * **`TaskEngine`**: A system for managing background jobs and asynchronous operations.
14
+ * **`TaskEngine`**: A system for managing background jobs and asynchronous operations, including composite-step concurrency controls.
15
15
  * **`ModelService` and `PersistenceService`**: Base classes for creating services that encapsulate business logic and data access.
16
16
  * **Migrations**: A system for managing database schema changes over time.
17
17
  * **RAM Adapter**: An in-memory adapter for testing and development.
@@ -39,7 +39,7 @@ Decaf Core provides the foundational building blocks for the Decaf TypeScript ec
39
39
 
40
40
  Documentation [here](https://decaf-ts.github.io/injectable-decorators/), Test results [here](https://decaf-ts.github.io/injectable-decorators/workdocs/reports/html/test-report.html) and Coverage [here](https://decaf-ts.github.io/injectable-decorators/workdocs/reports/coverage/lcov-report/index.html)
41
41
 
42
- Minimal size: 47.5 KB kb gzipped
42
+ Minimal size: 48 KB kb gzipped
43
43
 
44
44
 
45
45
  # Core Package — Detailed Description
@@ -48,7 +48,7 @@ The Decaf Core package provides a cohesive set of primitives for building strong
48
48
 
49
49
  - Models (from @decaf-ts/decorator-validation) enhanced with identity and persistence metadata.
50
50
  - A Repository abstraction that encapsulates CRUD, querying, and observation.
51
- - A powerful Task Engine for defining, scheduling, and executing background jobs with support for worker threads.
51
+ - A powerful Task Engine for defining, scheduling, and executing background jobs with support for worker threads and composite-step concurrency controls.
52
52
  - Adapters that bridge repositories to underlying storage (in-memory, HTTP, TypeORM, etc.).
53
53
  - A fluent Query DSL (Statement/Condition) with pagination.
54
54
  - Lightweight dependency injection utilities to auto-resolve repositories.
@@ -88,7 +88,7 @@ Below is an overview of the main modules and their public APIs exposed by core.
88
88
 
89
89
  ## 2. Task Engine Module
90
90
  A robust system for managing background jobs.
91
- - **`TaskEngine<A>`**: The core engine that polls for and executes tasks. Manages the task lifecycle, concurrency, and worker threads.
91
+ - **`TaskEngine<A>`**: The core engine that polls for and executes tasks. Manages the task lifecycle, global runnable-task concurrency, composite-step concurrency, and worker threads.
92
92
  - **`TaskService<A>`**: A high-level service providing a clean API for interacting with the `TaskEngine`. It's the recommended entry point for managing tasks.
93
93
  - `push(task, track?)`: Submits a new task for execution.
94
94
  - `schedule(task, track?).for(date)`: Schedules a task to run at a specific time.
@@ -96,14 +96,18 @@ A robust system for managing background jobs.
96
96
  - **Models**:
97
97
  - `TaskModel`: Represents a task, its status (`PENDING`, `RUNNING`, `SUCCEEDED`, `FAILED`), input, and configuration (e.g., `maxAttempts`, `backoff`). Can be `ATOMIC` or `COMPOSITE`.
98
98
  - `TaskEventModel`: Logs status changes and progress for a task.
99
+ - `TaskStepSpecModel`: Describes composite steps, including `classification`, `name`, `lock`, `dependsOn`, and `allowConcurrent` for opt-in parallel execution of compatible steps.
99
100
  - **Builders**:
100
- - `TaskBuilder`: A fluent API for constructing `TaskModel` instances.
101
+ - `TaskBuilder`: A fluent API for constructing atomic `TaskModel` instances.
101
102
  - `CompositeTaskBuilder`: A builder for creating multi-step (`COMPOSITE`) tasks.
103
+ - `TaskStepSpecBuilder`: A fluent API for constructing composite step specs, including `setAllowConcurrent(false)` by default.
102
104
  - **Handlers & Tracking**:
103
105
  - `ITaskHandler`: The interface to implement for defining the logic of a task. Handlers are registered with the `TaskHandlerRegistry`.
104
106
  - `TaskTracker`: An object returned when tracking a task, allowing you to await its completion and receive progress updates.
105
107
  - **Worker Threads**: The engine can be configured to run tasks in Node.js `worker_threads`, providing true parallelism and non-blocking execution for CPU-intensive jobs. Configuration is done via the `workerPool` and `workerAdapter` properties in the `TaskEngineConfig`.
106
108
 
109
+ Composite-step concurrency is opt-in at the step level. `allowConcurrent` exists on `TaskStepSpecBuilder`, defaults to `false`, and only affects composite steps that share the same `lock`. The per-task `maxConcurrentCompositeSteps` limit defaults to `-1` and is separate from the engine-wide `concurrency` limit for runnable tasks. The engine also uses a shared task-context write lock so logs and results remain serialized while compatible steps run in parallel.
110
+
107
111
  ## 3. Persistence Module
108
112
  - **`Adapter<N, Q, R, Ctx>`**: The bridge between a repository and the back-end storage.
109
113
  - Handles CRUD operations, raw queries, and model/record transformation (`prepare`/`revert`).
@@ -430,7 +434,7 @@ const activeUsers = await userService.findActiveUsers();
430
434
 
431
435
  ## Task Engine
432
436
 
433
- The `TaskEngine` is a powerful tool for managing background jobs.
437
+ The `TaskEngine` is a powerful tool for managing background jobs, including composite-step concurrency controls.
434
438
 
435
439
  ### Creating a Task Handler
436
440
 
@@ -518,6 +522,7 @@ await taskEngine.start();
518
522
  | `bus` | Optional `TaskEventBus` that receives progress/log/status events. |
519
523
  | `workerId` | Uniquely identifies the worker claiming leases. Each engine (including CLI migrations) must use a different `workerId` so leases do not clash. |
520
524
  | `concurrency` | Number of work units to execute in parallel (set to `1` when migration steps must stay sequential). |
525
+ | `maxConcurrentCompositeSteps` | Maximum number of composite steps that may run at once for a single composite task. Defaults to `-1`, which means no limit. |
521
526
  | `leaseMs` | How long a running task can go without a heartbeat before it is re-queued. |
522
527
  | `pollMsIdle` | Poll interval when the queue is empty. |
523
528
  | `pollMsBusy` | Poll interval while tasks are running (shorter than `pollMsIdle`). |
@@ -534,6 +539,9 @@ await taskEngine.start();
534
539
  - `pipe(...log)` and `flush()`: buffer logs that eventually feed into `TaskEventType.LOG`.
535
540
  - `heartbeat()`: extend the lease before it expires (used in long-running handlers).
536
541
  - `scheduleCompositeSteps(...)`: dynamically insert extra steps when building migration tasks.
542
+ - `stepWriteLock`: a shared lock used by composite steps to serialize writes to the task context, so logs and results stay consistent even when compatible steps run concurrently.
543
+
544
+ Composite-step concurrency is opt-in and step-scoped. `allowConcurrent` lives on `TaskStepSpecBuilder`, defaults to `false`, and only affects composite steps that share the same `lock`. The per-task `maxConcurrentCompositeSteps` limit defaults to `-1` and is independent from the engine-wide `concurrency` limit for runnable tasks.
537
545
 
538
546
  ### Task Engine migration guardrails
539
547
 
@@ -560,7 +568,7 @@ The CLI already follows this pattern and explicitly prevents the task engine ada
560
568
 
561
569
  `TaskService.track(id)` wires the CLI logger to the matching `TaskTracker` so status/progress logs stream through your console before `TaskTracker.wait()` resolves. If a migration task fails, call `MigrationService.retry(taskId)`—it uses repository overrides to reset `status` to `PENDING`, clear `error`/lease metadata, and re-queue the work—then `taskService.track(id)` again so the TaskEngine reclaims it.
562
570
 
563
- Composite tasks are ordered by the sequence you pass to `CompositeTaskBuilder` or by using the `dependsOn`/`dependencies` array. Each step has a `classification` (matching a handler), an optional `name`, and `lock`/`dependsOn` metadata (`TaskStepSpecModel`). Locks avoid concurrent execution, and dependencies support either `<taskId>` or `<taskId>:<stepRef>` shorthand so you can mix tasks and steps as prerequisites.
571
+ Composite tasks are ordered by the sequence you pass to `CompositeTaskBuilder` or by using the `dependsOn`/`dependencies` array. Each step has a `classification` (matching a handler), an optional `name`, and `lock`/`dependsOn` metadata (`TaskStepSpecModel`). Use `TaskStepSpecBuilder.setAllowConcurrent(true)` to let compatible steps that share the same lock value run together; the default remains `false`. The engine still serializes context writes through the shared task-context lock so logs and results are persisted safely. Dependencies support either `<taskId>` or `<taskId>:<stepRef>` shorthand so you can mix tasks and steps as prerequisites.
564
572
 
565
573
  Task attempts are bounded by `maxAttempts` and `backoff` (configured via builders). The engine records each attempt and automatically escalates to `WAITING_RETRY`/`RUNNING` states; if a task exhausts retries, the service surfaces the final error via `TaskTracker.wait()` so your migration command can decide between retrying or aborting.
566
574