redis-smq-common
Version:
Provides essential components and utilities shared across RedisSMQ packages.
96 lines • 3.79 kB
JavaScript
import { RunnableWorker } from '../runnable-worker.js';
import { async } from '../../async/index.js';
import { findFilesByPattern } from '../../env/filesystem.js';
export class WorkerLoader {
logger;
filenamePattern;
onWorkerError;
workerManager;
constructor(logger, filenamePattern, onWorkerError, workerManager) {
this.logger = logger.createLogger(this.constructor.name);
this.filenamePattern = filenamePattern;
this.onWorkerError = onWorkerError;
this.workerManager = workerManager;
}
createWorker(filename, payload) {
const worker = new RunnableWorker(filename, payload, this.logger);
worker.removeAllListeners('worker.error');
worker.on('worker.error', (err) => {
this.onWorkerError(err, filename);
});
this.workerManager.addWorker(worker);
return worker;
}
loadFromDirectory(directory, payload, cb) {
findFilesByPattern(directory, this.filenamePattern, (err, files) => {
if (err) {
this.logger.error(`Failed to read directory ${directory}: ${err.message}`, err);
cb(err);
return;
}
const workerFiles = files ?? [];
if (workerFiles.length === 0) {
this.logger.warn(`No ${this.filenamePattern} files found in ${directory}`);
cb();
return;
}
this.logger.debug(`Found ${workerFiles.length} worker files`);
this.createWorkersBatch(workerFiles, payload, cb);
});
}
createWorkersBatch(filepaths, payload, cb) {
const tempWorkers = [];
async.eachOf(filepaths, (filepath, index, done) => {
this.logger.debug(`Creating worker ${index + 1}/${filepaths.length}: ${filepath}`);
try {
const worker = new RunnableWorker(filepath, payload, this.logger);
worker.on('worker.error', (err) => {
this.logger.debug(`Temporary worker error from ${filepath}: ${err.message}`);
});
tempWorkers.push(worker);
done();
}
catch (error) {
const err = error instanceof Error
? error
: new Error('Failed to create worker');
this.logger.error(`Failed to create worker from ${filepath}: ${err.message}`, err);
done(err);
}
}, (err) => {
if (err) {
this.logger.error(`Error creating workers: ${err.message}`, err);
this.cleanupTempWorkers(tempWorkers, () => cb(err));
return;
}
tempWorkers.forEach((worker) => {
worker.removeAllListeners('worker.error');
worker.on('worker.error', (err) => {
this.onWorkerError(err, worker.getWorkerFilename());
});
this.workerManager.addWorker(worker);
});
this.logger.debug(`Successfully created ${tempWorkers.length} workers`);
cb();
});
}
cleanupTempWorkers(workers, cb) {
if (workers.length === 0) {
cb();
return;
}
this.logger.debug(`Cleaning up ${workers.length} temporary workers...`);
async.each(workers, (worker, _, done) => {
worker.shutdown((err) => {
if (err) {
this.logger.warn(`Temp worker cleanup failed: ${err.message}`);
}
done();
});
}, () => {
this.logger.debug('Temporary workers cleaned up');
cb();
});
}
}
//# sourceMappingURL=worker-loader.js.map