@memberjunction/scheduling-engine 2.107.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 (33) hide show
  1. package/dist/BaseScheduledJob.d.ts +122 -0
  2. package/dist/BaseScheduledJob.d.ts.map +1 -0
  3. package/dist/BaseScheduledJob.js +105 -0
  4. package/dist/BaseScheduledJob.js.map +1 -0
  5. package/dist/CronExpressionHelper.d.ts +36 -0
  6. package/dist/CronExpressionHelper.d.ts.map +1 -0
  7. package/dist/CronExpressionHelper.js +106 -0
  8. package/dist/CronExpressionHelper.js.map +1 -0
  9. package/dist/NotificationManager.d.ts +19 -0
  10. package/dist/NotificationManager.d.ts.map +1 -0
  11. package/dist/NotificationManager.js +44 -0
  12. package/dist/NotificationManager.js.map +1 -0
  13. package/dist/ScheduledJobEngine.d.ts +188 -0
  14. package/dist/ScheduledJobEngine.d.ts.map +1 -0
  15. package/dist/ScheduledJobEngine.js +601 -0
  16. package/dist/ScheduledJobEngine.js.map +1 -0
  17. package/dist/drivers/ActionScheduledJobDriver.d.ts +40 -0
  18. package/dist/drivers/ActionScheduledJobDriver.d.ts.map +1 -0
  19. package/dist/drivers/ActionScheduledJobDriver.js +175 -0
  20. package/dist/drivers/ActionScheduledJobDriver.js.map +1 -0
  21. package/dist/drivers/AgentScheduledJobDriver.d.ts +40 -0
  22. package/dist/drivers/AgentScheduledJobDriver.d.ts.map +1 -0
  23. package/dist/drivers/AgentScheduledJobDriver.js +149 -0
  24. package/dist/drivers/AgentScheduledJobDriver.js.map +1 -0
  25. package/dist/drivers/index.d.ts +12 -0
  26. package/dist/drivers/index.d.ts.map +1 -0
  27. package/dist/drivers/index.js +35 -0
  28. package/dist/drivers/index.js.map +1 -0
  29. package/dist/index.d.ts +15 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +38 -0
  32. package/dist/index.js.map +1 -0
  33. package/package.json +31 -0
@@ -0,0 +1,601 @@
1
+ "use strict";
2
+ /**
3
+ * @fileoverview Engine for managing and executing scheduled jobs
4
+ * @module @memberjunction/scheduling-engine
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.SchedulingEngine = void 0;
8
+ const core_1 = require("@memberjunction/core");
9
+ const global_1 = require("@memberjunction/global");
10
+ const scheduling_engine_base_1 = require("@memberjunction/scheduling-engine-base");
11
+ const BaseScheduledJob_1 = require("./BaseScheduledJob");
12
+ const CronExpressionHelper_1 = require("./CronExpressionHelper");
13
+ const NotificationManager_1 = require("./NotificationManager");
14
+ (0, scheduling_engine_base_1.LoadBaseSchedulingEngine)(); // Ensure extended entities are loaded
15
+ /**
16
+ * Engine for managing scheduled job execution
17
+ *
18
+ * This engine extends SchedulingEngineBase with execution capabilities:
19
+ * - Evaluates cron expressions to determine which jobs are due
20
+ * - Instantiates the appropriate plugin for each job type
21
+ * - Executes jobs and tracks results in ScheduledJobRun
22
+ * - Sends notifications based on job configuration
23
+ * - Updates job statistics (RunCount, SuccessCount, FailureCount)
24
+ * - Manages distributed locking for multi-server environments
25
+ *
26
+ * @description ONLY USE ON SERVER-SIDE. For metadata only, use SchedulingEngineBase which can be used anywhere.
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * const engine = SchedulingEngine.Instance;
31
+ * await engine.Config(false, contextUser);
32
+ * const runs = await engine.ExecuteScheduledJobs(contextUser);
33
+ * console.log(`Executed ${runs.length} scheduled jobs`);
34
+ * ```
35
+ */
36
+ class SchedulingEngine extends scheduling_engine_base_1.SchedulingEngineBase {
37
+ constructor() {
38
+ super(...arguments);
39
+ this.isPolling = false;
40
+ this.hasInitialized = false;
41
+ }
42
+ /**
43
+ * Get singleton instance
44
+ */
45
+ static get Instance() {
46
+ return super.getInstance();
47
+ }
48
+ /**
49
+ * Start continuous polling for scheduled jobs
50
+ * Uses adaptive interval based on ActivePollingInterval
51
+ *
52
+ * @param contextUser - User context for execution
53
+ */
54
+ StartPolling(contextUser) {
55
+ if (this.isPolling) {
56
+ this.log('Polling already started');
57
+ return;
58
+ }
59
+ this.isPolling = true;
60
+ const poll = async () => {
61
+ // Initialize NextRunAt and clean up stale locks on first poll only
62
+ if (!this.hasInitialized) {
63
+ await this.initializeNextRunTimes(contextUser);
64
+ await this.cleanupStaleLocks(contextUser);
65
+ // Force reload after cleaning locks to ensure we have fresh data
66
+ await this.Config(true, contextUser);
67
+ this.hasInitialized = true;
68
+ // Check if there are no jobs after initialization
69
+ if (this.ScheduledJobs.length === 0) {
70
+ console.log(`📅 Scheduled Jobs: No active jobs found, stopping polling`);
71
+ this.StopPolling();
72
+ return;
73
+ }
74
+ }
75
+ try {
76
+ const runs = await this.ExecuteScheduledJobs(contextUser);
77
+ // Only log if jobs were actually executed
78
+ if (runs.length > 0) {
79
+ console.log(`📅 Scheduled Jobs: Executed ${runs.length} job(s)`);
80
+ }
81
+ // Schedule next poll based on current ActivePollingInterval
82
+ if (this.isPolling) {
83
+ const interval = this.ActivePollingInterval;
84
+ // If interval is null (no jobs), stop polling
85
+ if (interval === null) {
86
+ console.log(`📅 Scheduled Jobs: All jobs removed, stopping polling`);
87
+ this.StopPolling();
88
+ return;
89
+ }
90
+ this.pollingTimer = setTimeout(poll, interval);
91
+ }
92
+ }
93
+ catch (error) {
94
+ this.logError('Error during polling', error);
95
+ // Continue polling even after errors
96
+ if (this.isPolling) {
97
+ this.pollingTimer = setTimeout(poll, 60000); // Fallback to 1 minute
98
+ }
99
+ }
100
+ };
101
+ // Start first poll immediately
102
+ poll();
103
+ }
104
+ /**
105
+ * Stop continuous polling
106
+ */
107
+ StopPolling() {
108
+ if (!this.isPolling) {
109
+ return;
110
+ }
111
+ this.isPolling = false;
112
+ if (this.pollingTimer) {
113
+ clearTimeout(this.pollingTimer);
114
+ this.pollingTimer = undefined;
115
+ }
116
+ this.log('Stopped scheduled job polling');
117
+ }
118
+ /**
119
+ * Check if polling is currently active
120
+ */
121
+ get IsPolling() {
122
+ return this.isPolling;
123
+ }
124
+ /**
125
+ * Handle job changes (create, update, delete)
126
+ * Reloads job metadata and restarts polling if needed
127
+ *
128
+ * This method is called automatically by ScheduledJobEntityExtended.Save() and Delete()
129
+ *
130
+ * @param contextUser - User context for reloading metadata
131
+ */
132
+ async OnJobChanged(contextUser) {
133
+ // Reload jobs from database
134
+ await this.Config(true, contextUser);
135
+ // Recalculate polling interval
136
+ this.UpdatePollingInterval();
137
+ // If polling is stopped and we now have jobs, restart it
138
+ if (!this.isPolling && this.ScheduledJobs.length > 0) {
139
+ console.log(`📅 Scheduled Jobs: Jobs detected, starting polling`);
140
+ this.StartPolling(contextUser);
141
+ }
142
+ }
143
+ /**
144
+ * Execute all scheduled jobs that are currently due
145
+ *
146
+ * Evaluates each active job's cron expression against the current time.
147
+ * Jobs that are due are executed via their plugin's Execute method.
148
+ *
149
+ * @param contextUser - User context for execution
150
+ * @param evalTime - Optional time to evaluate against (defaults to now)
151
+ * @returns Array of scheduled job run records
152
+ */
153
+ async ExecuteScheduledJobs(contextUser, evalTime = new Date()) {
154
+ await this.Config(false, contextUser);
155
+ console.log(`📅 Polling: Checking ${this.ScheduledJobs.length} job(s) at ${evalTime.toISOString()}`);
156
+ const runs = [];
157
+ for (const job of this.ScheduledJobs) {
158
+ console.log(` - ${job.Name}: NextRunAt=${job.NextRunAt?.toISOString() || 'NULL'}, Status=${job.Status}`);
159
+ if (this.isJobDue(job, evalTime)) {
160
+ console.log(` ✓ Job is due, executing...`);
161
+ try {
162
+ const run = await this.executeJob(job, contextUser);
163
+ if (run) { // null if skipped
164
+ runs.push(run);
165
+ }
166
+ else {
167
+ console.log(` ⊘ Job was skipped (locked or queued)`);
168
+ }
169
+ }
170
+ catch (error) {
171
+ this.logError(`Failed to execute job ${job.Name}`, error);
172
+ }
173
+ }
174
+ else {
175
+ console.log(` ⊗ Job is not due yet`);
176
+ }
177
+ }
178
+ // Recalculate polling interval after each poll cycle
179
+ // This ensures we adapt to the narrowest active job schedule
180
+ this.UpdatePollingInterval();
181
+ return runs;
182
+ }
183
+ /**
184
+ * Execute a specific scheduled job by ID
185
+ *
186
+ * @param jobId - ID of the job to execute
187
+ * @param contextUser - User context for execution
188
+ * @returns The scheduled job run record
189
+ */
190
+ async ExecuteScheduledJob(jobId, contextUser) {
191
+ await this.Config(false, contextUser);
192
+ const job = this.ScheduledJobs.find(j => j.ID === jobId);
193
+ if (!job) {
194
+ throw new Error(`Scheduled job ${jobId} not found or not active`);
195
+ }
196
+ return await this.executeJob(job, contextUser);
197
+ }
198
+ /**
199
+ * Determine if a job is currently due for execution
200
+ *
201
+ * @param job - The scheduled job
202
+ * @param evalTime - Time to evaluate against
203
+ * @returns True if the job should execute now
204
+ * @private
205
+ */
206
+ isJobDue(job, evalTime) {
207
+ // Check date range
208
+ if (job.StartAt && evalTime < job.StartAt) {
209
+ return false;
210
+ }
211
+ if (job.EndAt && evalTime > job.EndAt) {
212
+ return false;
213
+ }
214
+ // Check if NextRunAt is set and has passed
215
+ if (!job.NextRunAt) {
216
+ return false;
217
+ }
218
+ // Job is due if NextRunAt is in the past or very close to now (within 1 second tolerance)
219
+ return job.NextRunAt.getTime() <= evalTime.getTime() + 1000;
220
+ }
221
+ /**
222
+ * Execute a single scheduled job
223
+ *
224
+ * @param job - The job to execute
225
+ * @param contextUser - User context
226
+ * @returns The created job run record
227
+ * @private
228
+ */
229
+ async executeJob(job, contextUser) {
230
+ // Try to acquire lock for this job
231
+ const lockAcquired = await this.tryAcquireLock(job);
232
+ if (!lockAcquired) {
233
+ // Handle based on concurrency mode
234
+ if (job.ConcurrencyMode === 'Skip') {
235
+ this.log(`Job ${job.Name} is locked, skipping (ConcurrencyMode=Skip)`);
236
+ return null; // Skip this execution
237
+ }
238
+ else if (job.ConcurrencyMode === 'Queue') {
239
+ this.log(`Job ${job.Name} is locked, queueing (ConcurrencyMode=Queue)`);
240
+ // Create a queued run record for future processing
241
+ return await this.createQueuedJobRun(job, contextUser);
242
+ }
243
+ // Concurrent mode: proceed without lock
244
+ }
245
+ // Create run record
246
+ const run = await this.createJobRun(job, contextUser);
247
+ try {
248
+ // Get job type
249
+ const jobType = this.ScheduledJobTypes.find(t => t.ID === job.JobTypeID);
250
+ if (!jobType) {
251
+ throw new Error(`Job type ${job.JobTypeID} not found`);
252
+ }
253
+ // Instantiate plugin using ClassFactory
254
+ const plugin = global_1.MJGlobal.Instance.ClassFactory.CreateInstance(BaseScheduledJob_1.BaseScheduledJob, jobType.DriverClass);
255
+ if (!plugin) {
256
+ throw new Error(`Failed to create plugin instance: ${jobType.DriverClass}`);
257
+ }
258
+ // Console log job start
259
+ console.log(` ▶️ Starting: ${job.Name}`);
260
+ // Build execution context
261
+ const context = {
262
+ Schedule: job,
263
+ Run: run,
264
+ ContextUser: contextUser
265
+ };
266
+ // Execute the job via plugin
267
+ const result = await plugin.Execute(context);
268
+ // Update run record with result
269
+ run.CompletedAt = new Date();
270
+ run.Status = result.Success ? 'Completed' : 'Failed';
271
+ run.Success = result.Success;
272
+ run.ErrorMessage = result.ErrorMessage || null;
273
+ run.Details = result.Details ? JSON.stringify(result.Details) : null;
274
+ await run.Save();
275
+ // Update job statistics
276
+ await this.updateJobStatistics(job, result.Success, run.ID);
277
+ // Send notifications if configured
278
+ await this.sendNotificationsIfNeeded(job, context, result, plugin);
279
+ // Console log job completion
280
+ const duration = run.CompletedAt.getTime() - run.StartedAt.getTime();
281
+ const status = result.Success ? '✅' : '❌';
282
+ console.log(` ${status} Completed: ${job.Name} (${duration}ms)`);
283
+ return run;
284
+ }
285
+ catch (error) {
286
+ // Update run with failure
287
+ run.CompletedAt = new Date();
288
+ run.Status = 'Failed';
289
+ run.Success = false;
290
+ run.ErrorMessage = error instanceof Error ? error.message : 'Unknown error';
291
+ await run.Save();
292
+ // Update job failure count
293
+ await this.updateJobStatistics(job, false, run.ID);
294
+ this.logError(`Job failed: ${job.Name}`, error);
295
+ return run;
296
+ }
297
+ finally {
298
+ // Release lock if we acquired it
299
+ if (lockAcquired) {
300
+ await this.releaseLock(job);
301
+ }
302
+ }
303
+ }
304
+ /**
305
+ * Create a new ScheduledJobRun record
306
+ *
307
+ * @param job - The scheduled job
308
+ * @param contextUser - User context
309
+ * @returns The created run entity
310
+ * @private
311
+ */
312
+ async createJobRun(job, contextUser) {
313
+ const md = new core_1.Metadata();
314
+ const run = await md.GetEntityObject('MJ: Scheduled Job Runs', contextUser);
315
+ run.ScheduledJobID = job.ID;
316
+ run.ExecutedByUserID = contextUser.ID;
317
+ run.Status = 'Running';
318
+ run.StartedAt = new Date();
319
+ await run.Save();
320
+ return run;
321
+ }
322
+ /**
323
+ * Update job statistics after execution
324
+ *
325
+ * @param job - The scheduled job
326
+ * @param success - Whether the run succeeded
327
+ * @param runId - The run ID
328
+ * @private
329
+ */
330
+ async updateJobStatistics(job, success, runId) {
331
+ job.RunCount++;
332
+ if (success) {
333
+ job.SuccessCount++;
334
+ }
335
+ else {
336
+ job.FailureCount++;
337
+ }
338
+ job.LastRunAt = new Date();
339
+ job.NextRunAt = CronExpressionHelper_1.CronExpressionHelper.GetNextRunTime(job.CronExpression, job.Timezone);
340
+ await job.Save();
341
+ }
342
+ /**
343
+ * Send notifications if configured
344
+ *
345
+ * @param job - The scheduled job
346
+ * @param context - Execution context
347
+ * @param result - Execution result
348
+ * @param plugin - The job plugin
349
+ * @private
350
+ */
351
+ async sendNotificationsIfNeeded(job, context, result, plugin) {
352
+ const shouldNotify = (result.Success && job.NotifyOnSuccess) ||
353
+ (!result.Success && job.NotifyOnFailure);
354
+ if (!shouldNotify) {
355
+ return;
356
+ }
357
+ const recipientUserId = job.NotifyUserID || job.OwnerUserID;
358
+ if (!recipientUserId) {
359
+ return;
360
+ }
361
+ const channels = [];
362
+ if (job.NotifyViaEmail)
363
+ channels.push('Email');
364
+ if (job.NotifyViaInApp)
365
+ channels.push('InApp');
366
+ if (channels.length === 0) {
367
+ return;
368
+ }
369
+ const content = plugin.FormatNotification(context, result);
370
+ await NotificationManager_1.NotificationManager.SendScheduledJobNotification(recipientUserId, content, channels);
371
+ }
372
+ /**
373
+ * Try to acquire a lock for job execution
374
+ * Uses atomic database update to prevent race conditions
375
+ *
376
+ * @param job - The job to lock
377
+ * @returns True if lock acquired, false if already locked
378
+ * @private
379
+ */
380
+ async tryAcquireLock(job) {
381
+ // Check if already locked and not stale
382
+ console.log(` 🔒 tryAcquireLock: job.LockToken=${job.LockToken?.substring(0, 8) || 'NULL'}, ExpectedCompletionAt=${job.ExpectedCompletionAt?.toISOString() || 'NULL'}`);
383
+ if (job.LockToken != null) {
384
+ const now = new Date();
385
+ console.log(` Lock exists! Checking if stale: ExpectedCompletionAt=${job.ExpectedCompletionAt?.toISOString()}, now=${now.toISOString()}`);
386
+ if (job.ExpectedCompletionAt && now > job.ExpectedCompletionAt) {
387
+ console.log(` → Lock is STALE, cleaning up...`);
388
+ this.log(`Detected stale lock on job ${job.Name}, cleaning up`);
389
+ await this.cleanupStaleLock(job);
390
+ }
391
+ else {
392
+ // Lock is active and not stale
393
+ console.log(` → Lock is ACTIVE (not stale), returning false`);
394
+ return false;
395
+ }
396
+ }
397
+ else {
398
+ console.log(` → No lock exists, will try to acquire`);
399
+ }
400
+ // Try to acquire lock using BaseEntity Save for proper change tracking
401
+ const lockToken = this.generateGuid();
402
+ const instanceId = this.getInstanceIdentifier();
403
+ const expectedCompletion = new Date(Date.now() + 10 * 60 * 1000); // 10 minutes default
404
+ try {
405
+ // Reload job from database to ensure we have latest state and enable dirty checking
406
+ await job.Load(job.ID);
407
+ // Verify lock is still null after reload (race condition check)
408
+ if (job.LockToken != null) {
409
+ console.log(` ❌ Lock was acquired by another process during reload`);
410
+ return false;
411
+ }
412
+ // Set lock fields
413
+ job.LockToken = lockToken;
414
+ job.LockedAt = new Date();
415
+ job.LockedByInstance = instanceId;
416
+ job.ExpectedCompletionAt = expectedCompletion;
417
+ console.log(` → Attempting to save with lock: ${lockToken.substring(0, 8)}...`);
418
+ // Save will use optimistic concurrency - fails if another process updated the record
419
+ const saveResult = await job.Save();
420
+ if (saveResult) {
421
+ console.log(` ✅ Lock acquired successfully!`);
422
+ return true;
423
+ }
424
+ else {
425
+ console.log(` ❌ Save failed - likely race condition with another server`);
426
+ // Clear lock state on failure
427
+ job.LockToken = null;
428
+ job.LockedAt = null;
429
+ job.LockedByInstance = null;
430
+ job.ExpectedCompletionAt = null;
431
+ return false;
432
+ }
433
+ }
434
+ catch (error) {
435
+ this.logError(`Failed to acquire lock for job ${job.Name}`, error);
436
+ // Clear any partial lock state
437
+ job.LockToken = null;
438
+ job.LockedAt = null;
439
+ job.LockedByInstance = null;
440
+ job.ExpectedCompletionAt = null;
441
+ return false;
442
+ }
443
+ }
444
+ /**
445
+ * Release a lock after job execution
446
+ *
447
+ * @param job - The job to unlock
448
+ * @private
449
+ */
450
+ async releaseLock(job) {
451
+ try {
452
+ job.LockToken = null;
453
+ job.LockedAt = null;
454
+ job.LockedByInstance = null;
455
+ job.ExpectedCompletionAt = null;
456
+ await job.Save();
457
+ }
458
+ catch (error) {
459
+ this.logError(`Failed to release lock for job ${job.Name}`, error);
460
+ }
461
+ }
462
+ /**
463
+ * Clean up a stale lock (when ExpectedCompletionAt has passed)
464
+ *
465
+ * @param job - The job with stale lock
466
+ * @private
467
+ */
468
+ async cleanupStaleLock(job) {
469
+ this.log(`Cleaning up stale lock on job ${job.Name} (locked by ${job.LockedByInstance})`);
470
+ await this.releaseLock(job);
471
+ }
472
+ /**
473
+ * Create a queued job run for later execution
474
+ *
475
+ * @param job - The job to queue
476
+ * @param contextUser - User context
477
+ * @returns The queued run entity
478
+ * @private
479
+ */
480
+ async createQueuedJobRun(job, contextUser) {
481
+ const md = new core_1.Metadata();
482
+ const run = await md.GetEntityObject('MJ: Scheduled Job Runs', contextUser);
483
+ run.ScheduledJobID = job.ID;
484
+ run.ExecutedByUserID = contextUser.ID;
485
+ run.Status = 'Running'; // Will be picked up by queue processor
486
+ run.QueuedAt = new Date();
487
+ run.StartedAt = new Date();
488
+ await run.Save();
489
+ this.log(`Queued job ${job.Name} for later execution (Run ID: ${run.ID})`);
490
+ return run;
491
+ }
492
+ /**
493
+ * Get unique identifier for this server instance
494
+ *
495
+ * @returns Server instance identifier
496
+ * @private
497
+ */
498
+ getInstanceIdentifier() {
499
+ // Use hostname + process ID for unique instance identification
500
+ const os = require('os');
501
+ return `${os.hostname()}-${process.pid}`;
502
+ }
503
+ /**
504
+ * Generate a GUID for lock tokens
505
+ *
506
+ * @returns Generated GUID
507
+ * @private
508
+ */
509
+ generateGuid() {
510
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
511
+ const r = (Math.random() * 16) | 0;
512
+ const v = c === 'x' ? r : (r & 0x3) | 0x8;
513
+ return v.toString(16);
514
+ });
515
+ }
516
+ /**
517
+ * Initialize NextRunAt for jobs that don't have it set
518
+ * @param contextUser - User context
519
+ * @private
520
+ */
521
+ async initializeNextRunTimes(contextUser) {
522
+ for (const job of this.ScheduledJobs) {
523
+ if (!job.NextRunAt) {
524
+ job.NextRunAt = CronExpressionHelper_1.CronExpressionHelper.GetNextRunTime(job.CronExpression, job.Timezone);
525
+ try {
526
+ await job.Save();
527
+ console.log(` ⚙️ Initialized NextRunAt for ${job.Name} -> ${job.NextRunAt.toISOString()}`);
528
+ }
529
+ catch (error) {
530
+ this.logError(`Failed to initialize NextRunAt for job ${job.Name}`, error);
531
+ }
532
+ }
533
+ }
534
+ }
535
+ /**
536
+ * Clean up stale locks on startup
537
+ * Releases any locks that have expired (ExpectedCompletionAt in the past)
538
+ * @param contextUser - User context
539
+ * @private
540
+ */
541
+ async cleanupStaleLocks(contextUser) {
542
+ const now = new Date();
543
+ let cleanedCount = 0;
544
+ console.log(` 🔍 Checking for stale locks (current time: ${now.toISOString()})...`);
545
+ for (const job of this.ScheduledJobs) {
546
+ if (job.LockToken) {
547
+ console.log(` Job "${job.Name}": LockToken=${job.LockToken?.substring(0, 8)}..., ExpectedCompletionAt=${job.ExpectedCompletionAt?.toISOString() || 'NULL'}`);
548
+ if (job.ExpectedCompletionAt) {
549
+ const isStale = job.ExpectedCompletionAt < now;
550
+ console.log(` → Is stale? ${isStale} (${job.ExpectedCompletionAt.getTime()} < ${now.getTime()} = ${job.ExpectedCompletionAt.getTime() < now.getTime()})`);
551
+ if (isStale) {
552
+ console.log(` 🔓 Cleaning stale lock (locked by ${job.LockedByInstance})`);
553
+ job.LockToken = null;
554
+ job.LockedAt = null;
555
+ job.LockedByInstance = null;
556
+ job.ExpectedCompletionAt = null;
557
+ try {
558
+ await job.Save();
559
+ cleanedCount++;
560
+ }
561
+ catch (error) {
562
+ this.logError(`Failed to clean stale lock for job ${job.Name}`, error);
563
+ }
564
+ }
565
+ }
566
+ else {
567
+ console.log(` ⚠️ Lock exists but no ExpectedCompletionAt - clearing anyway`);
568
+ job.LockToken = null;
569
+ job.LockedAt = null;
570
+ job.LockedByInstance = null;
571
+ job.ExpectedCompletionAt = null;
572
+ try {
573
+ await job.Save();
574
+ cleanedCount++;
575
+ }
576
+ catch (error) {
577
+ this.logError(`Failed to clean stale lock for job ${job.Name}`, error);
578
+ }
579
+ }
580
+ }
581
+ }
582
+ if (cleanedCount > 0) {
583
+ console.log(` ✅ Cleaned ${cleanedCount} stale lock(s)`);
584
+ }
585
+ else {
586
+ console.log(` ✓ No stale locks found`);
587
+ }
588
+ }
589
+ log(message) {
590
+ (0, core_1.LogStatusEx)({
591
+ message: `[ScheduledJobEngine] ${message}`,
592
+ verboseOnly: false,
593
+ isVerboseEnabled: () => false
594
+ });
595
+ }
596
+ logError(message, error) {
597
+ (0, core_1.LogError)(`[ScheduledJobEngine] ${message}`, undefined, error);
598
+ }
599
+ }
600
+ exports.SchedulingEngine = SchedulingEngine;
601
+ //# sourceMappingURL=ScheduledJobEngine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ScheduledJobEngine.js","sourceRoot":"","sources":["../src/ScheduledJobEngine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @fileoverview Driver for executing scheduled Action jobs
3
+ * @module @memberjunction/scheduling-engine
4
+ */
5
+ import { BaseScheduledJob, ScheduledJobExecutionContext } from '../BaseScheduledJob';
6
+ import { ValidationResult } from '@memberjunction/core';
7
+ import { ScheduledJobResult, NotificationContent } from '@memberjunction/scheduling-base-types';
8
+ /**
9
+ * Driver for executing scheduled Action jobs
10
+ *
11
+ * Configuration schema (stored in ScheduledJob.Configuration):
12
+ * {
13
+ * ActionID: string,
14
+ * Params?: Array<{
15
+ * ActionParamID: string,
16
+ * ValueType: 'Static' | 'SQL Statement',
17
+ * Value: string
18
+ * }>
19
+ * }
20
+ *
21
+ * Execution result details (stored in ScheduledJobRun.Details):
22
+ * {
23
+ * ResultCode: string,
24
+ * IsSuccess: boolean,
25
+ * OutputParams?: any
26
+ * }
27
+ */
28
+ export declare class ActionScheduledJobDriver extends BaseScheduledJob {
29
+ Execute(context: ScheduledJobExecutionContext): Promise<ScheduledJobResult>;
30
+ ValidateConfiguration(schedule: any): ValidationResult;
31
+ FormatNotification(context: ScheduledJobExecutionContext, result: ScheduledJobResult): NotificationContent;
32
+ private processParams;
33
+ private executeSQL;
34
+ }
35
+ /**
36
+ * Loader function to ensure this driver is registered
37
+ * Prevents tree-shaking from removing the class
38
+ */
39
+ export declare function LoadActionScheduledJobDriver(): void;
40
+ //# sourceMappingURL=ActionScheduledJobDriver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ActionScheduledJobDriver.d.ts","sourceRoot":"","sources":["../../src/drivers/ActionScheduledJobDriver.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAgE,MAAM,sBAAsB,CAAC;AAGtH,OAAO,EACH,kBAAkB,EAClB,mBAAmB,EAEtB,MAAM,uCAAuC,CAAC;AAG/C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBACa,wBAAyB,SAAQ,gBAAgB;IAC7C,OAAO,CAAC,OAAO,EAAE,4BAA4B,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAmCjF,qBAAqB,CAAC,QAAQ,EAAE,GAAG,GAAG,gBAAgB;IA6DtD,kBAAkB,CACrB,OAAO,EAAE,4BAA4B,EACrC,MAAM,EAAE,kBAAkB,GAC3B,mBAAmB;YAyBR,aAAa;YA0Cb,UAAU;CAU3B;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,IAAI,IAAI,CAEnD"}