@nicnocquee/dataqueue 1.30.0 → 1.31.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.
package/dist/index.d.cts CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as pg from 'pg';
2
2
  import { Pool } from 'pg';
3
+ import { Cron } from 'croner';
3
4
 
4
5
  type JobType<PayloadMap> = keyof PayloadMap & string;
5
6
  interface JobOptions<PayloadMap, T extends JobType<PayloadMap>> {
@@ -490,6 +491,81 @@ type JobQueueConfig = PostgresJobQueueConfig | RedisJobQueueConfig;
490
491
  /** @deprecated Use JobQueueConfig instead. Alias kept for backward compat. */
491
492
  type JobQueueConfigLegacy = PostgresJobQueueConfig;
492
493
  type TagQueryMode = 'exact' | 'all' | 'any' | 'none';
494
+ /**
495
+ * Status of a cron schedule.
496
+ */
497
+ type CronScheduleStatus = 'active' | 'paused';
498
+ /**
499
+ * Options for creating a recurring cron schedule.
500
+ * Each schedule defines a recurring job that is automatically enqueued
501
+ * when its cron expression matches.
502
+ */
503
+ interface CronScheduleOptions<PayloadMap, T extends JobType<PayloadMap>> {
504
+ /** Unique human-readable name for the schedule. */
505
+ scheduleName: string;
506
+ /** Standard cron expression (5 fields, e.g. "0 * * * *"). */
507
+ cronExpression: string;
508
+ /** Job type from the PayloadMap. */
509
+ jobType: T;
510
+ /** Payload for each job instance. */
511
+ payload: PayloadMap[T];
512
+ /** Maximum retry attempts for each job instance (default: 3). */
513
+ maxAttempts?: number;
514
+ /** Priority for each job instance (default: 0). */
515
+ priority?: number;
516
+ /** Timeout in milliseconds for each job instance. */
517
+ timeoutMs?: number;
518
+ /** Whether to force-kill the job on timeout (default: false). */
519
+ forceKillOnTimeout?: boolean;
520
+ /** Tags for each job instance. */
521
+ tags?: string[];
522
+ /** IANA timezone string for cron evaluation (default: "UTC"). */
523
+ timezone?: string;
524
+ /**
525
+ * Whether to allow overlapping job instances (default: false).
526
+ * When false, a new job will not be enqueued if the previous instance
527
+ * is still pending, processing, or waiting.
528
+ */
529
+ allowOverlap?: boolean;
530
+ }
531
+ /**
532
+ * A persisted cron schedule record.
533
+ */
534
+ interface CronScheduleRecord {
535
+ id: number;
536
+ scheduleName: string;
537
+ cronExpression: string;
538
+ jobType: string;
539
+ payload: any;
540
+ maxAttempts: number;
541
+ priority: number;
542
+ timeoutMs: number | null;
543
+ forceKillOnTimeout: boolean;
544
+ tags: string[] | undefined;
545
+ timezone: string;
546
+ allowOverlap: boolean;
547
+ status: CronScheduleStatus;
548
+ lastEnqueuedAt: Date | null;
549
+ lastJobId: number | null;
550
+ nextRunAt: Date | null;
551
+ createdAt: Date;
552
+ updatedAt: Date;
553
+ }
554
+ /**
555
+ * Options for editing an existing cron schedule.
556
+ * All fields are optional; only provided fields are updated.
557
+ */
558
+ interface EditCronScheduleOptions {
559
+ cronExpression?: string;
560
+ payload?: any;
561
+ maxAttempts?: number;
562
+ priority?: number;
563
+ timeoutMs?: number | null;
564
+ forceKillOnTimeout?: boolean;
565
+ tags?: string[] | null;
566
+ timezone?: string;
567
+ allowOverlap?: boolean;
568
+ }
493
569
  interface JobQueue<PayloadMap> {
494
570
  /**
495
571
  * Add a job to the job queue.
@@ -676,6 +752,56 @@ interface JobQueue<PayloadMap> {
676
752
  * @returns The number of tokens that were expired.
677
753
  */
678
754
  expireTimedOutTokens: () => Promise<number>;
755
+ /**
756
+ * Add a recurring cron schedule. The processor automatically enqueues
757
+ * due cron jobs before each batch, so no manual triggering is needed.
758
+ *
759
+ * @returns The ID of the created schedule.
760
+ * @throws If the cron expression is invalid or the schedule name is already taken.
761
+ */
762
+ addCronJob: <T extends JobType<PayloadMap>>(options: CronScheduleOptions<PayloadMap, T>) => Promise<number>;
763
+ /**
764
+ * Get a cron schedule by its ID.
765
+ */
766
+ getCronJob: (id: number) => Promise<CronScheduleRecord | null>;
767
+ /**
768
+ * Get a cron schedule by its unique name.
769
+ */
770
+ getCronJobByName: (name: string) => Promise<CronScheduleRecord | null>;
771
+ /**
772
+ * List all cron schedules, optionally filtered by status.
773
+ */
774
+ listCronJobs: (status?: CronScheduleStatus) => Promise<CronScheduleRecord[]>;
775
+ /**
776
+ * Remove a cron schedule by its ID. Does not cancel any already-enqueued jobs.
777
+ */
778
+ removeCronJob: (id: number) => Promise<void>;
779
+ /**
780
+ * Pause a cron schedule. Paused schedules are skipped by `enqueueDueCronJobs()`.
781
+ */
782
+ pauseCronJob: (id: number) => Promise<void>;
783
+ /**
784
+ * Resume a paused cron schedule.
785
+ */
786
+ resumeCronJob: (id: number) => Promise<void>;
787
+ /**
788
+ * Edit an existing cron schedule. Only provided fields are updated.
789
+ * If `cronExpression` or `timezone` changes, `nextRunAt` is recalculated.
790
+ */
791
+ editCronJob: (id: number, updates: EditCronScheduleOptions) => Promise<void>;
792
+ /**
793
+ * Check all active cron schedules and enqueue jobs for any whose
794
+ * `nextRunAt` has passed. When `allowOverlap` is false (the default),
795
+ * a new job is not enqueued if the previous instance is still
796
+ * pending, processing, or waiting.
797
+ *
798
+ * **Note:** The processor calls this automatically before each batch,
799
+ * so you typically do not need to call it yourself. It is exposed for
800
+ * manual use in tests or one-off scripts.
801
+ *
802
+ * @returns The number of jobs that were enqueued.
803
+ */
804
+ enqueueDueCronJobs: () => Promise<number>;
679
805
  /**
680
806
  * Get the PostgreSQL database pool.
681
807
  * Throws if the backend is not PostgreSQL.
@@ -723,6 +849,24 @@ interface JobUpdates {
723
849
  timeoutMs?: number | null;
724
850
  tags?: string[] | null;
725
851
  }
852
+ /**
853
+ * Input shape for creating a cron schedule in the backend.
854
+ * This is the backend-level version of CronScheduleOptions.
855
+ */
856
+ interface CronScheduleInput {
857
+ scheduleName: string;
858
+ cronExpression: string;
859
+ jobType: string;
860
+ payload: any;
861
+ maxAttempts: number;
862
+ priority: number;
863
+ timeoutMs: number | null;
864
+ forceKillOnTimeout: boolean;
865
+ tags: string[] | undefined;
866
+ timezone: string;
867
+ allowOverlap: boolean;
868
+ nextRunAt: Date | null;
869
+ }
726
870
  /**
727
871
  * Abstract backend interface that both PostgreSQL and Redis implement.
728
872
  * All storage operations go through this interface so the processor
@@ -774,6 +918,32 @@ interface QueueBackend {
774
918
  recordJobEvent(jobId: number, eventType: JobEventType, metadata?: any): Promise<void>;
775
919
  /** Get all events for a job, ordered by createdAt ASC. */
776
920
  getJobEvents(jobId: number): Promise<JobEvent[]>;
921
+ /** Create a cron schedule and return its ID. */
922
+ addCronSchedule(input: CronScheduleInput): Promise<number>;
923
+ /** Get a cron schedule by ID, or null if not found. */
924
+ getCronSchedule(id: number): Promise<CronScheduleRecord | null>;
925
+ /** Get a cron schedule by its unique name, or null if not found. */
926
+ getCronScheduleByName(name: string): Promise<CronScheduleRecord | null>;
927
+ /** List cron schedules, optionally filtered by status. */
928
+ listCronSchedules(status?: CronScheduleStatus): Promise<CronScheduleRecord[]>;
929
+ /** Delete a cron schedule by ID. */
930
+ removeCronSchedule(id: number): Promise<void>;
931
+ /** Pause a cron schedule. */
932
+ pauseCronSchedule(id: number): Promise<void>;
933
+ /** Resume a cron schedule. */
934
+ resumeCronSchedule(id: number): Promise<void>;
935
+ /** Edit a cron schedule. */
936
+ editCronSchedule(id: number, updates: EditCronScheduleOptions, nextRunAt?: Date | null): Promise<void>;
937
+ /**
938
+ * Atomically fetch all active cron schedules whose nextRunAt <= now.
939
+ * In PostgreSQL this uses FOR UPDATE SKIP LOCKED to prevent duplicate enqueuing.
940
+ */
941
+ getDueCronSchedules(): Promise<CronScheduleRecord[]>;
942
+ /**
943
+ * Update a cron schedule after a job has been enqueued.
944
+ * Sets lastEnqueuedAt, lastJobId, and advances nextRunAt.
945
+ */
946
+ updateCronScheduleAfterEnqueue(id: number, lastEnqueuedAt: Date, lastJobId: number, nextRunAt: Date | null): Promise<void>;
777
947
  /** Set a pending reason for unpicked jobs of a given type. */
778
948
  setPendingReasonForUnpickedJobs(reason: string, jobType?: string | string[]): Promise<void>;
779
949
  }
@@ -809,6 +979,32 @@ declare class PostgresBackend implements QueueBackend {
809
979
  * More efficient than individual recordJobEvent calls.
810
980
  */
811
981
  private recordJobEventsBatch;
982
+ /** Create a cron schedule and return its ID. */
983
+ addCronSchedule(input: CronScheduleInput): Promise<number>;
984
+ /** Get a cron schedule by ID. */
985
+ getCronSchedule(id: number): Promise<CronScheduleRecord | null>;
986
+ /** Get a cron schedule by its unique name. */
987
+ getCronScheduleByName(name: string): Promise<CronScheduleRecord | null>;
988
+ /** List cron schedules, optionally filtered by status. */
989
+ listCronSchedules(status?: CronScheduleStatus): Promise<CronScheduleRecord[]>;
990
+ /** Delete a cron schedule by ID. */
991
+ removeCronSchedule(id: number): Promise<void>;
992
+ /** Pause a cron schedule. */
993
+ pauseCronSchedule(id: number): Promise<void>;
994
+ /** Resume a paused cron schedule. */
995
+ resumeCronSchedule(id: number): Promise<void>;
996
+ /** Edit a cron schedule. */
997
+ editCronSchedule(id: number, updates: EditCronScheduleOptions, nextRunAt?: Date | null): Promise<void>;
998
+ /**
999
+ * Atomically fetch all active cron schedules whose nextRunAt <= NOW().
1000
+ * Uses FOR UPDATE SKIP LOCKED to prevent duplicate enqueuing across workers.
1001
+ */
1002
+ getDueCronSchedules(): Promise<CronScheduleRecord[]>;
1003
+ /**
1004
+ * Update a cron schedule after a job has been enqueued.
1005
+ * Sets lastEnqueuedAt, lastJobId, and advances nextRunAt.
1006
+ */
1007
+ updateCronScheduleAfterEnqueue(id: number, lastEnqueuedAt: Date, lastJobId: number, nextRunAt: Date | null): Promise<void>;
812
1008
  setPendingReasonForUnpickedJobs(reason: string, jobType?: string | string[]): Promise<void>;
813
1009
  }
814
1010
 
@@ -863,6 +1059,25 @@ declare function testHandlerSerialization<PayloadMap, T extends keyof PayloadMap
863
1059
  error?: string;
864
1060
  }>;
865
1061
 
1062
+ /**
1063
+ * Calculate the next occurrence of a cron expression after a given date.
1064
+ *
1065
+ * @param cronExpression - A standard cron expression (5 fields, e.g. "0 * * * *").
1066
+ * @param timezone - IANA timezone string (default: "UTC").
1067
+ * @param after - The reference date to compute the next run from (default: now).
1068
+ * @param CronImpl - Cron class for dependency injection (default: croner's Cron).
1069
+ * @returns The next occurrence as a Date, or null if the expression will never fire again.
1070
+ */
1071
+ declare function getNextCronOccurrence(cronExpression: string, timezone?: string, after?: Date, CronImpl?: typeof Cron): Date | null;
1072
+ /**
1073
+ * Validate whether a string is a syntactically correct cron expression.
1074
+ *
1075
+ * @param cronExpression - The cron expression to validate.
1076
+ * @param CronImpl - Cron class for dependency injection (default: croner's Cron).
1077
+ * @returns True if the expression is valid, false otherwise.
1078
+ */
1079
+ declare function validateCronExpression(cronExpression: string, CronImpl?: typeof Cron): boolean;
1080
+
866
1081
  /**
867
1082
  * Initialize the job queue system.
868
1083
  *
@@ -870,4 +1085,4 @@ declare function testHandlerSerialization<PayloadMap, T extends keyof PayloadMap
870
1085
  */
871
1086
  declare const initJobQueue: <PayloadMap = any>(config: JobQueueConfig) => JobQueue<PayloadMap>;
872
1087
 
873
- export { type CreateTokenOptions, type DatabaseSSLConfig, type EditJobOptions, FailureReason, type JobContext, type JobEvent, JobEventType, type JobHandler, type JobHandlers, type JobOptions, type JobQueue, type JobQueueConfig, type JobQueueConfigLegacy, type JobRecord, type JobStatus, type JobType, type OnTimeoutCallback, PostgresBackend, type PostgresJobQueueConfig, type Processor, type ProcessorOptions, type QueueBackend, type RedisJobQueueConfig, type RedisTLSConfig, type TagQueryMode, type WaitDuration, WaitSignal, type WaitToken, type WaitTokenResult, type WaitpointRecord, type WaitpointStatus, initJobQueue, testHandlerSerialization, validateHandlerSerializable };
1088
+ export { type CreateTokenOptions, type CronScheduleInput, type CronScheduleOptions, type CronScheduleRecord, type CronScheduleStatus, type DatabaseSSLConfig, type EditCronScheduleOptions, type EditJobOptions, FailureReason, type JobContext, type JobEvent, JobEventType, type JobHandler, type JobHandlers, type JobOptions, type JobQueue, type JobQueueConfig, type JobQueueConfigLegacy, type JobRecord, type JobStatus, type JobType, type OnTimeoutCallback, PostgresBackend, type PostgresJobQueueConfig, type Processor, type ProcessorOptions, type QueueBackend, type RedisJobQueueConfig, type RedisTLSConfig, type TagQueryMode, type WaitDuration, WaitSignal, type WaitToken, type WaitTokenResult, type WaitpointRecord, type WaitpointStatus, getNextCronOccurrence, initJobQueue, testHandlerSerialization, validateCronExpression, validateHandlerSerializable };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as pg from 'pg';
2
2
  import { Pool } from 'pg';
3
+ import { Cron } from 'croner';
3
4
 
4
5
  type JobType<PayloadMap> = keyof PayloadMap & string;
5
6
  interface JobOptions<PayloadMap, T extends JobType<PayloadMap>> {
@@ -490,6 +491,81 @@ type JobQueueConfig = PostgresJobQueueConfig | RedisJobQueueConfig;
490
491
  /** @deprecated Use JobQueueConfig instead. Alias kept for backward compat. */
491
492
  type JobQueueConfigLegacy = PostgresJobQueueConfig;
492
493
  type TagQueryMode = 'exact' | 'all' | 'any' | 'none';
494
+ /**
495
+ * Status of a cron schedule.
496
+ */
497
+ type CronScheduleStatus = 'active' | 'paused';
498
+ /**
499
+ * Options for creating a recurring cron schedule.
500
+ * Each schedule defines a recurring job that is automatically enqueued
501
+ * when its cron expression matches.
502
+ */
503
+ interface CronScheduleOptions<PayloadMap, T extends JobType<PayloadMap>> {
504
+ /** Unique human-readable name for the schedule. */
505
+ scheduleName: string;
506
+ /** Standard cron expression (5 fields, e.g. "0 * * * *"). */
507
+ cronExpression: string;
508
+ /** Job type from the PayloadMap. */
509
+ jobType: T;
510
+ /** Payload for each job instance. */
511
+ payload: PayloadMap[T];
512
+ /** Maximum retry attempts for each job instance (default: 3). */
513
+ maxAttempts?: number;
514
+ /** Priority for each job instance (default: 0). */
515
+ priority?: number;
516
+ /** Timeout in milliseconds for each job instance. */
517
+ timeoutMs?: number;
518
+ /** Whether to force-kill the job on timeout (default: false). */
519
+ forceKillOnTimeout?: boolean;
520
+ /** Tags for each job instance. */
521
+ tags?: string[];
522
+ /** IANA timezone string for cron evaluation (default: "UTC"). */
523
+ timezone?: string;
524
+ /**
525
+ * Whether to allow overlapping job instances (default: false).
526
+ * When false, a new job will not be enqueued if the previous instance
527
+ * is still pending, processing, or waiting.
528
+ */
529
+ allowOverlap?: boolean;
530
+ }
531
+ /**
532
+ * A persisted cron schedule record.
533
+ */
534
+ interface CronScheduleRecord {
535
+ id: number;
536
+ scheduleName: string;
537
+ cronExpression: string;
538
+ jobType: string;
539
+ payload: any;
540
+ maxAttempts: number;
541
+ priority: number;
542
+ timeoutMs: number | null;
543
+ forceKillOnTimeout: boolean;
544
+ tags: string[] | undefined;
545
+ timezone: string;
546
+ allowOverlap: boolean;
547
+ status: CronScheduleStatus;
548
+ lastEnqueuedAt: Date | null;
549
+ lastJobId: number | null;
550
+ nextRunAt: Date | null;
551
+ createdAt: Date;
552
+ updatedAt: Date;
553
+ }
554
+ /**
555
+ * Options for editing an existing cron schedule.
556
+ * All fields are optional; only provided fields are updated.
557
+ */
558
+ interface EditCronScheduleOptions {
559
+ cronExpression?: string;
560
+ payload?: any;
561
+ maxAttempts?: number;
562
+ priority?: number;
563
+ timeoutMs?: number | null;
564
+ forceKillOnTimeout?: boolean;
565
+ tags?: string[] | null;
566
+ timezone?: string;
567
+ allowOverlap?: boolean;
568
+ }
493
569
  interface JobQueue<PayloadMap> {
494
570
  /**
495
571
  * Add a job to the job queue.
@@ -676,6 +752,56 @@ interface JobQueue<PayloadMap> {
676
752
  * @returns The number of tokens that were expired.
677
753
  */
678
754
  expireTimedOutTokens: () => Promise<number>;
755
+ /**
756
+ * Add a recurring cron schedule. The processor automatically enqueues
757
+ * due cron jobs before each batch, so no manual triggering is needed.
758
+ *
759
+ * @returns The ID of the created schedule.
760
+ * @throws If the cron expression is invalid or the schedule name is already taken.
761
+ */
762
+ addCronJob: <T extends JobType<PayloadMap>>(options: CronScheduleOptions<PayloadMap, T>) => Promise<number>;
763
+ /**
764
+ * Get a cron schedule by its ID.
765
+ */
766
+ getCronJob: (id: number) => Promise<CronScheduleRecord | null>;
767
+ /**
768
+ * Get a cron schedule by its unique name.
769
+ */
770
+ getCronJobByName: (name: string) => Promise<CronScheduleRecord | null>;
771
+ /**
772
+ * List all cron schedules, optionally filtered by status.
773
+ */
774
+ listCronJobs: (status?: CronScheduleStatus) => Promise<CronScheduleRecord[]>;
775
+ /**
776
+ * Remove a cron schedule by its ID. Does not cancel any already-enqueued jobs.
777
+ */
778
+ removeCronJob: (id: number) => Promise<void>;
779
+ /**
780
+ * Pause a cron schedule. Paused schedules are skipped by `enqueueDueCronJobs()`.
781
+ */
782
+ pauseCronJob: (id: number) => Promise<void>;
783
+ /**
784
+ * Resume a paused cron schedule.
785
+ */
786
+ resumeCronJob: (id: number) => Promise<void>;
787
+ /**
788
+ * Edit an existing cron schedule. Only provided fields are updated.
789
+ * If `cronExpression` or `timezone` changes, `nextRunAt` is recalculated.
790
+ */
791
+ editCronJob: (id: number, updates: EditCronScheduleOptions) => Promise<void>;
792
+ /**
793
+ * Check all active cron schedules and enqueue jobs for any whose
794
+ * `nextRunAt` has passed. When `allowOverlap` is false (the default),
795
+ * a new job is not enqueued if the previous instance is still
796
+ * pending, processing, or waiting.
797
+ *
798
+ * **Note:** The processor calls this automatically before each batch,
799
+ * so you typically do not need to call it yourself. It is exposed for
800
+ * manual use in tests or one-off scripts.
801
+ *
802
+ * @returns The number of jobs that were enqueued.
803
+ */
804
+ enqueueDueCronJobs: () => Promise<number>;
679
805
  /**
680
806
  * Get the PostgreSQL database pool.
681
807
  * Throws if the backend is not PostgreSQL.
@@ -723,6 +849,24 @@ interface JobUpdates {
723
849
  timeoutMs?: number | null;
724
850
  tags?: string[] | null;
725
851
  }
852
+ /**
853
+ * Input shape for creating a cron schedule in the backend.
854
+ * This is the backend-level version of CronScheduleOptions.
855
+ */
856
+ interface CronScheduleInput {
857
+ scheduleName: string;
858
+ cronExpression: string;
859
+ jobType: string;
860
+ payload: any;
861
+ maxAttempts: number;
862
+ priority: number;
863
+ timeoutMs: number | null;
864
+ forceKillOnTimeout: boolean;
865
+ tags: string[] | undefined;
866
+ timezone: string;
867
+ allowOverlap: boolean;
868
+ nextRunAt: Date | null;
869
+ }
726
870
  /**
727
871
  * Abstract backend interface that both PostgreSQL and Redis implement.
728
872
  * All storage operations go through this interface so the processor
@@ -774,6 +918,32 @@ interface QueueBackend {
774
918
  recordJobEvent(jobId: number, eventType: JobEventType, metadata?: any): Promise<void>;
775
919
  /** Get all events for a job, ordered by createdAt ASC. */
776
920
  getJobEvents(jobId: number): Promise<JobEvent[]>;
921
+ /** Create a cron schedule and return its ID. */
922
+ addCronSchedule(input: CronScheduleInput): Promise<number>;
923
+ /** Get a cron schedule by ID, or null if not found. */
924
+ getCronSchedule(id: number): Promise<CronScheduleRecord | null>;
925
+ /** Get a cron schedule by its unique name, or null if not found. */
926
+ getCronScheduleByName(name: string): Promise<CronScheduleRecord | null>;
927
+ /** List cron schedules, optionally filtered by status. */
928
+ listCronSchedules(status?: CronScheduleStatus): Promise<CronScheduleRecord[]>;
929
+ /** Delete a cron schedule by ID. */
930
+ removeCronSchedule(id: number): Promise<void>;
931
+ /** Pause a cron schedule. */
932
+ pauseCronSchedule(id: number): Promise<void>;
933
+ /** Resume a cron schedule. */
934
+ resumeCronSchedule(id: number): Promise<void>;
935
+ /** Edit a cron schedule. */
936
+ editCronSchedule(id: number, updates: EditCronScheduleOptions, nextRunAt?: Date | null): Promise<void>;
937
+ /**
938
+ * Atomically fetch all active cron schedules whose nextRunAt <= now.
939
+ * In PostgreSQL this uses FOR UPDATE SKIP LOCKED to prevent duplicate enqueuing.
940
+ */
941
+ getDueCronSchedules(): Promise<CronScheduleRecord[]>;
942
+ /**
943
+ * Update a cron schedule after a job has been enqueued.
944
+ * Sets lastEnqueuedAt, lastJobId, and advances nextRunAt.
945
+ */
946
+ updateCronScheduleAfterEnqueue(id: number, lastEnqueuedAt: Date, lastJobId: number, nextRunAt: Date | null): Promise<void>;
777
947
  /** Set a pending reason for unpicked jobs of a given type. */
778
948
  setPendingReasonForUnpickedJobs(reason: string, jobType?: string | string[]): Promise<void>;
779
949
  }
@@ -809,6 +979,32 @@ declare class PostgresBackend implements QueueBackend {
809
979
  * More efficient than individual recordJobEvent calls.
810
980
  */
811
981
  private recordJobEventsBatch;
982
+ /** Create a cron schedule and return its ID. */
983
+ addCronSchedule(input: CronScheduleInput): Promise<number>;
984
+ /** Get a cron schedule by ID. */
985
+ getCronSchedule(id: number): Promise<CronScheduleRecord | null>;
986
+ /** Get a cron schedule by its unique name. */
987
+ getCronScheduleByName(name: string): Promise<CronScheduleRecord | null>;
988
+ /** List cron schedules, optionally filtered by status. */
989
+ listCronSchedules(status?: CronScheduleStatus): Promise<CronScheduleRecord[]>;
990
+ /** Delete a cron schedule by ID. */
991
+ removeCronSchedule(id: number): Promise<void>;
992
+ /** Pause a cron schedule. */
993
+ pauseCronSchedule(id: number): Promise<void>;
994
+ /** Resume a paused cron schedule. */
995
+ resumeCronSchedule(id: number): Promise<void>;
996
+ /** Edit a cron schedule. */
997
+ editCronSchedule(id: number, updates: EditCronScheduleOptions, nextRunAt?: Date | null): Promise<void>;
998
+ /**
999
+ * Atomically fetch all active cron schedules whose nextRunAt <= NOW().
1000
+ * Uses FOR UPDATE SKIP LOCKED to prevent duplicate enqueuing across workers.
1001
+ */
1002
+ getDueCronSchedules(): Promise<CronScheduleRecord[]>;
1003
+ /**
1004
+ * Update a cron schedule after a job has been enqueued.
1005
+ * Sets lastEnqueuedAt, lastJobId, and advances nextRunAt.
1006
+ */
1007
+ updateCronScheduleAfterEnqueue(id: number, lastEnqueuedAt: Date, lastJobId: number, nextRunAt: Date | null): Promise<void>;
812
1008
  setPendingReasonForUnpickedJobs(reason: string, jobType?: string | string[]): Promise<void>;
813
1009
  }
814
1010
 
@@ -863,6 +1059,25 @@ declare function testHandlerSerialization<PayloadMap, T extends keyof PayloadMap
863
1059
  error?: string;
864
1060
  }>;
865
1061
 
1062
+ /**
1063
+ * Calculate the next occurrence of a cron expression after a given date.
1064
+ *
1065
+ * @param cronExpression - A standard cron expression (5 fields, e.g. "0 * * * *").
1066
+ * @param timezone - IANA timezone string (default: "UTC").
1067
+ * @param after - The reference date to compute the next run from (default: now).
1068
+ * @param CronImpl - Cron class for dependency injection (default: croner's Cron).
1069
+ * @returns The next occurrence as a Date, or null if the expression will never fire again.
1070
+ */
1071
+ declare function getNextCronOccurrence(cronExpression: string, timezone?: string, after?: Date, CronImpl?: typeof Cron): Date | null;
1072
+ /**
1073
+ * Validate whether a string is a syntactically correct cron expression.
1074
+ *
1075
+ * @param cronExpression - The cron expression to validate.
1076
+ * @param CronImpl - Cron class for dependency injection (default: croner's Cron).
1077
+ * @returns True if the expression is valid, false otherwise.
1078
+ */
1079
+ declare function validateCronExpression(cronExpression: string, CronImpl?: typeof Cron): boolean;
1080
+
866
1081
  /**
867
1082
  * Initialize the job queue system.
868
1083
  *
@@ -870,4 +1085,4 @@ declare function testHandlerSerialization<PayloadMap, T extends keyof PayloadMap
870
1085
  */
871
1086
  declare const initJobQueue: <PayloadMap = any>(config: JobQueueConfig) => JobQueue<PayloadMap>;
872
1087
 
873
- export { type CreateTokenOptions, type DatabaseSSLConfig, type EditJobOptions, FailureReason, type JobContext, type JobEvent, JobEventType, type JobHandler, type JobHandlers, type JobOptions, type JobQueue, type JobQueueConfig, type JobQueueConfigLegacy, type JobRecord, type JobStatus, type JobType, type OnTimeoutCallback, PostgresBackend, type PostgresJobQueueConfig, type Processor, type ProcessorOptions, type QueueBackend, type RedisJobQueueConfig, type RedisTLSConfig, type TagQueryMode, type WaitDuration, WaitSignal, type WaitToken, type WaitTokenResult, type WaitpointRecord, type WaitpointStatus, initJobQueue, testHandlerSerialization, validateHandlerSerializable };
1088
+ export { type CreateTokenOptions, type CronScheduleInput, type CronScheduleOptions, type CronScheduleRecord, type CronScheduleStatus, type DatabaseSSLConfig, type EditCronScheduleOptions, type EditJobOptions, FailureReason, type JobContext, type JobEvent, JobEventType, type JobHandler, type JobHandlers, type JobOptions, type JobQueue, type JobQueueConfig, type JobQueueConfigLegacy, type JobRecord, type JobStatus, type JobType, type OnTimeoutCallback, PostgresBackend, type PostgresJobQueueConfig, type Processor, type ProcessorOptions, type QueueBackend, type RedisJobQueueConfig, type RedisTLSConfig, type TagQueryMode, type WaitDuration, WaitSignal, type WaitToken, type WaitTokenResult, type WaitpointRecord, type WaitpointStatus, getNextCronOccurrence, initJobQueue, testHandlerSerialization, validateCronExpression, validateHandlerSerializable };