UNPKG

@clickup/ent-framework

Version:

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

64 lines 2.67 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TimelineManager = void 0; const misc_1 = require("../internal/misc"); /** * A side effect based container which holds the current master or replica * timeline position. For master, the expectation is that the pos will be * updated after each query only, so no need to use refreshMs. For replica, it's * also updated after each query PLUS the class will call triggerRefresh() hook * not more often than every refreshMs interval. */ class TimelineManager { constructor( /** Time interval after which a replica is declared as "caught up" even if * it's not caught up. This is to not read from master forever when * something has happened with the replica. */ maxLagMs, /** Up to how often we call triggerRefresh(). */ refreshMs, /** This method is called time to time to refresh the data which is later * returned by currentPos(). Makes sense for replica connections which * execute queries rarely: for them, the framework triggers the update when * the fresh data is needed. */ triggerRefresh) { this.maxLagMs = maxLagMs; this.refreshMs = refreshMs; this.triggerRefresh = triggerRefresh; this.pos = BigInt(0); this.changeTime = 0; this.triggerRefreshPromise = null; } /** * Returns the current Client's replication timeline position (e.g. WAL * position). */ async currentPos() { const refreshMs = (0, misc_1.maybeCall)(this.refreshMs); if (performance.now() > this.changeTime + refreshMs) { // Outdated pos; refresh it, also coalesce concurrent requests if any. // Notice that we run this logic not only for replicas, but for masters // too, because we can't distinguish the server role at this place. It's // not a big deal and results into just one extra query within refreshMs // time interval (which is typically ~1 second). try { this.triggerRefreshPromise ??= this.triggerRefresh(); await this.triggerRefreshPromise; } finally { this.triggerRefreshPromise = null; } } return this.pos; } /** * Sets the actual timeline pos. Must be called by the Client after each * interaction with the database. */ setCurrentPos(pos, force) { this.pos = pos > this.pos || force ? pos : this.pos; this.changeTime = performance.now(); } } exports.TimelineManager = TimelineManager; //# sourceMappingURL=TimelineManager.js.map