// runtime/subsystems/jobs/pg-notify.ts
import { Logger } from "@nestjs/common";
import { sql } from "drizzle-orm";
var JOBS_WAKE_CHANNEL = "codegen_jobs_wake";
var EVENTS_WAKE_CHANNEL = "codegen_events_wake";
async function pgNotify(tx, channel, payload) {
  const client = tx;
  await client.execute(sql`select pg_notify(${channel}, ${payload})`);
}
var DEFAULT_BACKOFF_MIN_MS = 100;
var DEFAULT_BACKOFF_MAX_MS = 5e3;
var PgNotifyListener = class {
  constructor(opts) {
    this.opts = opts;
    this.logger = new Logger(`PgNotifyListener(${opts.label})`);
    this.backoffMinMs = opts.backoffMinMs ?? DEFAULT_BACKOFF_MIN_MS;
    this.backoffMaxMs = opts.backoffMaxMs ?? DEFAULT_BACKOFF_MAX_MS;
    this.backoffMs = this.backoffMinMs;
  }
  opts;
  logger;
  client = null;
  stopped = false;
  reconnectTimer = null;
  backoffMs;
  backoffMinMs;
  backoffMaxMs;
  /** WARN-once gate so a flapping listener doesn't spam the log. */
  warnedDown = false;
  /** Begin listening. Idempotent-ish: a second call while connected is a no-op. */
  async start() {
    this.stopped = false;
    await this.connect();
  }
  /** Stop listening + release the connection. Safe to call repeatedly. */
  async stop() {
    this.stopped = true;
    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer);
      this.reconnectTimer = null;
    }
    await this.releaseClient();
  }
  async connect() {
    if (this.stopped) return;
    try {
      const client = await this.opts.pool.connect();
      client.on("notification", (msg) => {
        if (msg.channel !== this.opts.channel) return;
        try {
          this.opts.onNotify(msg.payload ?? "");
        } catch (err) {
          this.logger.error(`onNotify threw: ${err.message}`);
        }
      });
      client.on("error", (err) => {
        this.logger.debug?.(`listener connection error: ${err.message}`);
        this.handleDrop();
      });
      await client.query(`LISTEN ${this.opts.channel}`);
      this.client = client;
      if (this.warnedDown) {
        this.logger.log(
          `listener reconnected; LISTEN ${this.opts.channel} re-established`
        );
        this.warnedDown = false;
      }
      this.backoffMs = this.backoffMinMs;
    } catch (err) {
      this.handleConnectFailure(err);
    }
  }
  /** Connection dropped after being established → reconnect. */
  handleDrop() {
    if (this.stopped) return;
    void this.releaseClient().finally(() => this.scheduleReconnect());
  }
  /** Initial / reconnect `connect()` threw. */
  handleConnectFailure(err) {
    this.scheduleReconnect(err);
  }
  scheduleReconnect(err) {
    if (this.stopped) return;
    if (!this.warnedDown) {
      this.warnedDown = true;
      this.logger.warn(
        `listener down \u2014 falling back to interval polling until reconnect. Cause: ${err instanceof Error ? err.message : "connection lost"}. (This degrades latency, not durability \u2014 polling still drives all work.)`
      );
    }
    if (this.reconnectTimer) clearTimeout(this.reconnectTimer);
    const delay = this.backoffMs;
    this.backoffMs = Math.min(this.backoffMs * 2, this.backoffMaxMs);
    this.reconnectTimer = setTimeout(() => {
      this.reconnectTimer = null;
      void this.connect();
    }, delay);
  }
  async releaseClient() {
    const client = this.client;
    this.client = null;
    if (!client) return;
    try {
      client.removeAllListeners?.("notification");
      client.removeAllListeners?.("error");
      if (client.release) client.release(true);
      else if (client.end) await client.end();
    } catch {
    }
  }
};

export {
  JOBS_WAKE_CHANNEL,
  EVENTS_WAKE_CHANNEL,
  pgNotify,
  PgNotifyListener
};
//# sourceMappingURL=chunk-MYQIQ27N.js.map