Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/compute/idle-timeout.tsx
1503 views
1
import { useState } from "react";
2
import { useServer } from "./compute-server";
3
import { TimeAgo } from "@cocalc/frontend/components/time-ago";
4
import dayjs from "dayjs";
5
import { InputNumber, Tooltip } from "antd";
6
import { useInterval } from "react-interval-hook";
7
import { IDLE_TIMEOUT_MINUTES_DEFAULT } from "@cocalc/util/db-schema/compute-servers";
8
import { AutomaticShutdownCard } from "./automatic-shutdown";
9
import { setServerConfiguration } from "./api";
10
import duration from "dayjs/plugin/duration";
11
dayjs.extend(duration);
12
13
export function IdleTimeout({
14
id,
15
project_id,
16
help,
17
}: {
18
id: number;
19
project_id: string;
20
help?: boolean;
21
}) {
22
const server = useServer({ id, project_id });
23
const [error, setError] = useState<string>("");
24
const [saving, setSaving] = useState<boolean>(false);
25
const [enabled, setEnabled] = useState<boolean>(
26
!!server.configuration?.idleTimeoutMinutes,
27
);
28
const [idleTimeoutMinutes, setIdleTimeoutMinutes] = useState<number | null>(
29
server.configuration?.idleTimeoutMinutes ?? null,
30
);
31
32
return (
33
<AutomaticShutdownCard
34
title="Idle Timeout"
35
icon="stopwatch"
36
setEnabled={(enabled) => {
37
setEnabled(enabled);
38
if (enabled) {
39
setIdleTimeoutMinutes(IDLE_TIMEOUT_MINUTES_DEFAULT);
40
} else {
41
setIdleTimeoutMinutes(0);
42
}
43
}}
44
save={async () => {
45
await setServerConfiguration({
46
id,
47
configuration: {
48
idleTimeoutMinutes: idleTimeoutMinutes ?? undefined,
49
},
50
});
51
}}
52
hasUnsavedChanges={
53
(server.configuration?.idleTimeoutMinutes ?? 0) !=
54
(idleTimeoutMinutes ?? 0)
55
}
56
savedEnabled={!!server.configuration?.idleTimeoutMinutes}
57
enabled={enabled}
58
saving={saving}
59
setSaving={setSaving}
60
error={error}
61
setError={setError}
62
>
63
<IdleTimeoutMessage minimal project_id={project_id} id={id} />
64
{help && (
65
<div style={{ marginBottom: "15px" }}>
66
<p>
67
<IdleTimeoutMessage project_id={project_id} id={id} />
68
</p>
69
<p>
70
Automatically stop the compute server if no terminal or file (e.g.,
71
Jupyter notebook) on this compute server is used through the main
72
CoCalc web interface for a given numbers of minutes. CPU and GPU
73
usage is not taken into account.
74
</p>
75
<ul>
76
<li>
77
Idle timeout for compute servers has no direct impact on their
78
cost. Indirectly, setting an idle timeout can save you a huge
79
amount of money, depending on your usage patterns!
80
</li>
81
<li>
82
Compute server idle timeout is unrelated to your home base's idle
83
timeout. Any time a compute server is running, it keeps the home
84
base project running, which effectively gives the home base a long
85
idle timeout.
86
</li>
87
</ul>
88
</div>
89
)}
90
<div style={{ textAlign: "center" }}>
91
<InputNumber
92
style={{ width: "300px" }}
93
disabled={saving || !enabled}
94
min={0}
95
step={15}
96
value={idleTimeoutMinutes}
97
onChange={(value) => setIdleTimeoutMinutes(value)}
98
addonAfter="timeout minutes"
99
placeholder="Idle timeout..."
100
/>
101
</div>
102
</AutomaticShutdownCard>
103
);
104
}
105
106
interface Props {
107
id: number;
108
project_id: string;
109
style?;
110
minimal?: boolean;
111
}
112
113
export function IdleTimeoutMessage({ id, project_id, style, minimal }: Props) {
114
const server = useServer({ id, project_id });
115
const [counter, setCounter] = useState<number>(0);
116
useInterval(() => {
117
setCounter(counter + 1);
118
}, 5000);
119
120
if (!server) {
121
return null;
122
}
123
const { state, last_edited_user } = server;
124
const idleTimeoutMinutes = server.configuration?.idleTimeoutMinutes;
125
if (!idleTimeoutMinutes || state != "running" || !last_edited_user) {
126
return null;
127
}
128
const last = dayjs(last_edited_user);
129
const date = last.add(idleTimeoutMinutes, "minutes");
130
const mesg = (
131
<>
132
Server will stop <TimeAgo date={date.toDate()} /> unlesss somebody
133
actively edits.
134
</>
135
);
136
if (!minimal) {
137
return <div style={style}>{mesg}</div>;
138
}
139
140
let d = date.diff(dayjs());
141
const formattedDiff = dayjs.duration(d).format("HH:mm:ss");
142
return (
143
<Tooltip title={<>Idle Timeout: {mesg}</>}>
144
<div style={style}>{formattedDiff}</div>
145
</Tooltip>
146
);
147
}
148
149