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