feat(scheduler)!: durable jobs, progress and PostgreSQL persistence - #235
Conversation
| pool: { min: 0, max: 10 }, acquireConnectionTimeout: 5000 | ||
| }); | ||
| const jobs = new JobScheduler({ | ||
| repository: new PostgresJobRepository(database), |
There was a problem hiding this comment.
I think repository is not the best name here, let's come up with something better. What about persistRepository or storageRepository?
There was a problem hiding this comment.
Addressed in 8665e96: the constructor option is now storageRepository throughout the implementation, tests, both package guides and the website examples. No alias for the unpublished repository option remains. Verified by the full build, 4,377 tests, PostgreSQL integration tests and both runnable demos. Leaving this thread open for your review.
| type RowSchema<T> = ObjectSchemaBuilder<{ | ||
| [K in keyof T & string]: SchemaBuilder<T[K]>; | ||
| }>; |
There was a problem hiding this comment.
this looks weird, do we really need this type? Or we can just use typeof?
There was a problem hiding this comment.
Yes—the handwritten RowSchema<T> layer was unnecessary. Addressed in 8665e96: removed it, the four parallel row types and all as unknown as casts from this file. Storage and entity types now use typeof the actual schemas; tests derive row types with InferType. Named property maps plus ReturnType<typeof object<typeof fields>> keep declaration emission portable without duplicating field types. Added compile-time query/insert/nullability checks and runtime primary-key/table-prefix checks; package declaration emit and the real PostgreSQL suites pass. Leaving this thread open for your review.
|
The earlier revision retained recurrence through Validation is complete: 4,377 local tests, both website typechecks, both API reference builds, 12 PostgreSQL scheduler tests, 53 ORM query tests, both runnable demos and local docs browser QA passed. Both required CI jobs are green. Replies are on both inline threads; they are left unresolved for your review. No hosted preview/telemetry is configured; the PR description includes a local docs screenshot and explains the notification skip. |
| "dependencies": { | ||
| "@cleverbrush/schema": "^4.4.3" | ||
| "@cleverbrush/schema": "^4.4.3", | ||
| "@js-temporal/polyfill": "0.5.1" |
There was a problem hiding this comment.
let's avoid using it
There was a problem hiding this comment.
Addressed in 86afb34. Removed @js-temporal/polyfill and the now-unused jsbi dependency from the manifest and npm-generated lockfile. Calendar arithmetic and time-zone resolution now use built-in Date/Intl.DateTimeFormat, with a bounded formatter cache; no replacement date-time dependency was added.
The documented behavior is retained: gaps are skipped, repeated times select the earlier instant, and calculations are independent of the host TZ. Added 26 regressions covering half-hour DST changes, skipped dates, fractional/historical offsets, calendar eras and Date-range exhaustion. A one-off comparison against the previous implementation covered 5,852 cases across 418 IANA zones with zero mismatches; that dependency is not retained in tests.
Updated JSDoc, README (including runtime ICU/tzdata guidance) and the major changeset. Validation: 4,403 tests, both website typechecks, PostgreSQL suites, both demos and both required CI jobs pass. Leaving the thread open for your review.
Original request
Implement the agreed application-agnostic “Durable background jobs and progress” design in Framework, based on the existing scheduler, as a PR against
development. Keep contracts and handlers separate and strongly typed; include tests, JSDoc, guides, a migration guide and a changeset.Approved choices: a unified v5 scheduler redesign; immediate and recurring jobs; function and worker-thread handlers; opt-in whole-handler retries; UTC/IANA calendar schedules; coalesce/skip/replay missed policies; PostgreSQL persistence plus a process-local in-memory adapter; reuse Framework ORM and knex-schema.
What changed
Dependency review follow-up in
86afb348:@js-temporal/polyfilland its unusedjsbidependency from the scheduler manifest and npm-generated lockfile.Date/Intl.DateTimeFormatfor Gregorian calendar arithmetic and IANA offsets, with a bounded formatter cache. Keep gap skipping, earlier-fold selection and persisted recurrence semantics.TZindependence. Update JSDoc, README runtime/tzdata guidance and the existing major changeset.Review follow-up in
8665e96f:ScheduleSchema, individual schemas andSchemas; inferSchedule/TaskScheduleas a discriminated union.maxOccurencesspelling, reject both spellings together. Restore one-based public calculator indexes while retaining zero-based persisted cursors.storageRepositorythroughout implementation, tests and documentation.RowSchema<T>, parallel handwritten row types and double casts from the PostgreSQL adapter. Derive storage/entity/query types from actual schemas, with declaration-emission and metadata/type coverage.Original implementation:
defineJobcontracts,JobHandler<typeof Definition>, separate trusted handler registration and independently managed producer/dispatcher/worker lifecycles.@cleverbrush/scheduler-postgrespackage. Framework schemas generate tables, ORM handles routine queries, and isolated native queries implement locking and aggregates. Explicit up/down migrations; transaction-bound producers support business-write + enqueue rollback.Reasoning and guarantees
Native time-zone rules come from the Node.js runtime's ICU data. Dispatcher runtimes should use aligned tzdata versions; no additional date-time package is required.
One shared transition engine prevents adapters from drifting on retry/ownership semantics. PostgreSQL is optional, rather than a mandatory dependency of scheduler consumers.
This is not an exactly-once workflow engine. Enabled retries rerun the entire handler. Applications own side-effect idempotency, authorization and progress transport. Default maxAttempts is one; lease expiry consumes the same attempt budget. Ordinary functions must cooperate with cancellation; threads can be terminated.
The major changeset joins the existing Framework v5 release train. Changeset status confirms the fixed public package group receives major releases. No package has been published, and no production deployment is part of this PR.
Blog post
Skipped: library/runtime API work, not an end-user application feature. The package guides, API JSDoc, migration guide and documentation website are the consumer-facing documentation.
Screenshots / preview evidence
Framework has no hosted PR preview workflow or configured runtime telemetry service. Local docs QA at
http://127.0.0.1:3219/schedulerverified all guide sections and links, with no browser errors. This is a local-only preview, not a public deployment.The immediate example prints:
The periodic example reports
Completed both periodic reports.after running both the dispatcher and worker.Validation
npm run lintnpm run build— 22 package buildsnpm run test— 4,403 tests, 216 files, no type errorsnpm run typecheck:schema-sitenpm run typecheck:docs-sitenpm run test:scheduler:integration— 12 PostgreSQL testsnpm run test:queries:integration— 53 existing PostgreSQL testsnode demos/durable-jobs/demo.tsnode demos/durable-jobs/periodic.ts --fast— two periodic runs completednpm pack --dry-run— worker-thread entry includednpx changeset status --since=origin/development— major release group validated (existing private website file-dependency warnings remain)86afb348— both required jobs passed:Notification
Telegram PR-ready notification skipped: the notifier requires an environment URL, but Framework has no hosted PR preview deployment. Local docs QA and CI evidence are linked above.