@oneuptime/common 10.4.13 → 10.4.14

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.
Files changed (103) hide show
  1. package/Models/DatabaseModels/Alert.ts +2 -0
  2. package/Models/DatabaseModels/AlertFeed.ts +1 -0
  3. package/Models/DatabaseModels/CallLog.ts +2 -0
  4. package/Models/DatabaseModels/DockerHost.ts +34 -0
  5. package/Models/DatabaseModels/EmailLog.ts +2 -0
  6. package/Models/DatabaseModels/Host.ts +34 -0
  7. package/Models/DatabaseModels/Incident.ts +1 -0
  8. package/Models/DatabaseModels/IncidentFeed.ts +1 -0
  9. package/Models/DatabaseModels/KubernetesCluster.ts +34 -0
  10. package/Models/DatabaseModels/MonitorFeed.ts +1 -0
  11. package/Models/DatabaseModels/MonitorProbe.ts +1 -0
  12. package/Models/DatabaseModels/OnCallDutyPolicyTimeLog.ts +3 -0
  13. package/Models/DatabaseModels/SmsLog.ts +2 -0
  14. package/Models/DatabaseModels/StatusPageSubscriber.ts +2 -0
  15. package/Models/DatabaseModels/TelemetryException.ts +2 -0
  16. package/Models/DatabaseModels/UserOnCallLog.ts +1 -0
  17. package/Models/DatabaseModels/WorkflowLog.ts +1 -0
  18. package/Server/API/ProjectAPI.ts +52 -15
  19. package/Server/EnvironmentConfig.ts +69 -0
  20. package/Server/Infrastructure/Postgres/DataSourceOptions.ts +26 -1
  21. package/Server/Infrastructure/Postgres/SchemaMigrations/1779392865146-AddAgentVersionToKubernetesDockerHost.ts +29 -0
  22. package/Server/Infrastructure/Postgres/SchemaMigrations/1779392970424-AddPerformanceIndexes.ts +160 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
  24. package/Server/Infrastructure/PostgresDatabase.ts +2 -5
  25. package/Server/Middleware/ProjectAuthorization.ts +31 -53
  26. package/Server/Middleware/UserAuthorization.ts +106 -64
  27. package/Server/Services/ApiKeyService.ts +100 -1
  28. package/Server/Services/DockerHostService.ts +5 -0
  29. package/Server/Services/HostService.ts +6 -0
  30. package/Server/Services/KubernetesClusterService.ts +33 -10
  31. package/Server/Services/MonitorService.ts +10 -3
  32. package/Server/Services/ProjectService.ts +72 -1
  33. package/Server/Services/TeamMemberService.ts +36 -0
  34. package/Server/Services/UserService.ts +38 -0
  35. package/build/dist/Models/DatabaseModels/Alert.js +3 -1
  36. package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
  37. package/build/dist/Models/DatabaseModels/AlertFeed.js +2 -1
  38. package/build/dist/Models/DatabaseModels/AlertFeed.js.map +1 -1
  39. package/build/dist/Models/DatabaseModels/CallLog.js +4 -1
  40. package/build/dist/Models/DatabaseModels/CallLog.js.map +1 -1
  41. package/build/dist/Models/DatabaseModels/DockerHost.js +35 -0
  42. package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -1
  43. package/build/dist/Models/DatabaseModels/EmailLog.js +4 -1
  44. package/build/dist/Models/DatabaseModels/EmailLog.js.map +1 -1
  45. package/build/dist/Models/DatabaseModels/Host.js +35 -0
  46. package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
  47. package/build/dist/Models/DatabaseModels/Incident.js +2 -1
  48. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  49. package/build/dist/Models/DatabaseModels/IncidentFeed.js +2 -1
  50. package/build/dist/Models/DatabaseModels/IncidentFeed.js.map +1 -1
  51. package/build/dist/Models/DatabaseModels/KubernetesCluster.js +35 -0
  52. package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
  53. package/build/dist/Models/DatabaseModels/MonitorFeed.js +2 -1
  54. package/build/dist/Models/DatabaseModels/MonitorFeed.js.map +1 -1
  55. package/build/dist/Models/DatabaseModels/MonitorProbe.js +2 -0
  56. package/build/dist/Models/DatabaseModels/MonitorProbe.js.map +1 -1
  57. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js +3 -0
  58. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js.map +1 -1
  59. package/build/dist/Models/DatabaseModels/SmsLog.js +4 -1
  60. package/build/dist/Models/DatabaseModels/SmsLog.js.map +1 -1
  61. package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js +4 -1
  62. package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js.map +1 -1
  63. package/build/dist/Models/DatabaseModels/TelemetryException.js +3 -1
  64. package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
  65. package/build/dist/Models/DatabaseModels/UserOnCallLog.js +1 -0
  66. package/build/dist/Models/DatabaseModels/UserOnCallLog.js.map +1 -1
  67. package/build/dist/Models/DatabaseModels/WorkflowLog.js +2 -1
  68. package/build/dist/Models/DatabaseModels/WorkflowLog.js.map +1 -1
  69. package/build/dist/Server/API/ProjectAPI.js +42 -14
  70. package/build/dist/Server/API/ProjectAPI.js.map +1 -1
  71. package/build/dist/Server/EnvironmentConfig.js +41 -0
  72. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  73. package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js +20 -2
  74. package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js.map +1 -1
  75. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779392865146-AddAgentVersionToKubernetesDockerHost.js +16 -0
  76. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779392865146-AddAgentVersionToKubernetesDockerHost.js.map +1 -0
  77. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779392970424-AddPerformanceIndexes.js +63 -0
  78. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779392970424-AddPerformanceIndexes.js.map +1 -0
  79. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
  80. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  81. package/build/dist/Server/Infrastructure/PostgresDatabase.js +2 -2
  82. package/build/dist/Server/Infrastructure/PostgresDatabase.js.map +1 -1
  83. package/build/dist/Server/Middleware/ProjectAuthorization.js +21 -39
  84. package/build/dist/Server/Middleware/ProjectAuthorization.js.map +1 -1
  85. package/build/dist/Server/Middleware/UserAuthorization.js +83 -50
  86. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  87. package/build/dist/Server/Services/ApiKeyService.js +86 -0
  88. package/build/dist/Server/Services/ApiKeyService.js.map +1 -1
  89. package/build/dist/Server/Services/DockerHostService.js +5 -1
  90. package/build/dist/Server/Services/DockerHostService.js.map +1 -1
  91. package/build/dist/Server/Services/HostService.js +5 -1
  92. package/build/dist/Server/Services/HostService.js.map +1 -1
  93. package/build/dist/Server/Services/KubernetesClusterService.js +21 -11
  94. package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
  95. package/build/dist/Server/Services/MonitorService.js +8 -3
  96. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  97. package/build/dist/Server/Services/ProjectService.js +65 -1
  98. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  99. package/build/dist/Server/Services/TeamMemberService.js +24 -0
  100. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  101. package/build/dist/Server/Services/UserService.js +36 -0
  102. package/build/dist/Server/Services/UserService.js.map +1 -1
  103. package/package.json +1 -1
@@ -114,6 +114,7 @@ import NotificationRuleWorkspaceChannel from "../../Types/Workspace/Notification
114
114
  delete: true,
115
115
  },
116
116
  })
117
+ @Index(["projectId", "currentAlertStateId"]) // Active-alert counters on dashboard
117
118
  export default class Alert extends BaseModel {
118
119
  @ColumnAccessControl({
119
120
  create: [
@@ -484,6 +485,7 @@ export default class Alert extends BaseModel {
484
485
  Permission.EditAlert,
485
486
  ],
486
487
  })
488
+ @Index()
487
489
  @TableColumn({
488
490
  type: TableColumnType.ObjectID,
489
491
  title: "Monitor ID",
@@ -91,6 +91,7 @@ export enum AlertFeedEventType {
91
91
  tableDescription:
92
92
  "Log of the entire alert state change. This is a log of all the alert state changes, public notes, more etc.",
93
93
  })
94
+ @Index(["alertId", "postedAt"]) // Alert detail page: feed sorted by postedAt
94
95
  export default class AlertFeed extends BaseModel {
95
96
  @ColumnAccessControl({
96
97
  create: [
@@ -61,6 +61,8 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
61
61
  tableDescription:
62
62
  "Logs of all the Call sent out to all users and subscribers for this project.",
63
63
  })
64
+ @Index(["projectId", "createdAt"]) // Notification logs table: time-range filter per project
65
+ @Index(["projectId", "status"]) // Notification logs table: status filter per project
64
66
  export default class CallLog extends BaseModel {
65
67
  @ColumnAccessControl({
66
68
  create: [],
@@ -358,6 +358,40 @@ export default class DockerHost extends BaseModel {
358
358
  })
359
359
  public otelCollectorStatus?: string = undefined;
360
360
 
361
+ @ColumnAccessControl({
362
+ create: [],
363
+ read: [
364
+ Permission.ProjectOwner,
365
+ Permission.ProjectAdmin,
366
+ Permission.ProjectMember,
367
+ Permission.Viewer,
368
+ Permission.SettingsAdmin,
369
+ Permission.SettingsMember,
370
+ Permission.SettingsViewer,
371
+ Permission.ReadDockerHost,
372
+ ],
373
+ update: [
374
+ Permission.ProjectOwner,
375
+ Permission.ProjectAdmin,
376
+ Permission.EditDockerHost,
377
+ ],
378
+ })
379
+ @TableColumn({
380
+ required: false,
381
+ type: TableColumnType.ShortText,
382
+ canReadOnRelationQuery: true,
383
+ title: "Agent Version",
384
+ description:
385
+ "Version of the OneUptime Docker agent reporting telemetry, as self-reported via the oneuptime.agent.version resource attribute",
386
+ example: "1.0.0",
387
+ })
388
+ @Column({
389
+ nullable: true,
390
+ type: ColumnType.ShortText,
391
+ length: ColumnLength.ShortText,
392
+ })
393
+ public agentVersion?: string = undefined;
394
+
361
395
  @ColumnAccessControl({
362
396
  create: [],
363
397
  read: [
@@ -62,6 +62,8 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
62
62
  tableDescription:
63
63
  "Logs of all the Email sent out to all users and subscribers for this project.",
64
64
  })
65
+ @Index(["projectId", "createdAt"]) // Notification logs table: time-range filter per project
66
+ @Index(["projectId", "status"]) // Notification logs table: status filter per project
65
67
  export default class EmailLog extends BaseModel {
66
68
  @ColumnAccessControl({
67
69
  create: [],
@@ -360,6 +360,40 @@ export default class Host extends BaseModel {
360
360
  })
361
361
  public otelCollectorStatus?: string = undefined;
362
362
 
363
+ @ColumnAccessControl({
364
+ create: [],
365
+ read: [
366
+ Permission.ProjectOwner,
367
+ Permission.ProjectAdmin,
368
+ Permission.ProjectMember,
369
+ Permission.Viewer,
370
+ Permission.SettingsAdmin,
371
+ Permission.SettingsMember,
372
+ Permission.SettingsViewer,
373
+ Permission.ReadHost,
374
+ ],
375
+ update: [
376
+ Permission.ProjectOwner,
377
+ Permission.ProjectAdmin,
378
+ Permission.EditHost,
379
+ ],
380
+ })
381
+ @TableColumn({
382
+ required: false,
383
+ type: TableColumnType.ShortText,
384
+ canReadOnRelationQuery: true,
385
+ title: "Agent Version",
386
+ description:
387
+ "Version of the OneUptime agent reporting telemetry on this host, as self-reported via the oneuptime.agent.version resource attribute",
388
+ example: "1.0.0",
389
+ })
390
+ @Column({
391
+ nullable: true,
392
+ type: ColumnType.ShortText,
393
+ length: ColumnLength.ShortText,
394
+ })
395
+ public agentVersion?: string = undefined;
396
+
363
397
  @ColumnAccessControl({
364
398
  create: [],
365
399
  read: [
@@ -118,6 +118,7 @@ import NotificationRuleWorkspaceChannel from "../../Types/Workspace/Notification
118
118
  delete: true,
119
119
  },
120
120
  })
121
+ @Index(["projectId", "currentIncidentStateId"]) // Active-incident counters on dashboard
121
122
  export default class Incident extends BaseModel {
122
123
  @ColumnAccessControl({
123
124
  create: [
@@ -91,6 +91,7 @@ export enum IncidentFeedEventType {
91
91
  tableDescription:
92
92
  "Log of the entire incident state change. This is a log of all the incident state changes, public notes, more etc.",
93
93
  })
94
+ @Index(["incidentId", "postedAt"]) // Incident detail page: feed sorted by postedAt
94
95
  export default class IncidentFeed extends BaseModel {
95
96
  @ColumnAccessControl({
96
97
  create: [
@@ -410,6 +410,40 @@ export default class KubernetesCluster extends BaseModel {
410
410
  })
411
411
  public otelCollectorStatus?: string = undefined;
412
412
 
413
+ @ColumnAccessControl({
414
+ create: [],
415
+ read: [
416
+ Permission.ProjectOwner,
417
+ Permission.ProjectAdmin,
418
+ Permission.ProjectMember,
419
+ Permission.Viewer,
420
+ Permission.SettingsAdmin,
421
+ Permission.SettingsMember,
422
+ Permission.SettingsViewer,
423
+ Permission.ReadKubernetesCluster,
424
+ ],
425
+ update: [
426
+ Permission.ProjectOwner,
427
+ Permission.ProjectAdmin,
428
+ Permission.EditKubernetesCluster,
429
+ ],
430
+ })
431
+ @TableColumn({
432
+ required: false,
433
+ type: TableColumnType.ShortText,
434
+ canReadOnRelationQuery: true,
435
+ title: "Agent Version",
436
+ description:
437
+ "Version of the OneUptime Kubernetes agent reporting telemetry, as self-reported via the oneuptime.agent.version resource attribute",
438
+ example: "1.0.0",
439
+ })
440
+ @Column({
441
+ nullable: true,
442
+ type: ColumnType.ShortText,
443
+ length: ColumnLength.ShortText,
444
+ })
445
+ public agentVersion?: string = undefined;
446
+
413
447
  @ColumnAccessControl({
414
448
  create: [],
415
449
  read: [
@@ -80,6 +80,7 @@ export enum MonitorFeedEventType {
80
80
  tableDescription:
81
81
  "Log of the entire monitor state change. This is a log of all the monitor state changes, public notes, more etc.",
82
82
  })
83
+ @Index(["monitorId", "postedAt"]) // Monitor detail page: feed sorted by postedAt
83
84
  export default class MonitorFeed extends BaseModel {
84
85
  @ColumnAccessControl({
85
86
  create: [
@@ -27,6 +27,7 @@ export type MonitorStepProbeResponse = Dictionary<ProbeMonitorResponse>;
27
27
  @TenantColumn("projectId")
28
28
  @Index(["monitorId", "probeId"]) // Composite index for efficient monitor-probe relationship queries
29
29
  @Index(["monitorId", "projectId"]) // Alternative index for monitor queries within project
30
+ @Index(["probeId", "isEnabled", "nextPingAt"]) // Scheduler hot path: pick due probes per probeId
30
31
  @TableAccessControl({
31
32
  create: [
32
33
  Permission.ProjectOwner,
@@ -483,6 +483,7 @@ export default class OnCallDutyPolicyTimeLog extends BaseModel {
483
483
  ],
484
484
  update: [],
485
485
  })
486
+ @Index()
486
487
  @TableColumn({
487
488
  type: TableColumnType.ObjectID,
488
489
  required: true,
@@ -497,6 +498,7 @@ export default class OnCallDutyPolicyTimeLog extends BaseModel {
497
498
  })
498
499
  public userId?: ObjectID = undefined;
499
500
 
501
+ @Index()
500
502
  @TableColumn({
501
503
  title: "Start At",
502
504
  type: TableColumnType.Date,
@@ -530,6 +532,7 @@ export default class OnCallDutyPolicyTimeLog extends BaseModel {
530
532
  })
531
533
  public startsAt?: Date = undefined;
532
534
 
535
+ @Index()
533
536
  @TableColumn({
534
537
  title: "Ends At",
535
538
  type: TableColumnType.Date,
@@ -61,6 +61,8 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
61
61
  tableDescription:
62
62
  "Logs of all the SMS sent out to all users and subscribers for this project.",
63
63
  })
64
+ @Index(["projectId", "createdAt"]) // Notification logs table: time-range filter per project
65
+ @Index(["projectId", "status"]) // Notification logs table: status filter per project
64
66
  export default class SmsLog extends BaseModel {
65
67
  @ColumnAccessControl({
66
68
  create: [],
@@ -94,6 +94,8 @@ import StatusPageEventType from "../../Types/StatusPage/StatusPageEventType";
94
94
  @Entity({
95
95
  name: "StatusPageSubscriber",
96
96
  })
97
+ @Index(["statusPageId", "subscriberEmail"]) // Dedupe lookup on email subscribe
98
+ @Index(["statusPageId", "subscriberPhone"]) // Dedupe lookup on phone subscribe
97
99
  export default class StatusPageSubscriber extends BaseModel {
98
100
  @ColumnAccessControl({
99
101
  create: [
@@ -62,6 +62,7 @@ import Service from "./Service";
62
62
  @Entity({
63
63
  name: "TelemetryException",
64
64
  })
65
+ @Index(["projectId", "isResolved", "isArchived"]) // Exceptions dashboard counts/filters
65
66
  export default class TelemetryException extends DatabaseBaseModel {
66
67
  @ColumnAccessControl({
67
68
  create: [
@@ -1096,6 +1097,7 @@ export default class TelemetryException extends DatabaseBaseModel {
1096
1097
  Permission.EditTelemetryException,
1097
1098
  ],
1098
1099
  })
1100
+ @Index()
1099
1101
  @TableColumn({
1100
1102
  title: "Occurances",
1101
1103
  description: "Number of times this exception has occurred",
@@ -536,6 +536,7 @@ export default class UserOnCallLog extends BaseModel {
536
536
  read: [Permission.CurrentUser],
537
537
  update: [],
538
538
  })
539
+ @Index()
539
540
  @TableColumn({
540
541
  required: true,
541
542
  type: TableColumnType.ShortText,
@@ -60,6 +60,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
60
60
  icon: IconProp.Logs,
61
61
  tableDescription: "Logs of the workflows executed",
62
62
  })
63
+ @Index(["workflowStatus", "createdAt"]) // Worker sweep for scheduled/timed-out runs
63
64
  export default class WorkflowLog extends BaseModel {
64
65
  @ColumnAccessControl({
65
66
  create: [],
@@ -5,6 +5,7 @@ import ProjectService, {
5
5
  } from "../Services/ProjectService";
6
6
  import ResellerService from "../Services/ResellerService";
7
7
  import TeamMemberService from "../Services/TeamMemberService";
8
+ import QueryHelper from "../Types/Database/QueryHelper";
8
9
  import Select from "../Types/Database/Select";
9
10
  import {
10
11
  ExpressRequest,
@@ -223,25 +224,61 @@ export default class ProjectAPI extends BaseAPI<Project, ProjectServiceType> {
223
224
  }
224
225
  }
225
226
 
226
- // get reseller for each project.
227
+ /*
228
+ * Batch-fetch resellers for every project in one query instead of
229
+ * one findOneById per project.
230
+ */
231
+ const resellerIds: Array<ObjectID> = [];
232
+ const seenResellerIds: Set<string> = new Set<string>();
227
233
  for (const project of projects) {
228
- if (project.resellerId) {
229
- const reseller: Reseller | null =
230
- await ResellerService.findOneById({
231
- id: project.resellerId,
232
- select: {
233
- enableTelemetryFeatures: true,
234
- },
235
- props: {
236
- isRoot: true,
237
- },
238
- });
234
+ if (
235
+ project.resellerId &&
236
+ !seenResellerIds.has(project.resellerId.toString())
237
+ ) {
238
+ seenResellerIds.add(project.resellerId.toString());
239
+ resellerIds.push(project.resellerId);
240
+ }
241
+ }
239
242
 
240
- if (!reseller) {
241
- continue;
243
+ if (resellerIds.length > 0) {
244
+ const resellers: Array<Reseller> = await ResellerService.findBy({
245
+ query: {
246
+ _id: QueryHelper.any(
247
+ resellerIds.map((id: ObjectID) => {
248
+ return id.toString();
249
+ }),
250
+ ),
251
+ },
252
+ select: {
253
+ _id: true,
254
+ enableTelemetryFeatures: true,
255
+ },
256
+ limit: LIMIT_PER_PROJECT,
257
+ skip: 0,
258
+ props: {
259
+ isRoot: true,
260
+ },
261
+ });
262
+
263
+ const resellersById: Map<string, Reseller> = new Map<
264
+ string,
265
+ Reseller
266
+ >();
267
+ for (const reseller of resellers) {
268
+ if (reseller._id) {
269
+ resellersById.set(reseller._id.toString(), reseller);
242
270
  }
271
+ }
243
272
 
244
- project.reseller = reseller;
273
+ for (const project of projects) {
274
+ if (project.resellerId) {
275
+ const reseller: Reseller | undefined = resellersById.get(
276
+ project.resellerId.toString(),
277
+ );
278
+ if (reseller) {
279
+ project.reseller = reseller;
280
+ }
281
+ }
245
282
  }
246
283
  }
247
284
 
@@ -145,6 +145,75 @@ export const ShouldDatabaseSslEnable: boolean = Boolean(
145
145
  DatabaseSslCa || (DatabaseSslCert && DatabaseSslKey),
146
146
  );
147
147
 
148
+ /*
149
+ * Postgres pool size per API/Worker node. TypeORM's default is 10 which
150
+ * starves the API under any meaningful load — pick a number that, when
151
+ * multiplied by the number of running Node processes, stays under the
152
+ * Postgres server's `max_connections` (default 100 on a stock cluster).
153
+ */
154
+ export const MaxPostgresConnections: number = parseInt(
155
+ process.env["DATABASE_MAX_OPEN_CONNECTIONS"] || "50",
156
+ 10,
157
+ );
158
+
159
+ /*
160
+ * Postgres-side statement timeout (ms). Caps the wall-clock time of any
161
+ * single SQL statement. Without this, a single runaway query can pin a
162
+ * connection forever and starve the pool.
163
+ */
164
+ export const PostgresStatementTimeoutMs: number = parseInt(
165
+ process.env["DATABASE_STATEMENT_TIMEOUT_MS"] || "30000",
166
+ 10,
167
+ );
168
+
169
+ /*
170
+ * Node-postgres client-side query timeout (ms). Belt-and-braces for the
171
+ * server-side statement_timeout — fires even if the connection has gone
172
+ * silent or the server-side timeout doesn't kick in.
173
+ */
174
+ export const PostgresQueryTimeoutMs: number = parseInt(
175
+ process.env["DATABASE_QUERY_TIMEOUT_MS"] || "30000",
176
+ 10,
177
+ );
178
+
179
+ /*
180
+ * Postgres-side idle-in-transaction timeout (ms). Kills connections that
181
+ * are stuck holding row locks inside a BEGIN without committing.
182
+ */
183
+ export const PostgresIdleInTransactionTimeoutMs: number = parseInt(
184
+ process.env["DATABASE_IDLE_IN_TRANSACTION_TIMEOUT_MS"] || "60000",
185
+ 10,
186
+ );
187
+
188
+ /*
189
+ * pg-pool acquire timeout (ms). How long a query waits for a free
190
+ * connection before failing. Without this, requests pile up invisibly
191
+ * when the pool is exhausted.
192
+ */
193
+ export const PostgresConnectionAcquireTimeoutMs: number = parseInt(
194
+ process.env["DATABASE_CONNECTION_TIMEOUT_MS"] || "5000",
195
+ 10,
196
+ );
197
+
198
+ /*
199
+ * pg-pool idle connection timeout (ms). Closes connections that have
200
+ * been sitting unused for this long, freeing server-side slots.
201
+ */
202
+ export const PostgresIdleTimeoutMs: number = parseInt(
203
+ process.env["DATABASE_IDLE_TIMEOUT_MS"] || "30000",
204
+ 10,
205
+ );
206
+
207
+ /*
208
+ * TypeORM slow-query log threshold (ms). Any query exceeding this is
209
+ * logged so we can find offenders in production without per-query
210
+ * tracing. Set to 0 to disable.
211
+ */
212
+ export const PostgresSlowQueryLogThresholdMs: number = parseInt(
213
+ process.env["DATABASE_SLOW_QUERY_LOG_THRESHOLD_MS"] || "1000",
214
+ 10,
215
+ );
216
+
148
217
  export const EncryptionSecret: ObjectID = new ObjectID(
149
218
  process.env["ENCRYPTION_SECRET"] || "secret",
150
219
  );
@@ -8,6 +8,13 @@ import {
8
8
  DatabaseSslCert,
9
9
  DatabaseSslKey,
10
10
  DatabaseUsername,
11
+ MaxPostgresConnections,
12
+ PostgresConnectionAcquireTimeoutMs,
13
+ PostgresIdleInTransactionTimeoutMs,
14
+ PostgresIdleTimeoutMs,
15
+ PostgresQueryTimeoutMs,
16
+ PostgresSlowQueryLogThresholdMs,
17
+ PostgresStatementTimeoutMs,
11
18
  ShouldDatabaseSslEnable,
12
19
  } from "../../../Server/EnvironmentConfig";
13
20
  import Migrations from "./SchemaMigrations/Index";
@@ -35,7 +42,25 @@ const dataSourceOptions: DataSourceOptions = {
35
42
  cert: DatabaseSslCert,
36
43
  }
37
44
  : false,
38
- // logging: 'all',
45
+ /*
46
+ * Anything in `extra` is forwarded to the underlying node-postgres pool
47
+ * and client. Pool sizing + timeouts live here because TypeORM's defaults
48
+ * (10 connections, no timeouts) are too small for any non-trivial load.
49
+ */
50
+ extra: {
51
+ max: MaxPostgresConnections,
52
+ idleTimeoutMillis: PostgresIdleTimeoutMs,
53
+ connectionTimeoutMillis: PostgresConnectionAcquireTimeoutMs,
54
+ statement_timeout: PostgresStatementTimeoutMs,
55
+ query_timeout: PostgresQueryTimeoutMs,
56
+ idle_in_transaction_session_timeout: PostgresIdleInTransactionTimeoutMs,
57
+ },
58
+ /*
59
+ * Log any query slower than the configured threshold so we can find
60
+ * offenders in production. TypeORM emits these via the configured
61
+ * logger; the default `advanced-console` logger writes to stdout.
62
+ */
63
+ maxQueryExecutionTime: PostgresSlowQueryLogThresholdMs,
39
64
  synchronize: false,
40
65
  };
41
66
 
@@ -0,0 +1,29 @@
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ export class AddAgentVersionToKubernetesDockerHost1779392865146
4
+ implements MigrationInterface
5
+ {
6
+ name = "AddAgentVersionToKubernetesDockerHost1779392865146";
7
+
8
+ public async up(queryRunner: QueryRunner): Promise<void> {
9
+ await queryRunner.query(
10
+ `ALTER TABLE "KubernetesCluster" ADD "agentVersion" character varying(100)`,
11
+ );
12
+ await queryRunner.query(
13
+ `ALTER TABLE "DockerHost" ADD "agentVersion" character varying(100)`,
14
+ );
15
+ await queryRunner.query(
16
+ `ALTER TABLE "Host" ADD "agentVersion" character varying(100)`,
17
+ );
18
+ }
19
+
20
+ public async down(queryRunner: QueryRunner): Promise<void> {
21
+ await queryRunner.query(`ALTER TABLE "Host" DROP COLUMN "agentVersion"`);
22
+ await queryRunner.query(
23
+ `ALTER TABLE "DockerHost" DROP COLUMN "agentVersion"`,
24
+ );
25
+ await queryRunner.query(
26
+ `ALTER TABLE "KubernetesCluster" DROP COLUMN "agentVersion"`,
27
+ );
28
+ }
29
+ }