@wpmoo/toolkit 0.9.10 → 0.9.11

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/README.md CHANGED
@@ -171,8 +171,8 @@ npx @wpmoo/toolkit doctor --json --postgres
171
171
  JSON output is optional; human-readable output remains the default.
172
172
  `doctor --postgres` adds read-only PostgreSQL health and performance diagnostics
173
173
  such as database size, sessions currently running queries with
174
- `pg_stat_activity.state = 'active'`, slow-query readiness, extension visibility,
175
- and settings.
174
+ `pg_stat_activity.state = 'active'`, connection utilization against
175
+ `max_connections`, slow-query readiness, extension visibility, and settings.
176
176
  `doctor --json --postgres` includes a structured `postgres` object for automation.
177
177
  Incomplete or malformed PostgreSQL metric rows are reported as unavailable diagnostics.
178
178
 
package/dist/doctor.js CHANGED
@@ -57,6 +57,15 @@ WITH metrics(metric, value) AS (
57
57
  WHERE datname IS NOT NULL
58
58
  AND state = 'active'
59
59
  UNION ALL
60
+ SELECT 'connection_count', count(*)::text
61
+ FROM pg_stat_activity
62
+ WHERE datname IS NOT NULL
63
+ UNION ALL
64
+ SELECT 'max_connections', COALESCE(
65
+ (SELECT setting FROM pg_settings WHERE name = 'max_connections'),
66
+ 'unavailable'
67
+ )
68
+ UNION ALL
60
69
  SELECT 'total_database_size_bytes', COALESCE(sum(pg_database_size(datname)), 0)::text
61
70
  FROM pg_database
62
71
  WHERE datistemplate = false
@@ -83,16 +92,20 @@ FROM metrics
83
92
  ORDER BY CASE metric
84
93
  WHEN 'database_count' THEN 1
85
94
  WHEN 'active_connections' THEN 2
86
- WHEN 'total_database_size_bytes' THEN 3
87
- WHEN 'slow_query_logging' THEN 4
88
- WHEN 'pg_stat_statements' THEN 5
89
- WHEN 'shared_buffers' THEN 6
95
+ WHEN 'connection_count' THEN 3
96
+ WHEN 'max_connections' THEN 4
97
+ WHEN 'total_database_size_bytes' THEN 5
98
+ WHEN 'slow_query_logging' THEN 6
99
+ WHEN 'pg_stat_statements' THEN 7
100
+ WHEN 'shared_buffers' THEN 8
90
101
  ELSE 99
91
102
  END;
92
103
  `.trim();
93
104
  const postgresDiagnosticKeys = [
94
105
  'database_count',
95
106
  'active_connections',
107
+ 'connection_count',
108
+ 'max_connections',
96
109
  'total_database_size_bytes',
97
110
  'slow_query_logging',
98
111
  'pg_stat_statements',
@@ -127,9 +140,14 @@ function parsePostgresDiagnostics(output) {
127
140
  return diagnostics;
128
141
  }
129
142
  function renderPostgresDiagnostics(diagnostics) {
143
+ const connectionUtilizationPct = postgresConnectionUtilizationPct(diagnostics);
130
144
  const parts = postgresDiagnosticKeys.flatMap((key) => {
131
145
  const value = diagnostics[key];
132
- return value ? [`${key}=${value}`] : [];
146
+ const rendered = value ? [`${key}=${value}`] : [];
147
+ if (key === 'max_connections' && connectionUtilizationPct !== undefined) {
148
+ rendered.push(`connection_utilization_pct=${connectionUtilizationPct}`);
149
+ }
150
+ return rendered;
133
151
  });
134
152
  return parts.length > 0 ? `OK PostgreSQL diagnostics ${parts.join(' ')}` : undefined;
135
153
  }
@@ -151,19 +169,50 @@ function malformedPostgresDiagnosticKeys(diagnostics) {
151
169
  const numericKeys = [
152
170
  'database_count',
153
171
  'active_connections',
172
+ 'connection_count',
173
+ 'max_connections',
154
174
  'total_database_size_bytes',
155
175
  ];
156
176
  return numericKeys.filter((key) => diagnostics[key] !== undefined && integerDiagnostic(diagnostics[key]) === undefined);
157
177
  }
178
+ function postgresConnectionUtilizationPct(diagnostics) {
179
+ const connectionCount = integerDiagnostic(diagnostics.connection_count);
180
+ const maxConnections = integerDiagnostic(diagnostics.max_connections);
181
+ if (connectionCount === undefined || maxConnections === undefined || maxConnections <= 0) {
182
+ return undefined;
183
+ }
184
+ return Math.round((connectionCount / maxConnections) * 100);
185
+ }
186
+ function postgresConnectionUtilizationWarning(diagnostics) {
187
+ const connectionCount = integerDiagnostic(diagnostics.connection_count);
188
+ const maxConnections = integerDiagnostic(diagnostics.max_connections);
189
+ const utilizationPct = postgresConnectionUtilizationPct(diagnostics);
190
+ if (connectionCount === undefined ||
191
+ maxConnections === undefined ||
192
+ utilizationPct === undefined ||
193
+ utilizationPct < 80) {
194
+ return undefined;
195
+ }
196
+ return `PostgreSQL connection utilization is high: ${utilizationPct}% of max_connections used (${connectionCount}/${maxConnections}).`;
197
+ }
158
198
  function structuredPostgresDiagnostics(diagnostics) {
159
199
  const structured = {};
160
200
  const databaseCount = integerDiagnostic(diagnostics.database_count);
161
201
  const activeConnections = integerDiagnostic(diagnostics.active_connections);
202
+ const connectionCount = integerDiagnostic(diagnostics.connection_count);
203
+ const maxConnections = integerDiagnostic(diagnostics.max_connections);
204
+ const connectionUtilizationPct = postgresConnectionUtilizationPct(diagnostics);
162
205
  const totalDatabaseSizeBytes = integerDiagnostic(diagnostics.total_database_size_bytes);
163
206
  if (databaseCount !== undefined)
164
207
  structured.databaseCount = databaseCount;
165
208
  if (activeConnections !== undefined)
166
209
  structured.activeConnections = activeConnections;
210
+ if (connectionCount !== undefined)
211
+ structured.connectionCount = connectionCount;
212
+ if (maxConnections !== undefined)
213
+ structured.maxConnections = maxConnections;
214
+ if (connectionUtilizationPct !== undefined)
215
+ structured.connectionUtilizationPct = connectionUtilizationPct;
167
216
  if (totalDatabaseSizeBytes !== undefined)
168
217
  structured.totalDatabaseSizeBytes = totalDatabaseSizeBytes;
169
218
  if (diagnostics.slow_query_logging)
@@ -584,6 +633,10 @@ export async function getDoctorReport(target = process.cwd(), runnerOrOptions =
584
633
  available: true,
585
634
  diagnostics: structuredPostgresDiagnostics(postgresDiagnostics),
586
635
  };
636
+ const connectionUtilizationWarning = postgresConnectionUtilizationWarning(postgresDiagnostics);
637
+ if (connectionUtilizationWarning) {
638
+ warnings.push(connectionUtilizationWarning);
639
+ }
587
640
  }
588
641
  else {
589
642
  const warning = malformedKeys.length > 0
package/dist/help.js CHANGED
@@ -110,7 +110,8 @@ Status and doctor:
110
110
  doctor --fix: applies safe file-level repairs. Runs doctor again after fixes.
111
111
  doctor --postgres: adds read-only PostgreSQL diagnostics such as database size,
112
112
  sessions currently running queries with pg_stat_activity.state = 'active',
113
- slow-query readiness, extension visibility, and settings.
113
+ connection utilization against max_connections, slow-query readiness,
114
+ extension visibility, and settings.
114
115
  Incomplete or malformed PostgreSQL metric rows are reported as unavailable diagnostics.
115
116
 
116
117
  Task recipes:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wpmoo/toolkit",
3
- "version": "0.9.10",
3
+ "version": "0.9.11",
4
4
  "description": "WPMoo Toolkit for development, staging, and production lifecycle workflows.",
5
5
  "type": "module",
6
6
  "repository": {