@oneuptime/common 11.3.8 → 11.3.10
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/Models/AnalyticsModels/ExceptionInstance.ts +27 -0
- package/Models/AnalyticsModels/Log.ts +1 -0
- package/Models/AnalyticsModels/Metric.ts +1 -0
- package/Models/AnalyticsModels/MutableMetric.ts +333 -0
- package/Models/AnalyticsModels/Profile.ts +1 -0
- package/Models/AnalyticsModels/Span.ts +1 -0
- package/Server/Infrastructure/Queue.ts +19 -2
- package/Server/Infrastructure/QueueWorker.ts +67 -1
- package/Server/Services/AlertService.ts +167 -206
- package/Server/Services/AlertStateTimelineService.ts +121 -1
- package/Server/Services/AnalyticsDatabaseService.ts +19 -23
- package/Server/Services/IncidentService.ts +179 -252
- package/Server/Services/IncidentStateTimelineService.ts +120 -1
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/MetricAggregationService.ts +73 -3
- package/Server/Services/MetricService.ts +228 -0
- package/Server/Services/MutableMetricService.ts +275 -0
- package/Server/Services/TelemetryAttributeService.ts +186 -5
- package/Server/Utils/AnalyticsDatabase/ClusterConfig.ts +2 -0
- package/Server/Utils/AnalyticsDatabase/Statement.ts +2 -0
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +81 -2
- package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +143 -0
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +208 -0
- package/Tests/Types/Metrics/MetricPipelineRuleFilterCondition.test.ts +208 -0
- package/Tests/Types/Monitor/MonitorStepEntityScope.test.ts +0 -56
- package/Types/AnalyticsDatabase/AnalyticsTableEngine.ts +1 -0
- package/Types/AnalyticsDatabase/AnalyticsTableName.ts +1 -0
- package/Types/AnalyticsDatabase/TableColumn.ts +16 -0
- package/Types/Monitor/MonitorStepMetricMonitor.ts +0 -27
- package/build/dist/Models/AnalyticsModels/ExceptionInstance.js +24 -0
- package/build/dist/Models/AnalyticsModels/ExceptionInstance.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Log.js +1 -0
- package/build/dist/Models/AnalyticsModels/Log.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Metric.js +1 -0
- package/build/dist/Models/AnalyticsModels/Metric.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/MutableMetric.js +275 -0
- package/build/dist/Models/AnalyticsModels/MutableMetric.js.map +1 -0
- package/build/dist/Models/AnalyticsModels/Profile.js +1 -0
- package/build/dist/Models/AnalyticsModels/Profile.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Span.js +1 -0
- package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
- package/build/dist/Server/Infrastructure/Queue.js +14 -2
- package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
- package/build/dist/Server/Infrastructure/QueueWorker.js +45 -1
- package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +133 -170
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/AlertStateTimelineService.js +97 -0
- package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +16 -15
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +142 -207
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/IncidentStateTimelineService.js +97 -0
- package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/MetricAggregationService.js +49 -3
- package/build/dist/Server/Services/MetricAggregationService.js.map +1 -1
- package/build/dist/Server/Services/MetricService.js +155 -0
- package/build/dist/Server/Services/MetricService.js.map +1 -1
- package/build/dist/Server/Services/MutableMetricService.js +182 -0
- package/build/dist/Server/Services/MutableMetricService.js.map +1 -0
- package/build/dist/Server/Services/TelemetryAttributeService.js +132 -7
- package/build/dist/Server/Services/TelemetryAttributeService.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/ClusterConfig.js +2 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/ClusterConfig.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js +2 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +66 -2
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
- package/build/dist/Types/AnalyticsDatabase/AnalyticsTableEngine.js +1 -0
- package/build/dist/Types/AnalyticsDatabase/AnalyticsTableEngine.js.map +1 -1
- package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js +1 -0
- package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js.map +1 -1
- package/build/dist/Types/AnalyticsDatabase/TableColumn.js +7 -0
- package/build/dist/Types/AnalyticsDatabase/TableColumn.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js +0 -13
- package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js.map +1 -1
- package/package.json +1 -1
|
@@ -591,6 +591,7 @@ export default class ExceptionInstance extends AnalyticsBaseModel {
|
|
|
591
591
|
required: true,
|
|
592
592
|
defaultValue: {},
|
|
593
593
|
type: TableColumnType.MapStringString,
|
|
594
|
+
mapKeysColumn: "attributeKeys",
|
|
594
595
|
accessControl: {
|
|
595
596
|
read: [
|
|
596
597
|
Permission.ProjectOwner,
|
|
@@ -614,6 +615,23 @@ export default class ExceptionInstance extends AnalyticsBaseModel {
|
|
|
614
615
|
},
|
|
615
616
|
});
|
|
616
617
|
|
|
618
|
+
const attributeKeysColumn: AnalyticsTableColumn = new AnalyticsTableColumn({
|
|
619
|
+
key: "attributeKeys",
|
|
620
|
+
codec: { codec: "ZSTD", level: 3 },
|
|
621
|
+
title: "Attribute Keys",
|
|
622
|
+
description: "Attribute keys extracted from attributes",
|
|
623
|
+
required: true,
|
|
624
|
+
defaultValue: [],
|
|
625
|
+
type: TableColumnType.ArrayText,
|
|
626
|
+
skipIndex: {
|
|
627
|
+
name: "idx_attribute_keys",
|
|
628
|
+
type: SkipIndexType.BloomFilter,
|
|
629
|
+
params: [0.01],
|
|
630
|
+
granularity: 1,
|
|
631
|
+
},
|
|
632
|
+
accessControl: attributesColumn.accessControl,
|
|
633
|
+
});
|
|
634
|
+
|
|
617
635
|
const entityKeysColumn: AnalyticsTableColumn = new AnalyticsTableColumn({
|
|
618
636
|
key: "entityKeys",
|
|
619
637
|
codec: { codec: "ZSTD", level: 3 },
|
|
@@ -788,6 +806,7 @@ export default class ExceptionInstance extends AnalyticsBaseModel {
|
|
|
788
806
|
environmentColumn,
|
|
789
807
|
parsedFramesColumn,
|
|
790
808
|
attributesColumn,
|
|
809
|
+
attributeKeysColumn,
|
|
791
810
|
entityKeysColumn,
|
|
792
811
|
...scalarEntityKeyColumns,
|
|
793
812
|
retentionDateColumn,
|
|
@@ -918,6 +937,14 @@ export default class ExceptionInstance extends AnalyticsBaseModel {
|
|
|
918
937
|
this.setColumnValue("attributes", v);
|
|
919
938
|
}
|
|
920
939
|
|
|
940
|
+
public get attributeKeys(): Array<string> | undefined {
|
|
941
|
+
return this.getColumnValue("attributeKeys") as Array<string> | undefined;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
public set attributeKeys(v: Array<string> | undefined) {
|
|
945
|
+
this.setColumnValue("attributeKeys", v);
|
|
946
|
+
}
|
|
947
|
+
|
|
921
948
|
public get entityKeys(): Array<string> | undefined {
|
|
922
949
|
return this.getColumnValue("entityKeys") as Array<string> | undefined;
|
|
923
950
|
}
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import AnalyticsBaseModel from "./AnalyticsBaseModel/AnalyticsBaseModel";
|
|
2
|
+
import { MetricPointType } from "./Metric";
|
|
3
|
+
import AnalyticsTableEngine from "../../Types/AnalyticsDatabase/AnalyticsTableEngine";
|
|
4
|
+
import AnalyticsTableName from "../../Types/AnalyticsDatabase/AnalyticsTableName";
|
|
5
|
+
import AnalyticsTableColumn, {
|
|
6
|
+
SkipIndexType,
|
|
7
|
+
} from "../../Types/AnalyticsDatabase/TableColumn";
|
|
8
|
+
import TableColumnType from "../../Types/AnalyticsDatabase/TableColumnType";
|
|
9
|
+
import { JSONObject } from "../../Types/JSON";
|
|
10
|
+
import ObjectID from "../../Types/ObjectID";
|
|
11
|
+
import ServiceType from "../../Types/Telemetry/ServiceType";
|
|
12
|
+
|
|
13
|
+
export default class MutableMetric extends AnalyticsBaseModel {
|
|
14
|
+
public constructor() {
|
|
15
|
+
const projectIdColumn: AnalyticsTableColumn = new AnalyticsTableColumn({
|
|
16
|
+
key: "projectId",
|
|
17
|
+
title: "Project ID",
|
|
18
|
+
description: "ID of project",
|
|
19
|
+
required: true,
|
|
20
|
+
type: TableColumnType.ObjectID,
|
|
21
|
+
isTenantId: true,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const primaryEntityIdColumn: AnalyticsTableColumn =
|
|
25
|
+
new AnalyticsTableColumn({
|
|
26
|
+
key: "primaryEntityId",
|
|
27
|
+
title: "Primary Entity ID",
|
|
28
|
+
description: "ID of the incident, alert, or other entity.",
|
|
29
|
+
required: true,
|
|
30
|
+
type: TableColumnType.ObjectID,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const primaryEntityTypeColumn: AnalyticsTableColumn =
|
|
34
|
+
new AnalyticsTableColumn({
|
|
35
|
+
key: "primaryEntityType",
|
|
36
|
+
isLowCardinality: true,
|
|
37
|
+
title: "Primary Entity Type",
|
|
38
|
+
description: "Type of the primary entity.",
|
|
39
|
+
required: true,
|
|
40
|
+
type: TableColumnType.Text,
|
|
41
|
+
skipIndex: {
|
|
42
|
+
name: "idx_mutable_metric_entity_type",
|
|
43
|
+
type: SkipIndexType.Set,
|
|
44
|
+
params: [10],
|
|
45
|
+
granularity: 4,
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const nameColumn: AnalyticsTableColumn = new AnalyticsTableColumn({
|
|
50
|
+
key: "name",
|
|
51
|
+
codec: { codec: "ZSTD", level: 1 },
|
|
52
|
+
title: "Name",
|
|
53
|
+
description: "Name of the metric.",
|
|
54
|
+
required: true,
|
|
55
|
+
type: TableColumnType.Text,
|
|
56
|
+
skipIndex: {
|
|
57
|
+
name: "idx_mutable_metric_name",
|
|
58
|
+
type: SkipIndexType.BloomFilter,
|
|
59
|
+
params: [0.01],
|
|
60
|
+
granularity: 1,
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const metricPointIdColumn: AnalyticsTableColumn = new AnalyticsTableColumn({
|
|
65
|
+
key: "metricPointId",
|
|
66
|
+
codec: { codec: "ZSTD", level: 1 },
|
|
67
|
+
title: "Metric Point ID",
|
|
68
|
+
description:
|
|
69
|
+
"Stable identity for the mutable metric point within its entity and metric name.",
|
|
70
|
+
required: true,
|
|
71
|
+
type: TableColumnType.Text,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const metricPointTypeColumn: AnalyticsTableColumn =
|
|
75
|
+
new AnalyticsTableColumn({
|
|
76
|
+
key: "metricPointType",
|
|
77
|
+
isLowCardinality: true,
|
|
78
|
+
title: "Metric Point Type",
|
|
79
|
+
description: "Metric point type.",
|
|
80
|
+
required: false,
|
|
81
|
+
type: TableColumnType.Text,
|
|
82
|
+
skipIndex: {
|
|
83
|
+
name: "idx_mutable_metric_point_type",
|
|
84
|
+
type: SkipIndexType.Set,
|
|
85
|
+
params: [5],
|
|
86
|
+
granularity: 4,
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const timeColumn: AnalyticsTableColumn = new AnalyticsTableColumn({
|
|
91
|
+
key: "time",
|
|
92
|
+
codec: [{ codec: "DoubleDelta" }, { codec: "ZSTD", level: 1 }],
|
|
93
|
+
title: "Time",
|
|
94
|
+
description: "When this metric point happened.",
|
|
95
|
+
required: true,
|
|
96
|
+
type: TableColumnType.DateTime64,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const timeUnixNanoColumn: AnalyticsTableColumn = new AnalyticsTableColumn({
|
|
100
|
+
key: "timeUnixNano",
|
|
101
|
+
codec: [{ codec: "DoubleDelta" }, { codec: "ZSTD", level: 1 }],
|
|
102
|
+
title: "Time (in Unix Nano)",
|
|
103
|
+
description: "When this metric point happened.",
|
|
104
|
+
required: true,
|
|
105
|
+
type: TableColumnType.UInt64,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const attributesColumn: AnalyticsTableColumn = new AnalyticsTableColumn({
|
|
109
|
+
key: "attributes",
|
|
110
|
+
codec: { codec: "ZSTD", level: 3 },
|
|
111
|
+
title: "Attributes",
|
|
112
|
+
description: "Metric attributes.",
|
|
113
|
+
required: true,
|
|
114
|
+
type: TableColumnType.MapStringString,
|
|
115
|
+
defaultValue: {},
|
|
116
|
+
mapKeysColumn: "attributeKeys",
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const attributeKeysColumn: AnalyticsTableColumn = new AnalyticsTableColumn({
|
|
120
|
+
key: "attributeKeys",
|
|
121
|
+
codec: { codec: "ZSTD", level: 3 },
|
|
122
|
+
title: "Attribute Keys",
|
|
123
|
+
description: "Attribute keys extracted from attributes.",
|
|
124
|
+
required: true,
|
|
125
|
+
defaultValue: [],
|
|
126
|
+
type: TableColumnType.ArrayText,
|
|
127
|
+
skipIndex: {
|
|
128
|
+
name: "idx_mutable_metric_attribute_keys",
|
|
129
|
+
type: SkipIndexType.BloomFilter,
|
|
130
|
+
params: [0.01],
|
|
131
|
+
granularity: 1,
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
const valueColumn: AnalyticsTableColumn = new AnalyticsTableColumn({
|
|
136
|
+
key: "value",
|
|
137
|
+
codec: [{ codec: "Gorilla" }, { codec: "ZSTD", level: 1 }],
|
|
138
|
+
title: "Value",
|
|
139
|
+
description: "Metric value.",
|
|
140
|
+
required: false,
|
|
141
|
+
type: TableColumnType.Decimal,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const versionColumn: AnalyticsTableColumn = new AnalyticsTableColumn({
|
|
145
|
+
key: "version",
|
|
146
|
+
codec: [{ codec: "DoubleDelta" }, { codec: "ZSTD", level: 1 }],
|
|
147
|
+
title: "Version",
|
|
148
|
+
description:
|
|
149
|
+
"Monotonic version for ReplacingMergeTree and version-aware reads.",
|
|
150
|
+
required: true,
|
|
151
|
+
type: TableColumnType.UInt64,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
const isDeletedColumn: AnalyticsTableColumn = new AnalyticsTableColumn({
|
|
155
|
+
key: "isDeleted",
|
|
156
|
+
title: "Is Deleted",
|
|
157
|
+
description: "Tombstone marker for this metric point identity.",
|
|
158
|
+
required: true,
|
|
159
|
+
type: TableColumnType.Boolean,
|
|
160
|
+
defaultValue: false,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const retentionDateColumn: AnalyticsTableColumn = new AnalyticsTableColumn({
|
|
164
|
+
key: "retentionDate",
|
|
165
|
+
codec: [{ codec: "DoubleDelta" }, { codec: "ZSTD", level: 1 }],
|
|
166
|
+
title: "Retention Date",
|
|
167
|
+
description: "Date after which this row is eligible for TTL deletion.",
|
|
168
|
+
required: true,
|
|
169
|
+
type: TableColumnType.Date,
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
super({
|
|
173
|
+
tableName: AnalyticsTableName.MutableMetric,
|
|
174
|
+
tableEngine: AnalyticsTableEngine.ReplacingMergeTree,
|
|
175
|
+
singularName: "Mutable Metric",
|
|
176
|
+
pluralName: "Mutable Metrics",
|
|
177
|
+
tableDescription:
|
|
178
|
+
"Versioned derived metric points for lifecycle metrics that can be corrected after initial emission.",
|
|
179
|
+
tableColumns: [
|
|
180
|
+
projectIdColumn,
|
|
181
|
+
primaryEntityIdColumn,
|
|
182
|
+
primaryEntityTypeColumn,
|
|
183
|
+
nameColumn,
|
|
184
|
+
metricPointIdColumn,
|
|
185
|
+
metricPointTypeColumn,
|
|
186
|
+
timeColumn,
|
|
187
|
+
timeUnixNanoColumn,
|
|
188
|
+
attributesColumn,
|
|
189
|
+
attributeKeysColumn,
|
|
190
|
+
valueColumn,
|
|
191
|
+
versionColumn,
|
|
192
|
+
isDeletedColumn,
|
|
193
|
+
retentionDateColumn,
|
|
194
|
+
],
|
|
195
|
+
projections: [],
|
|
196
|
+
sortKeys: [
|
|
197
|
+
"projectId",
|
|
198
|
+
"name",
|
|
199
|
+
"primaryEntityType",
|
|
200
|
+
"primaryEntityId",
|
|
201
|
+
"metricPointId",
|
|
202
|
+
],
|
|
203
|
+
primaryKeys: [
|
|
204
|
+
"projectId",
|
|
205
|
+
"name",
|
|
206
|
+
"primaryEntityType",
|
|
207
|
+
"primaryEntityId",
|
|
208
|
+
"metricPointId",
|
|
209
|
+
],
|
|
210
|
+
partitionKey: "toYYYYMM(retentionDate)",
|
|
211
|
+
shardingKey:
|
|
212
|
+
"cityHash64(projectId, name, primaryEntityType, primaryEntityId, metricPointId)",
|
|
213
|
+
tableSettings:
|
|
214
|
+
"ttl_only_drop_parts = 1, non_replicated_deduplication_window = 10000",
|
|
215
|
+
ttlExpression: "retentionDate DELETE",
|
|
216
|
+
defaultSortColumn: "time",
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
public get projectId(): ObjectID | undefined {
|
|
221
|
+
return this.getColumnValue("projectId") as ObjectID | undefined;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
public set projectId(v: ObjectID | undefined) {
|
|
225
|
+
this.setColumnValue("projectId", v);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
public get primaryEntityId(): ObjectID | undefined {
|
|
229
|
+
return this.getColumnValue("primaryEntityId") as ObjectID | undefined;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
public set primaryEntityId(v: ObjectID | undefined) {
|
|
233
|
+
this.setColumnValue("primaryEntityId", v);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
public get primaryEntityType(): ServiceType | undefined {
|
|
237
|
+
return this.getColumnValue("primaryEntityType") as ServiceType | undefined;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
public set primaryEntityType(v: ServiceType | undefined) {
|
|
241
|
+
this.setColumnValue("primaryEntityType", v);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
public get name(): string | undefined {
|
|
245
|
+
return this.getColumnValue("name") as string | undefined;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
public set name(v: string | undefined) {
|
|
249
|
+
this.setColumnValue("name", v);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
public get metricPointId(): string | undefined {
|
|
253
|
+
return this.getColumnValue("metricPointId") as string | undefined;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
public set metricPointId(v: string | undefined) {
|
|
257
|
+
this.setColumnValue("metricPointId", v);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
public get metricPointType(): MetricPointType | undefined {
|
|
261
|
+
return this.getColumnValue("metricPointType") as
|
|
262
|
+
| MetricPointType
|
|
263
|
+
| undefined;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
public set metricPointType(v: MetricPointType | undefined) {
|
|
267
|
+
this.setColumnValue("metricPointType", v);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
public get time(): Date | undefined {
|
|
271
|
+
return this.getColumnValue("time") as Date | undefined;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
public set time(v: Date | undefined) {
|
|
275
|
+
this.setColumnValue("time", v);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
public get timeUnixNano(): number | undefined {
|
|
279
|
+
return this.getColumnValue("timeUnixNano") as number | undefined;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
public set timeUnixNano(v: number | undefined) {
|
|
283
|
+
this.setColumnValue("timeUnixNano", v);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
public get attributes(): JSONObject | undefined {
|
|
287
|
+
return this.getColumnValue("attributes") as JSONObject | undefined;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
public set attributes(v: JSONObject | undefined) {
|
|
291
|
+
this.setColumnValue("attributes", v);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
public get attributeKeys(): Array<string> | undefined {
|
|
295
|
+
return this.getColumnValue("attributeKeys") as Array<string> | undefined;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
public set attributeKeys(v: Array<string> | undefined) {
|
|
299
|
+
this.setColumnValue("attributeKeys", v);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
public get value(): number | undefined {
|
|
303
|
+
return this.getColumnValue("value") as number | undefined;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
public set value(v: number | undefined) {
|
|
307
|
+
this.setColumnValue("value", v);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
public get version(): number | undefined {
|
|
311
|
+
return this.getColumnValue("version") as number | undefined;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
public set version(v: number | undefined) {
|
|
315
|
+
this.setColumnValue("version", v);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
public get isDeleted(): boolean | undefined {
|
|
319
|
+
return this.getColumnValue("isDeleted") as boolean | undefined;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
public set isDeleted(v: boolean | undefined) {
|
|
323
|
+
this.setColumnValue("isDeleted", v);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
public get retentionDate(): Date | undefined {
|
|
327
|
+
return this.getColumnValue("retentionDate") as Date | undefined;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
public set retentionDate(v: Date | undefined) {
|
|
331
|
+
this.setColumnValue("retentionDate", v);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
@@ -455,6 +455,23 @@ export default class Queue {
|
|
|
455
455
|
}
|
|
456
456
|
}
|
|
457
457
|
|
|
458
|
+
private static normalizeFailedReason(reason: string | undefined): string {
|
|
459
|
+
if (typeof reason !== "string") {
|
|
460
|
+
return "No reason provided";
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
const normalized: string = reason.trim().toLowerCase();
|
|
464
|
+
if (
|
|
465
|
+
normalized.length === 0 ||
|
|
466
|
+
normalized === "null" ||
|
|
467
|
+
normalized === "undefined"
|
|
468
|
+
) {
|
|
469
|
+
return "No reason provided";
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return reason;
|
|
473
|
+
}
|
|
474
|
+
|
|
458
475
|
@CaptureSpan()
|
|
459
476
|
public static async getQueueSize(queueName: QueueName): Promise<number> {
|
|
460
477
|
const queue: BullQueue = this.getQueue(queueName);
|
|
@@ -534,7 +551,7 @@ export default class Queue {
|
|
|
534
551
|
id: job.id || "unknown",
|
|
535
552
|
name: job.name || "unknown",
|
|
536
553
|
data: job.data as JSONObject,
|
|
537
|
-
failedReason: job.failedReason
|
|
554
|
+
failedReason: Queue.normalizeFailedReason(job.failedReason),
|
|
538
555
|
processedOn: job.processedOn ? new Date(job.processedOn) : null,
|
|
539
556
|
finishedOn: job.finishedOn ? new Date(job.finishedOn) : null,
|
|
540
557
|
attemptsMade: job.attemptsMade || 0,
|
|
@@ -641,7 +658,7 @@ export default class Queue {
|
|
|
641
658
|
opts: (job.opts as unknown as JSONObject) || {},
|
|
642
659
|
returnValue: job.returnvalue ?? null,
|
|
643
660
|
progress: (job.progress as number | Record<string, unknown>) ?? null,
|
|
644
|
-
failedReason: job.failedReason
|
|
661
|
+
failedReason: Queue.normalizeFailedReason(job.failedReason),
|
|
645
662
|
stackTrace: job.stacktrace || [],
|
|
646
663
|
logs: logs,
|
|
647
664
|
attemptsMade: job.attemptsMade || 0,
|
|
@@ -92,7 +92,10 @@ export default class QueueWorker {
|
|
|
92
92
|
(err as { name?: string })?.name === "TimeoutException"
|
|
93
93
|
? "timeout"
|
|
94
94
|
: "failure";
|
|
95
|
-
throw
|
|
95
|
+
throw QueueWorker.toReportableError(
|
|
96
|
+
err,
|
|
97
|
+
`${queueName}/${job.name || "unknown"} (job ${job.id ?? "unknown"})`,
|
|
98
|
+
);
|
|
96
99
|
} finally {
|
|
97
100
|
const elapsedNs: bigint = process.hrtime.bigint() - startNs;
|
|
98
101
|
const durationMs: number = Number(elapsedNs) / 1e6;
|
|
@@ -134,6 +137,69 @@ export default class QueueWorker {
|
|
|
134
137
|
return worker;
|
|
135
138
|
}
|
|
136
139
|
|
|
140
|
+
private static toReportableError(err: unknown, context: string): unknown {
|
|
141
|
+
const messageIsUseful: (value: unknown) => boolean = (
|
|
142
|
+
value: unknown,
|
|
143
|
+
): boolean => {
|
|
144
|
+
const message: unknown = (value as { message?: unknown })?.message;
|
|
145
|
+
if (typeof message !== "string") {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const normalized: string = message.trim().toLowerCase();
|
|
150
|
+
return (
|
|
151
|
+
normalized.length > 0 &&
|
|
152
|
+
normalized !== "null" &&
|
|
153
|
+
normalized !== "undefined"
|
|
154
|
+
);
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
if (err instanceof Error && messageIsUseful(err)) {
|
|
158
|
+
return err;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const detailParts: Array<string> = [];
|
|
162
|
+
|
|
163
|
+
const name: unknown = (err as { name?: unknown })?.name;
|
|
164
|
+
if (typeof name === "string" && name && name !== "Error") {
|
|
165
|
+
detailParts.push(name);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const rawMessage: unknown = (err as { message?: unknown })?.message;
|
|
169
|
+
if (typeof rawMessage === "string" && rawMessage.trim()) {
|
|
170
|
+
detailParts.push(rawMessage.trim());
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (detailParts.length === 0) {
|
|
174
|
+
let serialized: string;
|
|
175
|
+
try {
|
|
176
|
+
serialized =
|
|
177
|
+
typeof err === "object" && err !== null
|
|
178
|
+
? JSON.stringify(err)
|
|
179
|
+
: String(err);
|
|
180
|
+
} catch {
|
|
181
|
+
serialized = Object.prototype.toString.call(err);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
detailParts.push(
|
|
185
|
+
serialized && serialized !== "{}" ? serialized : String(err),
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const reportable: Error = new Error(
|
|
190
|
+
`${context} failed with a non-descriptive error (original message was empty/null). Detail: ${detailParts.join(
|
|
191
|
+
": ",
|
|
192
|
+
)}`,
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
const originalStack: unknown = (err as { stack?: unknown })?.stack;
|
|
196
|
+
if (typeof originalStack === "string" && originalStack) {
|
|
197
|
+
reportable.stack = originalStack;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return reportable;
|
|
201
|
+
}
|
|
202
|
+
|
|
137
203
|
@CaptureSpan()
|
|
138
204
|
public static async runJobWithTimeout(
|
|
139
205
|
timeoutInMS: number,
|