@orion-js/dogs 4.6.5 → 4.6.7

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.cjs CHANGED
@@ -222,6 +222,7 @@ __runInitializers(_init, 1, JobsHistoryRepo);
222
222
  var import_helpers = require("@orion-js/helpers");
223
223
  var import_logger = require("@orion-js/logger");
224
224
  var import_mongodb2 = require("@orion-js/mongodb");
225
+ var import_schema3 = require("@orion-js/schema");
225
226
 
226
227
  // src/services/partitions.ts
227
228
  function validatePartitionsCount(nPartitions) {
@@ -661,13 +662,13 @@ var JobsRepo = class {
661
662
  if (jobs.length === 0) {
662
663
  return { scheduledCount: 0, skippedCount: 0, errors: [] };
663
664
  }
664
- let scheduledCount = 0;
665
- let skippedCount = 0;
666
665
  const errors = [];
666
+ const preparedJobs = [];
667
667
  for (let i = 0; i < jobs.length; i++) {
668
668
  const job = jobs[i];
669
669
  try {
670
- await this.jobs.insertOne({
670
+ const record = await (0, import_schema3.clean)(JobRecordSchema, {
671
+ _id: this.jobs.generateId(),
671
672
  jobName: job.name,
672
673
  uniqueIdentifier: job.uniqueIdentifier,
673
674
  params: job.params,
@@ -676,16 +677,60 @@ var JobsRepo = class {
676
677
  type: "event",
677
678
  ...job.partition === void 0 ? {} : { partition: job.partition }
678
679
  });
679
- scheduledCount++;
680
+ await (0, import_schema3.validate)(JobRecordSchema, record);
681
+ preparedJobs.push({ index: i, job, record });
680
682
  } catch (error) {
681
- if (error.isValidationError && Object.values(error.validationErrors).includes("notUnique") && job.uniqueIdentifier) {
682
- import_logger.logger.info(`Job "${job.name}" with identifier "${job.uniqueIdentifier}" already exists`);
683
- skippedCount++;
684
- } else {
683
+ errors.push({
684
+ index: i,
685
+ error: error instanceof Error ? error : new Error(String(error)),
686
+ job
687
+ });
688
+ }
689
+ }
690
+ if (preparedJobs.length === 0) {
691
+ return { scheduledCount: 0, skippedCount: 0, errors };
692
+ }
693
+ const rawCollection = await this.jobs.getRawCollection();
694
+ await this.jobs.createIndexesPromise;
695
+ const operations = preparedJobs.map(
696
+ ({ record }) => record.uniqueIdentifier === void 0 ? { insertOne: { document: record } } : {
697
+ updateOne: {
698
+ filter: { uniqueIdentifier: record.uniqueIdentifier },
699
+ update: { $setOnInsert: record },
700
+ upsert: true
701
+ }
702
+ }
703
+ );
704
+ let scheduledCount = 0;
705
+ let skippedCount = 0;
706
+ try {
707
+ const result = await rawCollection.bulkWrite(operations, { ordered: false });
708
+ scheduledCount = result.insertedCount + result.upsertedCount;
709
+ skippedCount = result.matchedCount;
710
+ } catch (error) {
711
+ const writeErrors = error instanceof import_mongodb2.MongoDB.MongoBulkWriteError ? Array.isArray(error.writeErrors) ? error.writeErrors : [error.writeErrors] : [];
712
+ if (!(error instanceof import_mongodb2.MongoDB.MongoBulkWriteError) || writeErrors.length === 0) {
713
+ for (const preparedJob of preparedJobs) {
685
714
  errors.push({
686
- index: i,
715
+ index: preparedJob.index,
687
716
  error: error instanceof Error ? error : new Error(String(error)),
688
- job
717
+ job: preparedJob.job
718
+ });
719
+ }
720
+ } else {
721
+ scheduledCount = error.result.insertedCount + error.result.upsertedCount;
722
+ skippedCount = error.result.matchedCount;
723
+ for (const writeError of writeErrors) {
724
+ const preparedJob = preparedJobs[writeError.index];
725
+ if (!preparedJob) continue;
726
+ if (writeError.code === 11e3 && preparedJob.record.uniqueIdentifier !== void 0) {
727
+ skippedCount++;
728
+ continue;
729
+ }
730
+ errors.push({
731
+ index: preparedJob.index,
732
+ error: new Error(writeError.errmsg),
733
+ job: preparedJob.job
689
734
  });
690
735
  }
691
736
  }
@@ -849,39 +894,102 @@ var Executor = class {
849
894
  return job.lockTime ?? jobToRun.lockTime;
850
895
  }
851
896
  getContext(job, jobToRun, onStale, isExecutionActive) {
852
- var _a;
853
897
  const effectiveLockTime = this.getEffectiveLockTime(job, jobToRun);
854
- let staleTimeout = setTimeout(() => onStale(), effectiveLockTime);
855
- (_a = staleTimeout.unref) == null ? void 0 : _a.call(staleTimeout);
856
898
  const contextLogger = import_logger3.logger.addMetadata({
857
899
  jobName: jobToRun.name,
858
900
  jobId: jobToRun.jobId
859
901
  });
902
+ let staleTimeout;
903
+ let watchdogCleared = false;
904
+ let staleReported = false;
905
+ let pendingExtraTime;
906
+ let renewalRunning = false;
907
+ let renewalPromise;
908
+ const clearCurrentStaleTimeout = () => {
909
+ if (staleTimeout === void 0) return;
910
+ clearTimeout(staleTimeout);
911
+ staleTimeout = void 0;
912
+ };
913
+ const reportStale = () => {
914
+ if (staleReported) return;
915
+ staleReported = true;
916
+ watchdogCleared = true;
917
+ pendingExtraTime = void 0;
918
+ clearCurrentStaleTimeout();
919
+ onStale();
920
+ };
921
+ const armStaleTimeout = (lockedUntil) => {
922
+ var _a;
923
+ if (watchdogCleared || staleReported || !isExecutionActive()) return;
924
+ clearCurrentStaleTimeout();
925
+ staleTimeout = setTimeout(
926
+ () => {
927
+ staleTimeout = void 0;
928
+ reportStale();
929
+ },
930
+ Math.max(0, lockedUntil - Date.now())
931
+ );
932
+ (_a = staleTimeout.unref) == null ? void 0 : _a.call(staleTimeout);
933
+ };
934
+ const runRenewals = async () => {
935
+ try {
936
+ while (pendingExtraTime !== void 0) {
937
+ const extraTime = pendingExtraTime;
938
+ pendingExtraTime = void 0;
939
+ if (watchdogCleared || staleReported || !isExecutionActive()) {
940
+ clearCurrentStaleTimeout();
941
+ return;
942
+ }
943
+ clearCurrentStaleTimeout();
944
+ const lockedUntil = Date.now() + extraTime;
945
+ let didExtend = false;
946
+ try {
947
+ didExtend = await this.jobsRepo.extendLockTime(
948
+ jobToRun.jobId,
949
+ extraTime,
950
+ jobToRun.lockId
951
+ );
952
+ } catch (error) {
953
+ reportStale();
954
+ throw error;
955
+ }
956
+ if (!didExtend) {
957
+ reportStale();
958
+ return;
959
+ }
960
+ if (watchdogCleared || staleReported || !isExecutionActive()) {
961
+ pendingExtraTime = void 0;
962
+ clearCurrentStaleTimeout();
963
+ return;
964
+ }
965
+ armStaleTimeout(lockedUntil);
966
+ }
967
+ } finally {
968
+ renewalRunning = false;
969
+ renewalPromise = void 0;
970
+ }
971
+ };
972
+ armStaleTimeout(Date.now() + effectiveLockTime);
860
973
  return {
861
974
  definition: job,
862
975
  record: jobToRun,
863
976
  tries: jobToRun.tries || 0,
864
- clearStaleTimeout: () => clearTimeout(staleTimeout),
865
- extendLockTime: async (extraTime) => {
866
- var _a2;
867
- if (!isExecutionActive()) {
977
+ clearStaleTimeout: () => {
978
+ watchdogCleared = true;
979
+ pendingExtraTime = void 0;
980
+ clearCurrentStaleTimeout();
981
+ },
982
+ extendLockTime: (extraTime) => {
983
+ if (watchdogCleared || staleReported || !isExecutionActive()) {
868
984
  contextLogger.warn(`Will not extend lock for stale execution "${jobToRun.executionId}"`);
869
- return;
985
+ return Promise.resolve();
870
986
  }
871
- clearTimeout(staleTimeout);
872
- let didExtend = false;
873
- try {
874
- didExtend = await this.jobsRepo.extendLockTime(jobToRun.jobId, extraTime, jobToRun.lockId);
875
- } catch (error) {
876
- onStale();
877
- throw error;
987
+ pendingExtraTime = Math.max(pendingExtraTime ?? extraTime, extraTime);
988
+ if (!renewalRunning) {
989
+ renewalRunning = true;
990
+ renewalPromise = runRenewals();
878
991
  }
879
- if (!didExtend) {
880
- onStale();
881
- return;
882
- }
883
- staleTimeout = setTimeout(() => onStale(), extraTime);
884
- (_a2 = staleTimeout.unref) == null ? void 0 : _a2.call(staleTimeout);
992
+ return renewalPromise ?? Promise.resolve();
885
993
  },
886
994
  logger: contextLogger
887
995
  };
@@ -1597,7 +1705,7 @@ function setNameToJobs(jobs, nPartitions) {
1597
1705
  }
1598
1706
 
1599
1707
  // src/defineJob/index.ts
1600
- var import_schema3 = require("@orion-js/schema");
1708
+ var import_schema4 = require("@orion-js/schema");
1601
1709
  var import_cron_parser2 = require("cron-parser");
1602
1710
  var import_parse_duration = __toESM(require("parse-duration"), 1);
1603
1711
  function createEventJob(options) {
@@ -1611,7 +1719,7 @@ function createEventJob(options) {
1611
1719
  if (!jobDefinition.jobName) {
1612
1720
  throw new Error("This job has not been registered in the workers");
1613
1721
  }
1614
- const params = jobDefinition.params ? await (0, import_schema3.cleanAndValidate)(jobDefinition.params, scheduleOptions.params) : scheduleOptions.params;
1722
+ const params = jobDefinition.params ? await (0, import_schema4.cleanAndValidate)(jobDefinition.params, scheduleOptions.params) : scheduleOptions.params;
1615
1723
  return await scheduleJobInternal(
1616
1724
  {
1617
1725
  ...scheduleOptions,
@@ -1627,7 +1735,7 @@ function createEventJob(options) {
1627
1735
  }
1628
1736
  const processedJobs = await Promise.all(
1629
1737
  jobs.map(async (scheduleOptions) => {
1630
- const params = jobDefinition.params ? await (0, import_schema3.cleanAndValidate)(jobDefinition.params, scheduleOptions.params) : scheduleOptions.params;
1738
+ const params = jobDefinition.params ? await (0, import_schema4.cleanAndValidate)(jobDefinition.params, scheduleOptions.params) : scheduleOptions.params;
1631
1739
  return {
1632
1740
  ...scheduleOptions,
1633
1741
  name: jobDefinition.jobName,