-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathlocalstack-status.ts
More file actions
100 lines (88 loc) · 2.53 KB
/
localstack-status.ts
File metadata and controls
100 lines (88 loc) · 2.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import type { Disposable, LogOutputChannel } from "vscode";
import type {
ContainerStatus,
ContainerStatusTracker,
} from "./container-status.ts";
import { createEmitter } from "./emitter.ts";
export type LocalStackStatus = "starting" | "running" | "stopping" | "stopped";
export interface LocalStackStatusTracker extends Disposable {
status(): LocalStackStatus;
onChange(callback: (status: LocalStackStatus) => void): void;
}
/**
* Checks the status of the LocalStack instance in realtime.
*/
export async function createLocalStackStatusTracker(
containerStatusTracker: ContainerStatusTracker,
outputChannel: LogOutputChannel,
): Promise<LocalStackStatusTracker> {
let status: LocalStackStatus | undefined;
const emitter = createEmitter<LocalStackStatus>(outputChannel);
let healthCheck: boolean | undefined;
const updateStatus = () => {
const newStatus = getLocalStackStatus(
containerStatusTracker.status(),
healthCheck,
);
if (status !== newStatus) {
status = newStatus;
void emitter.emit(status);
}
};
containerStatusTracker.onChange(() => {
updateStatus();
});
let healthCheckTimeout: NodeJS.Timeout | undefined;
const startHealthCheck = async () => {
healthCheck = await fetchHealth();
updateStatus();
healthCheckTimeout = setTimeout(() => void startHealthCheck(), 1_000);
};
await startHealthCheck();
return {
status() {
return status!;
},
onChange(callback) {
emitter.on(callback);
if (status) {
callback(status);
}
},
dispose() {
clearTimeout(healthCheckTimeout);
},
};
}
function getLocalStackStatus(
containerStatus: ContainerStatus | undefined,
healthCheck: boolean | undefined,
): LocalStackStatus {
if (containerStatus === "running") {
if (healthCheck === true) {
return "running";
} else {
return "starting";
}
} else if (containerStatus === "stopping") {
return "stopping";
} else {
return "stopped";
}
}
async function fetchHealth(): Promise<boolean> {
// Abort the fetch if it takes more than 500ms.
const controller = new AbortController();
setTimeout(() => controller.abort(), 500);
try {
// health is ok in the majority of use cases, however, determining status based on it can be flaky.
// for example, if localstack becomes unhealthy while running for reasons other that stop then reporting "stopping" may be misleading.
// though we don't know if it happens often.
const response = await fetch("http://localhost:4566/_localstack/health", {
signal: controller.signal,
});
return response.ok;
} catch (err) {
return false;
}
}