UNPKG

@clickup/ent-framework

Version:

A PostgreSQL graph-database-alike library with microsharding and row-level security

138 lines 6.02 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ToolPing = void 0; const stream_1 = require("stream"); const chalk_1 = __importDefault(require("chalk")); const delay_1 = __importDefault(require("delay")); const compact_1 = __importDefault(require("lodash/compact")); const defaults_1 = __importDefault(require("lodash/defaults")); const first_1 = __importDefault(require("lodash/first")); const misc_1 = require("../abstract/internal/misc"); const QueryPing_1 = require("../abstract/QueryPing"); const Timeline_1 = require("../abstract/Timeline"); const misc_2 = require("../internal/misc"); const formatTimeWithMs_1 = require("./internal/formatTimeWithMs"); const highlightIf_1 = require("./internal/highlightIf"); /** * A tool which plays the role of Linux `ping` command, but for master() or * replica() Client of a Shard. Allows to verify that there is no downtime * happening when a PG node goes down or experiences a failover/switchover. */ class ToolPing { /** * Initializes the instance. */ constructor(options) { this.options = (0, defaults_1.default)({}, options, ToolPing.DEFAULT_OPTIONS); } /** * Runs an endless loop that pings a master() or replica() Client of the * passed Island. Yields the colored output line by line. */ async *[Symbol.asyncIterator]() { const cluster = this.options.cluster; const stream = new stream_1.Readable({ objectMode: true, read() { } }); const oldLoggers = { ...cluster.options.loggers }; cluster.options.loggers.clientQueryLogger = ({ annotations, op, elapsed, error, backend, role, connStats, }) => { const annotation = (0, first_1.default)(annotations); if (op === misc_1.OP_PING || op === misc_1.OP_SHARD_NOS) { stream.push(chalk_1.default[error ? op === misc_1.OP_PING ? "yellowBright" : "yellow" : op === misc_1.OP_PING ? "whiteBright" : "white"]((0, compact_1.default)([ `[${(0, formatTimeWithMs_1.formatTimeWithMs)(new Date(), true)}]`, "clientQueryLogger", op, `backend=${backend}`, (0, highlightIf_1.highlightIf)(`elapsed=${Math.round(elapsed.total).toString().padEnd(2)}`, "bgBlue", () => elapsed.total > 3000), `role=${role}`, `conn.id=${connStats.id}`, `conn.queriesSent=${connStats.queriesSent}`, ...(annotation ? [ (0, highlightIf_1.highlightIf)(`attempt=${annotation.attempt}`, "bgGrey", () => annotation.attempt > 0), `whyClient=${annotation.whyClient}`, `|| ${error ?? "ok"}`, ] : [`|| ${error?.replace(/\s*\[\S+\]$/s, "") ?? "ok"}`]), ]).join(" "))); } }; cluster.options.loggers.swallowedErrorLogger = (props) => { if (props.importance === "low") { return; } stream.push(chalk_1.default.gray([ `[${(0, formatTimeWithMs_1.formatTimeWithMs)(new Date(), true)}]`, "swallowedErrorLogger", (0, highlightIf_1.highlightIf)(`elapsed=${Math.round(props.elapsed ?? 0) .toString() .padEnd(2)}`, "bgBlue", () => (props.elapsed ?? 0) > 3000), `where="${props.where}"`, "||", props.error?.message?.replace(/\n.*/s, ""), ].join(" "))); }; let stop = false; const promise = (async () => { let shard = undefined; try { const shards = [ cluster.globalShard(), ...(await cluster.nonGlobalShards()), ]; shard = (0, misc_2.nullthrows)(shards.find((s) => s.no === this.options.shard), "No such Shard"); } catch (e) { stream.push((0, misc_2.indent)(chalk_1.default.redBright(`Shard selection threw ${e}`))); return; } while (!stop) { try { const startTime = performance.now(); await shard.run(new QueryPing_1.QueryPing({ execTimeMs: this.options.pingExecTimeMs, isWrite: this.options.pingIsWrite, }), { trace: "ping-trace", vc: "ping-vc", debugStack: "", whyClient: undefined, attempt: 0, }, new Timeline_1.Timeline(), null); const duration = Math.round(performance.now() - startTime); stream.push((0, misc_2.indent)(chalk_1.default.green(`ping() succeeded in ${duration} ms`))); } catch (e) { stream.push((0, misc_2.indent)(chalk_1.default.redBright(`ping() threw ${e}`))); } await (0, delay_1.default)(this.options.pingPollMs); } })(); try { for await (const item of stream) { yield item; } } finally { stop = true; await promise; Object.assign(cluster.options.loggers, oldLoggers); } } } exports.ToolPing = ToolPing; /** Default values for the constructor options. */ ToolPing.DEFAULT_OPTIONS = { shard: 0, pingExecTimeMs: 0, pingPollMs: 500, pingIsWrite: false, }; //# sourceMappingURL=ToolPing.js.map