@forzalabs/remora
Version:
A powerful CLI tool for seamless data translation.
223 lines (222 loc) • 9.1 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const cron = __importStar(require("node-cron"));
const Environment_1 = __importDefault(require("../Environment"));
const ExecutorOrchestrator_1 = __importDefault(require("../../executors/ExecutorOrchestrator"));
const settings_1 = require("../../settings");
class CronScheduler {
constructor() {
this.scheduledJobs = new Map();
this.isInitialized = false;
}
/**
* Initialize the CRON scheduler by scanning all consumers and scheduling those with CRON triggers
*/
initialize() {
if (this.isInitialized) {
console.log('CRON scheduler already initialized');
return;
}
console.log('Initializing CRON scheduler...');
try {
const consumers = Environment_1.default.getAllConsumers();
let cronJobCount = 0;
for (const consumer of consumers) {
if (this.hasCronTrigger(consumer)) {
this.scheduleConsumer(consumer);
cronJobCount++;
}
}
this.isInitialized = true;
console.log(`CRON scheduler initialized with ${cronJobCount} scheduled jobs`);
}
catch (error) {
console.error('Failed to initialize CRON scheduler:', error);
throw error;
}
}
/**
* Check if a consumer has any CRON triggers configured
*/
hasCronTrigger(consumer) {
return consumer.outputs.some(output => { var _a; return ((_a = output.trigger) === null || _a === void 0 ? void 0 : _a.type) === 'CRON' && output.trigger.value; });
}
/**
* Schedule a consumer with CRON triggers
*/
scheduleConsumer(consumer) {
consumer.outputs.forEach((output, index) => {
var _a;
if (((_a = output.trigger) === null || _a === void 0 ? void 0 : _a.type) === 'CRON' && output.trigger.value) {
const jobKey = `${consumer.name}_output_${index}`;
const cronExpression = output.trigger.value;
try {
// Validate CRON expression
if (!cron.validate(cronExpression)) {
console.error(`Invalid CRON expression for consumer ${consumer.name}: ${cronExpression}`);
return;
}
// Schedule the job
const task = cron.schedule(cronExpression, () => __awaiter(this, void 0, void 0, function* () {
yield this.executeConsumerOutput(consumer, output, index);
}));
// Don't start the task immediately, we'll start it manually
task.stop();
this.scheduledJobs.set(jobKey, task);
task.start();
console.log(`Scheduled CRON job for consumer "${consumer.name}" output ${index} with expression: ${cronExpression}`);
}
catch (error) {
console.error(`Failed to schedule CRON job for consumer ${consumer.name}:`, error);
}
}
});
}
/**
* Execute a consumer output when triggered by CRON
*/
executeConsumerOutput(consumer, output, outputIndex) {
return __awaiter(this, void 0, void 0, function* () {
try {
console.log(`Executing CRON job for consumer "${consumer.name}" output ${outputIndex}`);
const user = settings_1.REMORA_WORKER_USER;
const runner = { _id: user._id, name: user.name, type: 'actor' };
const result = yield ExecutorOrchestrator_1.default.launch({
consumer,
details: {
invokedBy: 'CRON',
user: runner
},
logProgress: false
});
console.log(`CRON job completed successfully for consumer "${consumer.name}" output ${outputIndex}`);
// Log execution statistics
if (result) {
console.log(`CRON job stats: ${result.elapsedMS}ms, size: ${result.outputCount}, cycles: ${result.cycles}`);
}
}
catch (error) {
console.error(`CRON job failed for consumer "${consumer.name}" output ${outputIndex}:`, error);
// Optionally, you could implement error handling strategies here:
// - Send notifications
// - Log to a monitoring system
// - Retry logic
// - Disable the job after repeated failures
}
});
}
/**
* Add or update a CRON job for a specific consumer
*/
updateConsumerSchedule(consumer) {
// First, remove any existing schedules for this consumer
this.removeConsumerSchedule(consumer.name);
// Then, add new schedules if they have CRON triggers
if (this.hasCronTrigger(consumer)) {
this.scheduleConsumer(consumer);
}
}
/**
* Remove all scheduled jobs for a consumer
*/
removeConsumerSchedule(consumerName) {
const jobsToRemove = Array.from(this.scheduledJobs.keys()).filter(key => key.startsWith(`${consumerName}_output_`));
jobsToRemove.forEach(jobKey => {
const task = this.scheduledJobs.get(jobKey);
if (task) {
task.stop();
task.destroy();
this.scheduledJobs.delete(jobKey);
console.log(`Removed CRON job: ${jobKey}`);
}
});
}
/**
* Get information about all scheduled jobs
*/
getScheduledJobs() {
return Array.from(this.scheduledJobs.entries()).map(([jobKey, task]) => ({
jobKey,
isRunning: task.getStatus() === 'scheduled'
}));
}
/**
* Stop all scheduled jobs
*/
stopAllJobs() {
console.log('Stopping all CRON jobs...');
this.scheduledJobs.forEach((task, jobKey) => {
task.stop();
task.destroy();
console.log(`Stopped CRON job: ${jobKey}`);
});
this.scheduledJobs.clear();
this.isInitialized = false;
console.log('All CRON jobs stopped');
}
/**
* Restart the scheduler (useful for configuration reloads)
*/
restart() {
console.log('Restarting CRON scheduler...');
this.stopAllJobs();
this.initialize();
}
/**
* Get the scheduler status
*/
getStatus() {
return {
initialized: this.isInitialized,
jobCount: this.scheduledJobs.size,
jobs: this.getScheduledJobs()
};
}
}
// Export a singleton instance
exports.default = new CronScheduler();