UNPKG

@best/runner-remote

Version:

Best Runner (Headless)

232 lines 9.31 kB
"use strict"; /* * Copyright (c) 2019, salesforce.com, inc. * All rights reserved. * SPDX-License-Identifier: MIT * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.RunnerRemote = void 0; const debug_1 = __importDefault(require("debug")); const path_1 = __importDefault(require("path")); const socket_io_client_1 = require("socket.io-client"); const shared_1 = require("@best/shared"); const utils_1 = require("@best/utils"); const file_uploader_1 = __importDefault(require("./utils/file-uploader")); const create_tar_1 = require("./utils/create-tar"); const { AGENT_REJECTION, BENCHMARK_UPLOAD_REQUEST, CONNECT_ERROR, CONNECT, DISCONNECT, ERROR, RECONNECT_FAILED } = shared_1.BEST_RPC; const { BENCHMARK_END, BENCHMARK_ERROR, BENCHMARK_LOG, BENCHMARK_RESULTS, BENCHMARK_START, BENCHMARK_UPDATE } = shared_1.BEST_RPC; const RPC_METHODS = [ AGENT_REJECTION, BENCHMARK_END, BENCHMARK_ERROR, BENCHMARK_LOG, BENCHMARK_RESULTS, BENCHMARK_START, BENCHMARK_UPDATE, BENCHMARK_UPLOAD_REQUEST, CONNECT_ERROR, CONNECT, DISCONNECT, ERROR, RECONNECT_FAILED, ]; const THROW_FUNCTION = function (err) { throw new Error(err || 'unknown error'); }; const log_rpc = (0, debug_1.default)('runner-remote:rpc'); class RunnerRemote { uri; running = false; uploader; pendingBenchmarks; isHub; socket; benchmarkBuilds; runnerLogStream; benchmarkResults = []; uploadingBenchmark = false; _onBenchmarkError = THROW_FUNCTION; _onBenchmarksRunSuccess = THROW_FUNCTION; constructor(benchmarksBuilds, runnerLogStream, config) { const { isHub, options, specs, token, uri } = config; const socketOptions = { path: '/best', reconnection: false, autoConnect: false, query: { ...options, specs: JSON.stringify(specs), jobs: benchmarksBuilds.length, }, pfx: [], }; if (token) { socketOptions.query.authToken = token; } this.uri = uri; this.isHub = isHub; this.socket = (0, socket_io_client_1.io)(uri, (0, utils_1.proxifiedSocketOptions)(socketOptions)); this.benchmarkBuilds = benchmarksBuilds; this.pendingBenchmarks = benchmarksBuilds.length; this.runnerLogStream = runnerLogStream; RPC_METHODS.forEach((methodName) => this.socket.on(methodName, this[methodName].bind(this))); } // -- Socket lifecycle ---------------------------------------------------------------------- [CONNECT]() { log_rpc(`socket:connect`); } [CONNECT_ERROR]() { log_rpc('socket:error'); this._triggerBenchmarkError(`Unable to connect to agent "${this.uri}" (socket:connect_error)`); } [DISCONNECT]() { log_rpc('socket:disconnect'); this._triggerBenchmarkError('socket:disconnect'); } [ERROR]() { log_rpc('socket:error'); this._triggerBenchmarkError('socket:reconnect_failed'); } [RECONNECT_FAILED]() { log_rpc('reconnect_failed'); this._triggerBenchmarkError('socket:reconnect_failed'); } // -- Specific Best RPC Commands ------------------------------------------------------------ [AGENT_REJECTION](reason) { log_rpc(`agent_rejection: ${AGENT_REJECTION}`); this._triggerBenchmarkError(reason); } [BENCHMARK_UPLOAD_REQUEST]() { const benchmarkConfig = this.benchmarkBuilds.shift(); if (!benchmarkConfig) { return this._triggerBenchmarkError('Agent is requesting more jobs than specified'); } if (this.uploadingBenchmark) { return this._triggerBenchmarkError('Already uploading a benchmark'); } benchmarkConfig.isHub = this.isHub; log_rpc(`${BENCHMARK_UPLOAD_REQUEST} - Sending: ${benchmarkConfig.benchmarkSignature}`); this.socket.emit(shared_1.BEST_RPC.BENCHMARK_UPLOAD_RESPONSE, benchmarkConfig, async (_benchmarkSignature) => { const { benchmarkName, benchmarkEntry, benchmarkRemoteEntry } = benchmarkConfig; const bundleDirname = path_1.default.dirname(benchmarkRemoteEntry || benchmarkEntry); const tarBundle = path_1.default.resolve(bundleDirname, `${benchmarkName}.tgz`); try { /* * Unfortunately, because of the way Best was designed, the hub * does a lot of unnecessary extracting and compressing of files, * when it already has the `tar` it needs to send to the agent. * * Because of that, the more tests Best has to run, the slower things * will be, and sometimes Best will even crash. * * The following is a band-aid fix until a more major refactoring \ * rearchitecting of Best is done. * * Ref: https://github.com/salesforce/best/commit/889191e84607afd93b206d64c68649b5c0905952 */ if (!this.isHub) { await (0, create_tar_1.createTarBundle)(bundleDirname, benchmarkName); } const uploader = await this._getUploaderInstance(); uploader.upload(tarBundle); } catch (err) { return this._triggerBenchmarkError(err.message); } }); } [BENCHMARK_RESULTS](results) { this.benchmarkResults.push(...results); this.pendingBenchmarks -= 1; log_rpc(`${BENCHMARK_UPLOAD_REQUEST} - Received results, pending ${this.pendingBenchmarks}`); if (this.pendingBenchmarks === 0) { if (this.benchmarkBuilds.length === 0) { this._triggerBenchmarkSucess(); } else { this._triggerBenchmarkError('Results missmatch: Agent has sent more jobs that benchmarks consumed...'); } } } // -- Logger methods (must be side effect free) -------------------------------------------------------------------- [BENCHMARK_START](benchmarkSignature) { this.runnerLogStream.onBenchmarkStart(benchmarkSignature); } [BENCHMARK_UPDATE](benchmarkSignature, state, runtimeOpts) { this.runnerLogStream.updateBenchmarkProgress(benchmarkSignature, state, runtimeOpts); } [BENCHMARK_END](benchmarkSignature) { this.runnerLogStream.onBenchmarkEnd(benchmarkSignature); } [BENCHMARK_ERROR](benchmarkSignature) { this.runnerLogStream.onBenchmarkError(benchmarkSignature); } [BENCHMARK_LOG](msg) { this.runnerLogStream.log(msg); } // -- Private -------------------------------------------------------------------- _getUploaderInstance() { if (this.uploader) { return Promise.resolve(this.uploader); } return new Promise((resolve, reject) => { const uploader = new file_uploader_1.default(this.socket); const cancelRejection = setTimeout(() => { reject('[RUNNER_REMOTE] uploader:error | Unable to stablish connection for upload benchmarks'); }, 10000); uploader.on('start', () => { log_rpc('uploader:start'); this.uploadingBenchmark = true; }); uploader.on('error', (err) => { log_rpc('uploader:error'); this._triggerBenchmarkError(err); }); uploader.on('complete', () => { log_rpc('uploader:complete'); this.uploadingBenchmark = false; }); uploader.on('ready', () => { log_rpc('uploader:ready'); this.uploader = uploader; clearTimeout(cancelRejection); resolve(uploader); }); }); } _triggerBenchmarkSucess() { if (this.running) { this.running = false; this.socket.disconnect(); this._onBenchmarksRunSuccess(this.benchmarkResults); this._onBenchmarksRunSuccess = THROW_FUNCTION; // To catch side-effects and race conditions } } _triggerBenchmarkError(error_msg) { if (this.running) { const error = typeof error_msg === 'string' ? new Error(error_msg) : error_msg; this.running = false; this._onBenchmarkError(error); this._onBenchmarkError = THROW_FUNCTION; // To catch side-effects and race conditions } } run() { return new Promise((resolve, reject) => { this._onBenchmarksRunSuccess = resolve; this._onBenchmarkError = reject; this.running = true; this.socket.open(); }); } interruptRunner() { if (this.running) { this.socket.disconnect(); } } } exports.RunnerRemote = RunnerRemote; //# sourceMappingURL=runner-remote.js.map