CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/compute/automatic-shutdown.tsx
Views: 687
1
/*
2
Configuration to automate state control via backend maintenance task.
3
4
The only thing we implement so far is "script", see StateControl in
5
6
https://wstein-dev.cocalc.cloud/projects/6b851643-360e-435e-b87e-f9a6ab64a8b1/files/cocalc/src/packages/util/db-schema/compute-servers.ts
7
8
It gets configured here. A maintenance process on the backend periodically checks the idle timeout conditions,
9
and if met, shuts down the compute server.
10
*/
11
12
import {
13
Alert,
14
Button,
15
Flex,
16
Input,
17
Modal,
18
InputNumber,
19
Space,
20
Spin,
21
} from "antd";
22
import { useEffect, useState } from "react";
23
import ShowError from "@cocalc/frontend/components/error";
24
import { useServer } from "./compute-server";
25
import { webapp_client } from "@cocalc/frontend/webapp-client";
26
import Inline from "./inline";
27
import { plural } from "@cocalc/util/misc";
28
import { AUTOMATIC_SHUTDOWN_DEFAULTS } from "@cocalc/util/db-schema/compute-servers";
29
30
async function saveStateControl({ id, project_id, automatic_shutdown }) {
31
await webapp_client.async_query({
32
query: {
33
compute_servers: {
34
id,
35
project_id,
36
automatic_shutdown,
37
},
38
},
39
});
40
}
41
42
function AutomaticShutdown({ id, project_id }) {
43
const server = useServer({ id, project_id });
44
const [error, setError] = useState<string>("");
45
const [test, setTest] = useState<string>("");
46
const [saving, setSaving] = useState<boolean>(false);
47
const [command, setCommand] = useState<string | null>("");
48
const [attempts, setAttempts] = useState<number | null>(
49
AUTOMATIC_SHUTDOWN_DEFAULTS.ATTEMPTS,
50
);
51
const [interval_minutes, setIntervalMinutes] = useState<number | null>(
52
AUTOMATIC_SHUTDOWN_DEFAULTS.INTERVAL_MINUTES,
53
);
54
55
useEffect(() => {
56
if (server.automatic_shutdown) {
57
if (!command) {
58
setCommand(server.automatic_shutdown?.command ?? "");
59
}
60
if (attempts == null) {
61
setAttempts(
62
server.automatic_shutdown?.attempts ??
63
AUTOMATIC_SHUTDOWN_DEFAULTS.ATTEMPTS,
64
);
65
}
66
if (interval_minutes == null) {
67
setIntervalMinutes(
68
server.automatic_shutdown?.interval_minutes ??
69
AUTOMATIC_SHUTDOWN_DEFAULTS.INTERVAL_MINUTES,
70
);
71
}
72
}
73
}, [server?.automatic_shutdown]);
74
75
const save = async () => {
76
try {
77
setSaving(true);
78
await saveStateControl({
79
id,
80
project_id,
81
automatic_shutdown: {
82
command,
83
attempts,
84
interval_minutes,
85
},
86
});
87
} catch (err) {
88
setError(`${err}`);
89
} finally {
90
// a little delay makes the feedback with setting above again and disabled just
91
// feel cleaner. It also reduces potential load.
92
setTimeout(() => setSaving(false), 1000);
93
}
94
};
95
96
const doTest = async () => {
97
try {
98
setSaving(true);
99
setTest("");
100
const resp = await webapp_client.exec({
101
filesystem: false,
102
compute_server_id: id,
103
project_id,
104
command,
105
bash: true,
106
err_on_exit: false,
107
});
108
delete resp.type;
109
setTest(JSON.stringify(resp, undefined, 2));
110
} catch (err) {
111
setError(`${err}`);
112
} finally {
113
setSaving(false);
114
}
115
};
116
117
return (
118
<div>
119
CoCalc will run this bash command line on your compute server in
120
/home/user every{" "}
121
{interval_minutes ?? AUTOMATIC_SHUTDOWN_DEFAULTS.INTERVAL_MINUTES}{" "}
122
{plural(
123
interval_minutes ?? AUTOMATIC_SHUTDOWN_DEFAULTS.INTERVAL_MINUTES,
124
"minute",
125
)}
126
. If the command fails{" "}
127
{`${attempts ?? 1} ${plural(attempts ?? 1, "time")} in a row`}, then
128
CoCalc will turn off <Inline id={id} />.
129
<Space direction="vertical" style={{ marginTop: "15px" }} size="large">
130
<Input
131
allowClear
132
disabled={saving}
133
value={command ?? ""}
134
onChange={(e) => setCommand(e.target.value)}
135
placeholder="Bash Command Line..."
136
/>
137
<Flex>
138
<InputNumber
139
style={{ flex: 1, marginRight: "15px" }}
140
disabled={saving}
141
min={1}
142
step={1}
143
value={attempts}
144
onChange={(value) => setAttempts(value)}
145
addonAfter="retries"
146
placeholder="Retries..."
147
/>
148
<InputNumber
149
style={{ flex: 1 }}
150
disabled={saving}
151
min={1}
152
step={1}
153
value={interval_minutes}
154
onChange={(value) => setIntervalMinutes(value)}
155
addonAfter="minutes"
156
placeholder="Interval..."
157
/>
158
</Flex>
159
<div style={{ textAlign: "center" }}>
160
<Space>
161
<Button
162
disabled={saving}
163
onClick={() => {
164
setCommand("");
165
setAttempts(AUTOMATIC_SHUTDOWN_DEFAULTS.ATTEMPTS);
166
save();
167
}}
168
>
169
Disable
170
</Button>
171
<Button disabled={saving || !command} onClick={doTest}>
172
Test
173
</Button>
174
<Button
175
disabled={
176
saving ||
177
attempts == null ||
178
(server.automatic_shutdown?.command == command &&
179
server.automatic_shutdown?.attempts == attempts)
180
}
181
type="primary"
182
onClick={() => {
183
save();
184
}}
185
>
186
Save {saving && <Spin style={{ marginLeft: "5px" }} />}
187
</Button>
188
</Space>
189
</div>
190
{server.automatic_shutdown?.command ? (
191
<Alert
192
type="success"
193
showIcon
194
message="Automatic Shutdown Monitor is Enabled"
195
/>
196
) : (
197
<Alert
198
type="info"
199
showIcon
200
message="NOT Enabled (set command line to enable)"
201
/>
202
)}
203
{test && (
204
<pre
205
style={{
206
width: "550px",
207
overflow: "auto",
208
background: "#e8e8e8",
209
padding: "15px",
210
borderRadius: "15px",
211
}}
212
>
213
{test}
214
</pre>
215
)}
216
<ShowError
217
error={error}
218
setError={setError}
219
style={{ width: "100%" }}
220
/>
221
</Space>
222
</div>
223
);
224
}
225
226
export function AutomaticShutdownModal({ id, project_id, close }) {
227
return (
228
<Modal
229
width={600}
230
open
231
onCancel={close}
232
onOk={close}
233
cancelText="Close"
234
okButtonProps={{ style: { display: "none" } }}
235
title={"Compute Server Automatic Shutdown"}
236
>
237
<AutomaticShutdown id={id} project_id={project_id} />
238
</Modal>
239
);
240
}
241
242