@clickup/pg-microsharding
Version:
Microshards support for PostgreSQL
84 lines (79 loc) • 2.24 kB
text/typescript
import { createConnectedClient } from "./createConnectedClient";
import { subtractLsn } from "./parseLsn";
export interface SlotInfo {
srcLsn: string;
dstLsn: string;
gap: number;
gapTillLatch: number;
lagSec: number | null;
latched: {
srcLsn: string;
at: number;
};
}
/**
* Returns the difference between src LSN and dst LSN (gap), along with some
* estimation on how much seconds they are apart from each other. To measure
* that time, we "latch" an LSN on the src and then wait until dst crosses that
* latched LSN. Once it does, we remember the actual astronomical time it took
* to cross, and then latch the src LSN again (towards the next estimation
* cycle). When the caller decides that the time is small enough, it stops
* polling; and if the time is large (e.g. more than 20 seconds), it continues
* to call getSlotInfo() over and over again until that time drops below the
* needed 20 seconds threshold.
*/
export async function getSlotInfo(
{
dsn,
slotName,
}: {
dsn: string;
slotName: string;
},
prevSlotInfo: SlotInfo | undefined,
): Promise<SlotInfo> {
const client = await createConnectedClient(dsn);
try {
const srcLsn = await client.currentWalInsertLsn();
const dstLsn = await client.confirmedFlushLsn(slotName);
const gap = subtractLsn(srcLsn, dstLsn)!;
if (!prevSlotInfo) {
prevSlotInfo = {
srcLsn,
dstLsn,
gap,
gapTillLatch: gap,
lagSec: null, // means "unknown"
latched: {
srcLsn,
at: performance.now(),
},
};
}
const gapTillLatch = subtractLsn(prevSlotInfo.latched.srcLsn, dstLsn)!;
return gapTillLatch <= 0
? {
srcLsn,
dstLsn,
gap,
gapTillLatch,
lagSec: Math.round(
(performance.now() - prevSlotInfo.latched.at) / 1000,
),
latched: {
srcLsn,
at: performance.now(),
},
}
: {
srcLsn,
dstLsn,
gap,
gapTillLatch,
lagSec: prevSlotInfo.lagSec,
latched: prevSlotInfo.latched,
};
} finally {
await client.end().catch(() => {});
}
}