UNPKG

@rsksmart/rif-storage-pinning

Version:

Application for providing your storage space to other to use in exchange of RIF Tokens

146 lines (145 loc) 6.77 kB
"use strict"; 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 }); exports.JobsManager = exports.Job = exports.FINISHED_EVENT_NAME = void 0; const events_1 = require("events"); const job_model_1 = __importDefault(require("./models/job.model")); const utils_1 = require("./utils"); const logger_1 = require("./logger"); const definitions_1 = require("./definitions"); const communication_1 = require("./communication"); const errors_1 = require("./errors"); const logger = logger_1.loggingFactory('jobs'); exports.FINISHED_EVENT_NAME = 'finished'; class Job extends events_1.EventEmitter { constructor(name, agreementReference, type) { super(); this.entity = new job_model_1.default({ name, type, agreementReference }); } get name() { return this.entity.name; } get type() { return this.entity.type; } get state() { return this.entity.state; } get agreementReference() { return this.entity.agreementReference; } run() { (() => __awaiter(this, void 0, void 0, function* () { try { this.entity.state = definitions_1.JobState.RUNNING; this.entity.start = new Date(Date.now()); yield this.entity.save(); yield this._run(); this.entity.state = definitions_1.JobState.FINISHED; this.entity.finish = new Date(Date.now()); yield this.entity.save(); this.emit(exports.FINISHED_EVENT_NAME); } catch (e) { this.entity.state = definitions_1.JobState.ERRORED; this.entity.finish = new Date(Date.now()); this.entity.errorMessage = e.message; yield this.entity.save(); this.emit('error', e); } }))(); } retry(count, total) { return __awaiter(this, void 0, void 0, function* () { this.entity.retry = `${count}/${total}`; this.entity.state = definitions_1.JobState.BACKOFF; yield this.entity.save(); }); } } exports.Job = Job; const DEFAULT_RETRIES = 3; class JobsManager { constructor(options) { var _a, _b, _c; this.retries = (_a = options === null || options === void 0 ? void 0 : options.retries) !== null && _a !== void 0 ? _a : DEFAULT_RETRIES; this.backoffStart = (_b = options === null || options === void 0 ? void 0 : options.backoffTime) !== null && _b !== void 0 ? _b : 0; this.isExponentialBackoff = (_c = options === null || options === void 0 ? void 0 : options.exponentialBackoff) !== null && _c !== void 0 ? _c : false; } handleError(job, e) { return __awaiter(this, void 0, void 0, function* () { if (errors_1.HashExceedsSizeError.is(e)) { yield communication_1.broadcast(definitions_1.MessageCodesEnum.E_AGREEMENT_SIZE_LIMIT_EXCEEDED, { hash: job.name, size: e.currentSize, expectedSize: e.expectedSize, agreementReference: job.agreementReference }); } else { yield communication_1.broadcast(definitions_1.MessageCodesEnum.E_GENERAL, { hash: job.name, error: e.message }); } throw e; }); } run(job) { return __awaiter(this, void 0, void 0, function* () { const start = process.hrtime(); let backoff = this.backoffStart; for (let retry = 1; retry <= this.retries; retry++) { try { logger.info(`Starting job (${job.name})`); yield communication_1.broadcast(definitions_1.MessageCodesEnum.I_HASH_START, { hash: job.name, agreementReference: job.agreementReference }); yield utils_1.runAndAwaitFirstEvent(job, exports.FINISHED_EVENT_NAME, () => { job.run(); }); yield communication_1.broadcast(definitions_1.MessageCodesEnum.I_HASH_PINNED, { hash: job.name, agreementReference: job.agreementReference }); logger.info(`Finished job in ${process.hrtime(start)[0]}s (${job.name})`); break; // Lets exit then! } catch (e) { // If the Error directly specifies that it does not make sense to retry the Job, exit immediately if (e.retryable === false) { yield this.handleError(job, e); return; } logger.error(`While ${retry}/${this.retries} try of job ${job.name} error happened: ${e}`); if (retry === this.retries) { // Last retry ==> reject the promise yield this.handleError(job, e); } else { yield job.retry(retry, this.retries); yield communication_1.broadcast(definitions_1.MessageCodesEnum.W_HASH_RETRY, { hash: job.name, retryNumber: retry, totalRetries: this.retries, error: e.message, agreementReference: job.agreementReference }); if (backoff > 0) { logger.verbose(`Backing off for ${backoff / 1000}s (${job.name})`); yield utils_1.sleep(backoff); // eslint-disable-next-line max-depth if (this.isExponentialBackoff) { backoff *= 2; } } } } } }); } } exports.JobsManager = JobsManager;