Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/openstatusHQ/openstatus. ๐ซ Status page with uptime monitoring & API monitoring as code ๐ซ openstatus.dev
bun drizzle-orm monitoring monitoring-as-code nextjs observability on-call open-source shadcn-ui status-page statuspage synthetic-monitoring tinybird turso uptime uptime-checker uptime-monitor
Something went wrong. Try again.
3.7 kB ยท 118 lines
TypeScript
at apifix
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119import { Redis } from "@upstash/redis";
import type { SlackReplyMessage } from "./slack-blocks";
export interface SlackThreadAnchor { ts: string; channelId: string; // The first update lives only in the root message until a second update // arrives and re-renders the root. We stash its reply payload here so the // next update can backfill it into the thread before it's overwritten. pendingRootReply?: SlackReplyMessage;}
export interface SlackAnchorStore { getAnchor( reportId: number, subscriberId: number, ): Promise<SlackThreadAnchor | null>; setAnchor( reportId: number, subscriberId: number, anchor: SlackThreadAnchor, ): Promise<void>; clearAnchor(reportId: number, subscriberId: number): Promise<void>; // Atomically claim delivery of (report, subscriber, update). Returns true only // for the caller that wins the claim; concurrent callers get false and must // skip. This is the dedupe reservation โ a single atomic op, not a // read-then-write pair, so two dispatchers can't both post the same message. reserveDelivery( reportId: number, subscriberId: number, updateId: number, ): Promise<boolean>; // Release a reservation whose post failed, so the delivery can be retried. releaseDelivery( reportId: number, subscriberId: number, updateId: number, ): Promise<void>;}
const TTL_SECONDS = 90 * 24 * 60 * 60;
function anchorKey(reportId: number, subscriberId: number): string { return `slack:report:${reportId}:sub:${subscriberId}`;}
function deliveredKey( reportId: number, subscriberId: number, updateId: number,): string { return `${anchorKey(reportId, subscriberId)}:update:${updateId}`;}
let redisClient: Redis | null = null;
function getRedis(): Redis { if (!redisClient) { redisClient = Redis.fromEnv(); } return redisClient;}
export function createRedisAnchorStore(): SlackAnchorStore { return { async getAnchor(reportId, subscriberId) { const raw = await getRedis().get<SlackThreadAnchor>( anchorKey(reportId, subscriberId), ); return raw ?? null; }, async setAnchor(reportId, subscriberId, anchor) { await getRedis().set(anchorKey(reportId, subscriberId), anchor, { ex: TTL_SECONDS, }); }, async clearAnchor(reportId, subscriberId) { await getRedis().del(anchorKey(reportId, subscriberId)); }, async reserveDelivery(reportId, subscriberId, updateId) { const res = await getRedis().set( deliveredKey(reportId, subscriberId, updateId), 1, { ex: TTL_SECONDS, nx: true }, ); return res === "OK"; }, async releaseDelivery(reportId, subscriberId, updateId) { await getRedis().del(deliveredKey(reportId, subscriberId, updateId)); }, };}
export function createMemoryAnchorStore(): SlackAnchorStore { const anchors = new Map<string, SlackThreadAnchor>(); const delivered = new Set<string>(); return { async getAnchor(reportId, subscriberId) { return anchors.get(anchorKey(reportId, subscriberId)) ?? null; }, async setAnchor(reportId, subscriberId, anchor) { anchors.set(anchorKey(reportId, subscriberId), anchor); }, async clearAnchor(reportId, subscriberId) { anchors.delete(anchorKey(reportId, subscriberId)); }, async reserveDelivery(reportId, subscriberId, updateId) { const key = deliveredKey(reportId, subscriberId, updateId); if (delivered.has(key)) return false; delivered.add(key); return true; }, async releaseDelivery(reportId, subscriberId, updateId) { delivered.delete(deliveredKey(reportId, subscriberId, updateId)); }, };}