@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
JavaScript
;
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;