@indiekitai/pg-dash 0.4.5 → 0.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -300,30 +300,44 @@ SHOW shared_buffers;`,
300
300
  }
301
301
  try {
302
302
  const r = await client.query(`
303
- SELECT pid, state, now() - state_change AS idle_duration,
303
+ SELECT pid,
304
304
  client_addr::text, application_name,
305
305
  extract(epoch from now() - state_change)::int AS idle_seconds
306
306
  FROM pg_stat_activity
307
- WHERE state IN ('idle', 'idle in transaction')
307
+ WHERE state = 'idle in transaction'
308
308
  AND now() - state_change > $1 * interval '1 minute'
309
309
  AND pid != pg_backend_pid()
310
+ ORDER BY idle_seconds DESC
310
311
  `, [longQueryThreshold]);
311
- for (const row of r.rows) {
312
- const isIdleTx = row.state === "idle in transaction";
312
+ if (r.rows.length === 1) {
313
+ const row = r.rows[0];
313
314
  issues.push({
314
- id: `maint-idle-${row.pid}`,
315
- severity: isIdleTx ? "warning" : "info",
315
+ id: `maint-idle-tx-${row.pid}`,
316
+ severity: "warning",
316
317
  category: "maintenance",
317
- title: `${isIdleTx ? "Idle in transaction" : "Idle connection"} (PID ${row.pid})`,
318
- description: `PID ${row.pid} from ${row.client_addr || "local"} (${row.application_name || "unknown"}) has been ${row.state} for ${Math.round(row.idle_seconds / 60)} minutes.`,
318
+ title: `Idle-in-transaction connection (PID ${row.pid})`,
319
+ description: `PID ${row.pid} from ${row.client_addr || "local"} (${row.application_name || "unknown"}) has been idle in transaction for ${Math.round(row.idle_seconds / 60)} minutes. This holds locks and blocks VACUUM.`,
319
320
  fix: `SELECT pg_terminate_backend(${row.pid});`,
320
- impact: isIdleTx ? "Idle-in-transaction connections hold locks and prevent VACUUM." : "Idle connections consume connection slots.",
321
+ impact: "Idle-in-transaction connections hold locks and prevent VACUUM.",
322
+ effort: "quick"
323
+ });
324
+ } else if (r.rows.length > 1) {
325
+ const pids = r.rows.map((row) => row.pid);
326
+ const maxMin = Math.round(r.rows[0].idle_seconds / 60);
327
+ issues.push({
328
+ id: `maint-idle-tx-multi`,
329
+ severity: "warning",
330
+ category: "maintenance",
331
+ title: `${r.rows.length} idle-in-transaction connections (longest: ${maxMin}m)`,
332
+ description: `${r.rows.length} connections have been idle in transaction for over ${longQueryThreshold} minutes. These hold locks and prevent VACUUM from running.`,
333
+ fix: `SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'idle in transaction' AND now() - state_change > interval '${longQueryThreshold} minutes';`,
334
+ impact: "Idle-in-transaction connections hold locks and prevent VACUUM.",
321
335
  effort: "quick"
322
336
  });
323
337
  }
324
338
  } catch (err) {
325
- console.error("[advisor] Error checking idle connections:", err.message);
326
- skipped.push("idle connections: " + err.message);
339
+ console.error("[advisor] Error checking idle-in-transaction connections:", err.message);
340
+ skipped.push("idle-in-transaction: " + err.message);
327
341
  }
328
342
  try {
329
343
  const r = await client.query(`