@checkstack/healthcheck-ping-backend 0.1.13 → 0.2.0
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/CHANGELOG.md +54 -0
- package/package.json +6 -6
- package/src/ping-collector.test.ts +5 -4
- package/src/ping-collector.ts +30 -37
- package/src/strategy.test.ts +26 -26
- package/src/strategy.ts +42 -62
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,59 @@
|
|
|
1
1
|
# @checkstack/healthcheck-ping-backend
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 3dd1914: Migrate health check strategies to VersionedAggregated with \_type discriminator
|
|
8
|
+
|
|
9
|
+
All 13 health check strategies now use `VersionedAggregated` for their `aggregatedResult` property, enabling automatic bucket merging with 100% mathematical fidelity.
|
|
10
|
+
|
|
11
|
+
**Key changes:**
|
|
12
|
+
|
|
13
|
+
- **`_type` discriminator**: All aggregated state objects now include a required `_type` field (`"average"`, `"rate"`, `"counter"`, `"minmax"`) for reliable type detection
|
|
14
|
+
- The `HealthCheckStrategy` interface now requires `aggregatedResult` to be a `VersionedAggregated<AggregatedResultShape>`
|
|
15
|
+
- Strategy/collector `mergeResult` methods return state objects with `_type` (e.g., `{ _type: "average", _sum, _count, avg }`)
|
|
16
|
+
- `mergeAggregatedBucketResults`, `combineBuckets`, and `reaggregateBuckets` now require `registry` and `strategyId` parameters
|
|
17
|
+
- `HealthCheckService` constructor now requires both `registry` and `collectorRegistry` parameters
|
|
18
|
+
- Frontend `extractComputedValue` now uses `_type` discriminator for robust type detection
|
|
19
|
+
|
|
20
|
+
**Breaking Change**: State objects now require `_type`. Merge functions automatically add `_type` to output. The bucket merging functions and `HealthCheckService` now require additional required parameters.
|
|
21
|
+
|
|
22
|
+
### Patch Changes
|
|
23
|
+
|
|
24
|
+
- Updated dependencies [3dd1914]
|
|
25
|
+
- @checkstack/backend-api@0.7.0
|
|
26
|
+
|
|
27
|
+
## 0.1.14
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- 48c2080: Migrate aggregation from batch to incremental (`mergeResult`)
|
|
32
|
+
|
|
33
|
+
### Breaking Changes (Internal)
|
|
34
|
+
|
|
35
|
+
- Replaced `aggregateResult(runs[])` with `mergeResult(existing, run)` interface across all HealthCheckStrategy and CollectorStrategy implementations
|
|
36
|
+
|
|
37
|
+
### New Features
|
|
38
|
+
|
|
39
|
+
- Added incremental aggregation utilities in `@checkstack/backend-api`:
|
|
40
|
+
- `mergeCounter()` - track occurrences
|
|
41
|
+
- `mergeAverage()` - track sum/count, compute avg
|
|
42
|
+
- `mergeRate()` - track success/total, compute %
|
|
43
|
+
- `mergeMinMax()` - track min/max values
|
|
44
|
+
- Exported Zod schemas for internal state: `averageStateSchema`, `rateStateSchema`, `minMaxStateSchema`, `counterStateSchema`
|
|
45
|
+
|
|
46
|
+
### Improvements
|
|
47
|
+
|
|
48
|
+
- Enables O(1) storage overhead by maintaining incremental aggregation state
|
|
49
|
+
- Prepares for real-time hourly aggregation without batch accumulation
|
|
50
|
+
|
|
51
|
+
- Updated dependencies [f676e11]
|
|
52
|
+
- Updated dependencies [48c2080]
|
|
53
|
+
- @checkstack/common@0.6.2
|
|
54
|
+
- @checkstack/backend-api@0.6.0
|
|
55
|
+
- @checkstack/healthcheck-common@0.8.2
|
|
56
|
+
|
|
3
57
|
## 0.1.13
|
|
4
58
|
|
|
5
59
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@checkstack/healthcheck-ping-backend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -9,14 +9,14 @@
|
|
|
9
9
|
"lint:code": "eslint . --max-warnings 0"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@checkstack/backend-api": "0.5.
|
|
13
|
-
"@checkstack/common": "0.6.
|
|
14
|
-
"@checkstack/healthcheck-common": "0.
|
|
12
|
+
"@checkstack/backend-api": "0.5.2",
|
|
13
|
+
"@checkstack/common": "0.6.1",
|
|
14
|
+
"@checkstack/healthcheck-common": "0.8.1"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"@types/bun": "^1.0.0",
|
|
18
18
|
"typescript": "^5.0.0",
|
|
19
|
-
"@checkstack/tsconfig": "0.0.
|
|
20
|
-
"@checkstack/scripts": "0.1.
|
|
19
|
+
"@checkstack/tsconfig": "0.0.3",
|
|
20
|
+
"@checkstack/scripts": "0.1.1"
|
|
21
21
|
}
|
|
22
22
|
}
|
|
@@ -82,7 +82,7 @@ describe("PingCollector", () => {
|
|
|
82
82
|
});
|
|
83
83
|
});
|
|
84
84
|
|
|
85
|
-
describe("
|
|
85
|
+
describe("mergeResult", () => {
|
|
86
86
|
it("should calculate average packet loss and latency", () => {
|
|
87
87
|
const collector = new PingCollector();
|
|
88
88
|
const runs = [
|
|
@@ -114,10 +114,11 @@ describe("PingCollector", () => {
|
|
|
114
114
|
},
|
|
115
115
|
];
|
|
116
116
|
|
|
117
|
-
|
|
117
|
+
let aggregated = collector.mergeResult(undefined, runs[0]);
|
|
118
|
+
aggregated = collector.mergeResult(aggregated, runs[1]);
|
|
118
119
|
|
|
119
|
-
expect(aggregated.avgPacketLoss).toBe(5);
|
|
120
|
-
expect(aggregated.avgLatency).toBe(15);
|
|
120
|
+
expect(aggregated.avgPacketLoss.avg).toBe(5);
|
|
121
|
+
expect(aggregated.avgLatency.avg).toBe(15);
|
|
121
122
|
});
|
|
122
123
|
});
|
|
123
124
|
|
package/src/ping-collector.ts
CHANGED
|
@@ -4,6 +4,10 @@ import {
|
|
|
4
4
|
type HealthCheckRunForAggregation,
|
|
5
5
|
type CollectorResult,
|
|
6
6
|
type CollectorStrategy,
|
|
7
|
+
mergeAverage,
|
|
8
|
+
VersionedAggregated,
|
|
9
|
+
aggregatedAverage,
|
|
10
|
+
type InferAggregatedResult,
|
|
7
11
|
} from "@checkstack/backend-api";
|
|
8
12
|
import {
|
|
9
13
|
healthResultNumber,
|
|
@@ -71,20 +75,24 @@ const pingResultSchema = healthResultSchema({
|
|
|
71
75
|
|
|
72
76
|
export type PingResult = z.infer<typeof pingResultSchema>;
|
|
73
77
|
|
|
74
|
-
|
|
75
|
-
|
|
78
|
+
// Aggregated result fields definition
|
|
79
|
+
const pingAggregatedFields = {
|
|
80
|
+
avgPacketLoss: aggregatedAverage({
|
|
76
81
|
"x-chart-type": "gauge",
|
|
77
82
|
"x-chart-label": "Avg Packet Loss",
|
|
78
83
|
"x-chart-unit": "%",
|
|
79
84
|
}),
|
|
80
|
-
avgLatency:
|
|
85
|
+
avgLatency: aggregatedAverage({
|
|
81
86
|
"x-chart-type": "line",
|
|
82
87
|
"x-chart-label": "Avg Latency",
|
|
83
88
|
"x-chart-unit": "ms",
|
|
84
89
|
}),
|
|
85
|
-
}
|
|
90
|
+
};
|
|
86
91
|
|
|
87
|
-
|
|
92
|
+
// Type inferred from field definitions
|
|
93
|
+
export type PingAggregatedResult = InferAggregatedResult<
|
|
94
|
+
typeof pingAggregatedFields
|
|
95
|
+
>;
|
|
88
96
|
|
|
89
97
|
// ============================================================================
|
|
90
98
|
// PING COLLECTOR
|
|
@@ -94,15 +102,12 @@ export type PingAggregatedResult = z.infer<typeof pingAggregatedSchema>;
|
|
|
94
102
|
* Built-in Ping collector.
|
|
95
103
|
* Performs ICMP ping and checks latency.
|
|
96
104
|
*/
|
|
97
|
-
export class PingCollector
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
PingAggregatedResult
|
|
104
|
-
>
|
|
105
|
-
{
|
|
105
|
+
export class PingCollector implements CollectorStrategy<
|
|
106
|
+
PingTransportClient,
|
|
107
|
+
PingConfig,
|
|
108
|
+
PingResult,
|
|
109
|
+
PingAggregatedResult
|
|
110
|
+
> {
|
|
106
111
|
id = "ping";
|
|
107
112
|
displayName = "ICMP Ping";
|
|
108
113
|
description = "Ping a host and check latency";
|
|
@@ -113,9 +118,9 @@ export class PingCollector
|
|
|
113
118
|
|
|
114
119
|
config = new Versioned({ version: 1, schema: pingConfigSchema });
|
|
115
120
|
result = new Versioned({ version: 1, schema: pingResultSchema });
|
|
116
|
-
aggregatedResult = new
|
|
121
|
+
aggregatedResult = new VersionedAggregated({
|
|
117
122
|
version: 1,
|
|
118
|
-
|
|
123
|
+
fields: pingAggregatedFields,
|
|
119
124
|
});
|
|
120
125
|
|
|
121
126
|
async execute({
|
|
@@ -145,30 +150,18 @@ export class PingCollector
|
|
|
145
150
|
};
|
|
146
151
|
}
|
|
147
152
|
|
|
148
|
-
|
|
149
|
-
|
|
153
|
+
mergeResult(
|
|
154
|
+
existing: PingAggregatedResult | undefined,
|
|
155
|
+
run: HealthCheckRunForAggregation<PingResult>,
|
|
150
156
|
): PingAggregatedResult {
|
|
151
|
-
const
|
|
152
|
-
.map((r) => r.metadata?.packetLoss)
|
|
153
|
-
.filter((v): v is number => typeof v === "number");
|
|
154
|
-
|
|
155
|
-
const latencies = runs
|
|
156
|
-
.map((r) => r.metadata?.avgLatency)
|
|
157
|
-
.filter((v): v is number => typeof v === "number");
|
|
157
|
+
const metadata = run.metadata;
|
|
158
158
|
|
|
159
159
|
return {
|
|
160
|
-
avgPacketLoss:
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
: 0,
|
|
166
|
-
avgLatency:
|
|
167
|
-
latencies.length > 0
|
|
168
|
-
? Math.round(
|
|
169
|
-
(latencies.reduce((a, b) => a + b, 0) / latencies.length) * 10
|
|
170
|
-
) / 10
|
|
171
|
-
: 0,
|
|
160
|
+
avgPacketLoss: mergeAverage(
|
|
161
|
+
existing?.avgPacketLoss,
|
|
162
|
+
metadata?.packetLoss,
|
|
163
|
+
),
|
|
164
|
+
avgLatency: mergeAverage(existing?.avgLatency, metadata?.avgLatency),
|
|
172
165
|
};
|
|
173
166
|
}
|
|
174
167
|
}
|
package/src/strategy.test.ts
CHANGED
|
@@ -14,8 +14,8 @@ const mockSpawn = mock(() => ({
|
|
|
14
14
|
|
|
15
15
|
--- 8.8.8.8 ping statistics ---
|
|
16
16
|
3 packets transmitted, 3 packets received, 0.0% packet loss
|
|
17
|
-
round-trip min/avg/max/stddev = 10.123/11.456/12.456/0.957 ms
|
|
18
|
-
)
|
|
17
|
+
round-trip min/avg/max/stddev = 10.123/11.456/12.456/0.957 ms`,
|
|
18
|
+
),
|
|
19
19
|
);
|
|
20
20
|
controller.close();
|
|
21
21
|
},
|
|
@@ -83,8 +83,8 @@ describe("PingHealthCheckStrategy", () => {
|
|
|
83
83
|
`PING 10.0.0.1 (10.0.0.1): 56 data bytes
|
|
84
84
|
|
|
85
85
|
--- 10.0.0.1 ping statistics ---
|
|
86
|
-
3 packets transmitted, 0 packets received, 100.0% packet loss
|
|
87
|
-
)
|
|
86
|
+
3 packets transmitted, 0 packets received, 100.0% packet loss`,
|
|
87
|
+
),
|
|
88
88
|
);
|
|
89
89
|
controller.close();
|
|
90
90
|
},
|
|
@@ -139,7 +139,7 @@ describe("PingHealthCheckStrategy", () => {
|
|
|
139
139
|
});
|
|
140
140
|
});
|
|
141
141
|
|
|
142
|
-
describe("
|
|
142
|
+
describe("mergeResult", () => {
|
|
143
143
|
it("should calculate averages correctly", () => {
|
|
144
144
|
const runs = [
|
|
145
145
|
{
|
|
@@ -172,34 +172,34 @@ describe("PingHealthCheckStrategy", () => {
|
|
|
172
172
|
},
|
|
173
173
|
];
|
|
174
174
|
|
|
175
|
-
|
|
175
|
+
let aggregated = strategy.mergeResult(undefined, runs[0]);
|
|
176
|
+
aggregated = strategy.mergeResult(aggregated, runs[1]);
|
|
176
177
|
|
|
177
|
-
|
|
178
|
-
expect(aggregated.
|
|
179
|
-
expect(aggregated.
|
|
180
|
-
expect(aggregated.
|
|
178
|
+
// (0 + 33) / 2 = 16.5
|
|
179
|
+
expect(aggregated.avgPacketLoss.avg).toBeCloseTo(16.5, 1);
|
|
180
|
+
expect(aggregated.avgLatency.avg).toBeCloseTo(15, 1);
|
|
181
|
+
expect(aggregated.maxLatency.max).toBe(25);
|
|
182
|
+
expect(aggregated.errorCount.count).toBe(0);
|
|
181
183
|
});
|
|
182
184
|
|
|
183
185
|
it("should count errors", () => {
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
error: "Timeout",
|
|
196
|
-
},
|
|
186
|
+
const run = {
|
|
187
|
+
id: "1",
|
|
188
|
+
status: "unhealthy" as const,
|
|
189
|
+
latencyMs: 0,
|
|
190
|
+
checkId: "c1",
|
|
191
|
+
timestamp: new Date(),
|
|
192
|
+
metadata: {
|
|
193
|
+
packetsSent: 3,
|
|
194
|
+
packetsReceived: 0,
|
|
195
|
+
packetLoss: 100,
|
|
196
|
+
error: "Timeout",
|
|
197
197
|
},
|
|
198
|
-
|
|
198
|
+
};
|
|
199
199
|
|
|
200
|
-
const aggregated = strategy.
|
|
200
|
+
const aggregated = strategy.mergeResult(undefined, run);
|
|
201
201
|
|
|
202
|
-
expect(aggregated.errorCount).toBe(1);
|
|
202
|
+
expect(aggregated.errorCount.count).toBe(1);
|
|
203
203
|
});
|
|
204
204
|
});
|
|
205
205
|
});
|
package/src/strategy.ts
CHANGED
|
@@ -2,8 +2,16 @@ import {
|
|
|
2
2
|
HealthCheckStrategy,
|
|
3
3
|
HealthCheckRunForAggregation,
|
|
4
4
|
Versioned,
|
|
5
|
+
VersionedAggregated,
|
|
6
|
+
aggregatedAverage,
|
|
7
|
+
aggregatedMinMax,
|
|
8
|
+
aggregatedCounter,
|
|
9
|
+
mergeAverage,
|
|
10
|
+
mergeCounter,
|
|
11
|
+
mergeMinMax,
|
|
5
12
|
z,
|
|
6
13
|
type ConnectedClient,
|
|
14
|
+
type InferAggregatedResult,
|
|
7
15
|
} from "@checkstack/backend-api";
|
|
8
16
|
import {
|
|
9
17
|
healthResultNumber,
|
|
@@ -81,46 +89,41 @@ const pingResultSchema = healthResultSchema({
|
|
|
81
89
|
|
|
82
90
|
type PingResult = z.infer<typeof pingResultSchema>;
|
|
83
91
|
|
|
84
|
-
/**
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const pingAggregatedSchema = healthResultSchema({
|
|
88
|
-
avgPacketLoss: healthResultNumber({
|
|
92
|
+
/** Aggregated field definitions for bucket merging */
|
|
93
|
+
const pingAggregatedFields = {
|
|
94
|
+
avgPacketLoss: aggregatedAverage({
|
|
89
95
|
"x-chart-type": "gauge",
|
|
90
96
|
"x-chart-label": "Avg Packet Loss",
|
|
91
97
|
"x-chart-unit": "%",
|
|
92
98
|
}),
|
|
93
|
-
avgLatency:
|
|
99
|
+
avgLatency: aggregatedAverage({
|
|
94
100
|
"x-chart-type": "line",
|
|
95
101
|
"x-chart-label": "Avg Latency",
|
|
96
102
|
"x-chart-unit": "ms",
|
|
97
103
|
}),
|
|
98
|
-
maxLatency:
|
|
104
|
+
maxLatency: aggregatedMinMax({
|
|
99
105
|
"x-chart-type": "line",
|
|
100
106
|
"x-chart-label": "Max Latency",
|
|
101
107
|
"x-chart-unit": "ms",
|
|
102
108
|
}),
|
|
103
|
-
errorCount:
|
|
109
|
+
errorCount: aggregatedCounter({
|
|
104
110
|
"x-chart-type": "counter",
|
|
105
111
|
"x-chart-label": "Errors",
|
|
106
112
|
}),
|
|
107
|
-
}
|
|
113
|
+
};
|
|
108
114
|
|
|
109
|
-
type PingAggregatedResult =
|
|
115
|
+
type PingAggregatedResult = InferAggregatedResult<typeof pingAggregatedFields>;
|
|
110
116
|
|
|
111
117
|
// ============================================================================
|
|
112
118
|
// STRATEGY
|
|
113
119
|
// ============================================================================
|
|
114
120
|
|
|
115
|
-
export class PingHealthCheckStrategy
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
PingAggregatedResult
|
|
122
|
-
>
|
|
123
|
-
{
|
|
121
|
+
export class PingHealthCheckStrategy implements HealthCheckStrategy<
|
|
122
|
+
PingConfig,
|
|
123
|
+
PingTransportClient,
|
|
124
|
+
PingResult,
|
|
125
|
+
typeof pingAggregatedFields
|
|
126
|
+
> {
|
|
124
127
|
id = "ping";
|
|
125
128
|
displayName = "Ping Health Check";
|
|
126
129
|
description = "ICMP ping check for network reachability and latency";
|
|
@@ -153,57 +156,34 @@ export class PingHealthCheckStrategy
|
|
|
153
156
|
],
|
|
154
157
|
});
|
|
155
158
|
|
|
156
|
-
aggregatedResult
|
|
159
|
+
aggregatedResult = new VersionedAggregated({
|
|
157
160
|
version: 1,
|
|
158
|
-
|
|
161
|
+
fields: pingAggregatedFields,
|
|
159
162
|
});
|
|
160
163
|
|
|
161
|
-
|
|
162
|
-
|
|
164
|
+
mergeResult(
|
|
165
|
+
existing: PingAggregatedResult | undefined,
|
|
166
|
+
run: HealthCheckRunForAggregation<PingResult>,
|
|
163
167
|
): PingAggregatedResult {
|
|
164
|
-
const
|
|
168
|
+
const metadata = run.metadata;
|
|
165
169
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const packetLosses = validRuns
|
|
171
|
-
.map((r) => r.metadata?.packetLoss)
|
|
172
|
-
.filter((l): l is number => typeof l === "number");
|
|
173
|
-
|
|
174
|
-
const avgPacketLoss =
|
|
175
|
-
packetLosses.length > 0
|
|
176
|
-
? Math.round(
|
|
177
|
-
(packetLosses.reduce((a, b) => a + b, 0) / packetLosses.length) * 10
|
|
178
|
-
) / 10
|
|
179
|
-
: 0;
|
|
180
|
-
|
|
181
|
-
const latencies = validRuns
|
|
182
|
-
.map((r) => r.metadata?.avgLatency)
|
|
183
|
-
.filter((l): l is number => typeof l === "number");
|
|
184
|
-
|
|
185
|
-
const avgLatency =
|
|
186
|
-
latencies.length > 0
|
|
187
|
-
? Math.round(
|
|
188
|
-
(latencies.reduce((a, b) => a + b, 0) / latencies.length) * 10
|
|
189
|
-
) / 10
|
|
190
|
-
: 0;
|
|
170
|
+
const avgPacketLoss = mergeAverage(
|
|
171
|
+
existing?.avgPacketLoss,
|
|
172
|
+
metadata?.packetLoss,
|
|
173
|
+
);
|
|
191
174
|
|
|
192
|
-
const
|
|
193
|
-
.map((r) => r.metadata?.maxLatency)
|
|
194
|
-
.filter((l): l is number => typeof l === "number");
|
|
175
|
+
const avgLatency = mergeAverage(existing?.avgLatency, metadata?.avgLatency);
|
|
195
176
|
|
|
196
|
-
const maxLatency =
|
|
177
|
+
const maxLatency = mergeMinMax(existing?.maxLatency, metadata?.maxLatency);
|
|
197
178
|
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
).length;
|
|
179
|
+
const hasError = metadata?.error !== undefined;
|
|
180
|
+
const errorCount = mergeCounter(existing?.errorCount, hasError);
|
|
201
181
|
|
|
202
182
|
return { avgPacketLoss, avgLatency, maxLatency, errorCount };
|
|
203
183
|
}
|
|
204
184
|
|
|
205
185
|
async createClient(
|
|
206
|
-
config: PingConfig
|
|
186
|
+
config: PingConfig,
|
|
207
187
|
): Promise<ConnectedClient<PingTransportClient>> {
|
|
208
188
|
const validatedConfig = this.config.validate(config);
|
|
209
189
|
|
|
@@ -212,7 +192,7 @@ export class PingHealthCheckStrategy
|
|
|
212
192
|
return this.runPing(
|
|
213
193
|
request.host,
|
|
214
194
|
request.count,
|
|
215
|
-
request.timeout ?? validatedConfig.timeout
|
|
195
|
+
request.timeout ?? validatedConfig.timeout,
|
|
216
196
|
);
|
|
217
197
|
},
|
|
218
198
|
};
|
|
@@ -228,7 +208,7 @@ export class PingHealthCheckStrategy
|
|
|
228
208
|
private async runPing(
|
|
229
209
|
host: string,
|
|
230
210
|
count: number,
|
|
231
|
-
timeout: number
|
|
211
|
+
timeout: number,
|
|
232
212
|
): Promise<PingResultType> {
|
|
233
213
|
const isMac = process.platform === "darwin";
|
|
234
214
|
const args = isMac
|
|
@@ -260,11 +240,11 @@ export class PingHealthCheckStrategy
|
|
|
260
240
|
private parsePingOutput(
|
|
261
241
|
output: string,
|
|
262
242
|
expectedCount: number,
|
|
263
|
-
_exitCode: number
|
|
243
|
+
_exitCode: number,
|
|
264
244
|
): PingResultType {
|
|
265
245
|
// Parse packet statistics
|
|
266
246
|
const statsMatch = output.match(
|
|
267
|
-
/(\d+) packets transmitted, (\d+) (?:packets )?received
|
|
247
|
+
/(\d+) packets transmitted, (\d+) (?:packets )?received/,
|
|
268
248
|
);
|
|
269
249
|
const packetsSent = statsMatch
|
|
270
250
|
? Number.parseInt(statsMatch[1], 10)
|
|
@@ -279,7 +259,7 @@ export class PingHealthCheckStrategy
|
|
|
279
259
|
// macOS: round-trip min/avg/max/stddev = 0.043/0.059/0.082/0.016 ms
|
|
280
260
|
// Linux: rtt min/avg/max/mdev = 0.039/0.049/0.064/0.009 ms
|
|
281
261
|
const latencyMatch = output.match(
|
|
282
|
-
/(?:round-trip|rtt) min\/avg\/max\/(?:stddev|mdev) = ([\d.]+)\/([\d.]+)\/([\d.]+)
|
|
262
|
+
/(?:round-trip|rtt) min\/avg\/max\/(?:stddev|mdev) = ([\d.]+)\/([\d.]+)\/([\d.]+)/,
|
|
283
263
|
);
|
|
284
264
|
|
|
285
265
|
let minLatency: number | undefined;
|