From 2fbd5cdd6eec76d1b0533e325e60a2c53ba62078 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 14 Dec 2019 02:00:36 -0500 Subject: factored out repl into module --- src/server/ChildProcessUtilities/ProcessFactory.ts | 67 -------- src/server/ChildProcessUtilities/daemon/session.ts | 190 --------------------- src/server/ProcessFactory.ts | 44 +++++ src/server/index.ts | 2 +- src/server/session_manager/config.ts | 32 ++++ src/server/session_manager/input_manager.ts | 101 +++++++++++ .../session_crashes_@ 2019-12-11T18:52:10.359Z.log | 1 + .../session_crashes_@ 2019-12-12T00:38:44.803Z.log | 1 + .../session_crashes_@ 2019-12-12T00:42:11.945Z.log | 1 + .../session_manager/logs/current_daemon_pid.log | 1 + .../session_manager/logs/current_server_pid.log | 1 + .../logs/current_session_manager_pid.log | 1 + src/server/session_manager/session_manager.ts | 176 +++++++++++++++++++ 13 files changed, 360 insertions(+), 258 deletions(-) delete mode 100644 src/server/ChildProcessUtilities/ProcessFactory.ts delete mode 100644 src/server/ChildProcessUtilities/daemon/session.ts create mode 100644 src/server/ProcessFactory.ts create mode 100644 src/server/session_manager/config.ts create mode 100644 src/server/session_manager/input_manager.ts create mode 100644 src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-11T18:52:10.359Z.log create mode 100644 src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:38:44.803Z.log create mode 100644 src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:42:11.945Z.log create mode 100644 src/server/session_manager/logs/current_daemon_pid.log create mode 100644 src/server/session_manager/logs/current_server_pid.log create mode 100644 src/server/session_manager/logs/current_session_manager_pid.log create mode 100644 src/server/session_manager/session_manager.ts (limited to 'src') diff --git a/src/server/ChildProcessUtilities/ProcessFactory.ts b/src/server/ChildProcessUtilities/ProcessFactory.ts deleted file mode 100644 index 745b1479a..000000000 --- a/src/server/ChildProcessUtilities/ProcessFactory.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { existsSync, mkdirSync } from "fs"; -import { pathFromRoot, log_execution, fileDescriptorFromStream } from '../ActionUtilities'; -import { red, green } from "colors"; -import rimraf = require("rimraf"); -import { ChildProcess, spawn, StdioOptions } from "child_process"; -import { Stream } from "stream"; -import { resolve } from "path"; - -export namespace ProcessFactory { - - export type Sink = "pipe" | "ipc" | "ignore" | "inherit" | Stream | number | null | undefined; - - export async function createWorker(command: string, args?: readonly string[], stdio?: StdioOptions | "logfile", detached = true): Promise { - if (stdio === "logfile") { - const log_fd = await Logger.create(command, args); - stdio = ["ignore", log_fd, log_fd]; - } - const child = spawn(command, args, { detached, stdio }); - child.unref(); - return child; - } - - export namespace NamedAgents { - - export async function persistenceDaemon() { - await log_execution({ - startMessage: "\ninitializing persistence daemon", - endMessage: ({ result, error }) => { - const success = error === null && result !== undefined; - if (!success) { - console.log(red("failed to initialize the persistance daemon")); - console.log(error); - process.exit(0); - } - return "failsafe daemon process successfully spawned"; - }, - action: () => createWorker('npx', ['ts-node', resolve(__dirname, "./daemon/persistence_daemon.ts")], ["ignore", "inherit", "inherit"]), - color: green - }); - console.log(); - } - } - -} - -export namespace Logger { - - const logPath = pathFromRoot("./logs"); - - export async function initialize() { - if (existsSync(logPath)) { - if (!process.env.SPAWNED) { - await new Promise(resolve => rimraf(logPath, resolve)); - } - } - mkdirSync(logPath); - } - - export async function create(command: string, args?: readonly string[]): Promise { - return fileDescriptorFromStream(generate_log_path(command, args)); - } - - function generate_log_path(command: string, args?: readonly string[]) { - return pathFromRoot(`./logs/${command}-${args?.length}-${new Date().toUTCString()}.log`); - } - -} \ No newline at end of file diff --git a/src/server/ChildProcessUtilities/daemon/session.ts b/src/server/ChildProcessUtilities/daemon/session.ts deleted file mode 100644 index fb2b3551e..000000000 --- a/src/server/ChildProcessUtilities/daemon/session.ts +++ /dev/null @@ -1,190 +0,0 @@ -import * as request from "request-promise"; -import { log_execution, pathFromRoot } from "../../ActionUtilities"; -import { red, yellow, cyan, green, Color } from "colors"; -import * as nodemailer from "nodemailer"; -import { MailOptions } from "nodemailer/lib/json-transport"; -import { writeFileSync, existsSync, mkdirSync } from "fs"; -import { resolve } from 'path'; -import { ChildProcess, exec, execSync } from "child_process"; -import { createInterface } from "readline"; -const killport = require("kill-port"); - -process.on('SIGINT', endPrevious); -const identifier = yellow("__session_manager__:"); - -let manualRestartActive = false; -createInterface(process.stdin, process.stdout).on('line', async line => { - const prompt = line.trim().toLowerCase(); - switch (prompt) { - case "restart": - manualRestartActive = true; - identifiedLog(cyan("Initializing manual restart...")); - await endPrevious(); - break; - case "exit": - identifiedLog(cyan("Initializing session end")); - await endPrevious(); - identifiedLog("Cleanup complete. Exiting session...\n"); - execSync(killAllCommand()); - break; - default: - identifiedLog(red("commands: { exit, restart }")); - return; - } -}); - -const logPath = resolve(__dirname, "./logs"); -const crashPath = resolve(logPath, "./crashes"); -if (!existsSync(logPath)) { - mkdirSync(logPath); -} -if (!existsSync(crashPath)) { - mkdirSync(crashPath); -} - -const crashLogPath = resolve(crashPath, `./session_crashes_${new Date().toISOString()}.log`); -function addLogEntry(message: string, color: Color) { - const formatted = color(`${message} ${timestamp()}.`); - identifiedLog(formatted); - // appendFileSync(crashLogPath, `${formatted}\n`); -} - -function identifiedLog(message?: any, ...optionalParams: any[]) { - console.log(identifier, message, ...optionalParams); -} - -if (!["win32", "darwin"].includes(process.platform)) { - identifiedLog(red("Invalid operating system: this script is supported only on Mac and Windows.")); - process.exit(1); -} - -const latency = 10; -const ports = [1050, 4321]; -const onWindows = process.platform === "win32"; -const LOCATION = "http://localhost"; -const heartbeat = `${LOCATION}:1050/serverHeartbeat`; -const recipient = "samuel_wilkins@brown.edu"; -const { pid } = process; -let restarting = false; -let count = 0; - -function startServerCommand() { - if (onWindows) { - return '"C:\\Program Files\\Git\\git-bash.exe" -c "npm run start-release"'; - } - return `osascript -e 'tell app "Terminal"\ndo script "cd ${pathFromRoot()} && npm run start-release"\nend tell'`; -} - -function killAllCommand() { - if (onWindows) { - return "taskkill /f /im node.exe"; - } - return "killall -9 node"; -} - -identifiedLog("Initializing session..."); - -writeLocalPidLog("session_manager", pid); - -function writeLocalPidLog(filename: string, contents: any) { - const path = `./logs/current_${filename}_pid.log`; - identifiedLog(cyan(`${contents} written to ${path}`)); - writeFileSync(resolve(__dirname, path), `${contents}\n`); -} - -function timestamp() { - return `@ ${new Date().toISOString()}`; -} - -async function endPrevious() { - identifiedLog(yellow("Cleaning up previous connections...")); - current_backup?.kill("SIGTERM"); - await Promise.all(ports.map(port => { - const task = killport(port, 'tcp'); - return task.catch((error: any) => identifiedLog(red(error))); - })); - identifiedLog(yellow("Done. Any failures will be printed in red immediately above.")); -} - -let current_backup: ChildProcess | undefined = undefined; - -async function checkHeartbeat() { - let error: any; - try { - count && !restarting && process.stdout.write(`${identifier} 👂 `); - await request.get(heartbeat); - count && !restarting && console.log('⇠ 💚'); - if (restarting || manualRestartActive) { - addLogEntry(count++ ? "Backup server successfully restarted" : "Server successfully started", green); - restarting = false; - } - } catch (e) { - count && !restarting && console.log("⇠ 💔"); - error = e; - } finally { - if (error) { - if (!restarting || manualRestartActive) { - restarting = true; - if (count && !manualRestartActive) { - console.log(); - addLogEntry("Detected a server crash", red); - identifiedLog(red(error.message)); - await endPrevious(); - await log_execution({ - startMessage: identifier + " Sending crash notification email", - endMessage: ({ error, result }) => { - const success = error === null && result === true; - return identifier + ` ${(success ? `Notification successfully sent to` : `Failed to notify`)} ${recipient} ${timestamp()}`; - }, - action: async () => notify(error || "Hmm, no error to report..."), - color: cyan - }); - identifiedLog(green("Initiating server restart...")); - } - manualRestartActive = false; - current_backup = exec(startServerCommand(), err => identifiedLog(err?.message || count ? "Previous server process exited." : "Spawned initial server.")); - writeLocalPidLog("server", `${(current_backup?.pid ?? -2) + 1} created ${timestamp()}`); - } - } - setTimeout(checkHeartbeat, 1000 * latency); - } -} - -async function startListening() { - identifiedLog(yellow(`After initialization, will poll server heartbeat repeatedly...\n`)); - if (!LOCATION) { - identifiedLog(red("No location specified for session manager. Please include as a command line environment variable or in a .env file.")); - process.exit(0); - } - await checkHeartbeat(); -} - -function emailText(error: any) { - return [ - `Hey ${recipient.split("@")[0]},`, - "You, as a Dash Administrator, are being notified of a server crash event. Here's what we know:", - `Location: ${LOCATION}\nError: ${error}`, - "The server should already be restarting itself, but if you're concerned, use the Remote Desktop Connection to monitor progress." - ].join("\n\n"); -} - -async function notify(error: any) { - const smtpTransport = nodemailer.createTransport({ - service: 'Gmail', - auth: { - user: 'brownptcdash@gmail.com', - pass: 'browngfx1' - } - }); - const mailOptions = { - to: recipient, - from: 'brownptcdash@gmail.com', - subject: 'Dash Server Crash', - text: emailText(error) - } as MailOptions; - return new Promise(resolve => { - smtpTransport.sendMail(mailOptions, (dispatchError: Error | null) => resolve(dispatchError === null)); - }); -} - -startListening(); \ No newline at end of file diff --git a/src/server/ProcessFactory.ts b/src/server/ProcessFactory.ts new file mode 100644 index 000000000..acb8b3a99 --- /dev/null +++ b/src/server/ProcessFactory.ts @@ -0,0 +1,44 @@ +import { existsSync, mkdirSync } from "fs"; +import { pathFromRoot, fileDescriptorFromStream } from './ActionUtilities'; +import rimraf = require("rimraf"); +import { ChildProcess, spawn, StdioOptions } from "child_process"; +import { Stream } from "stream"; + +export namespace ProcessFactory { + + export type Sink = "pipe" | "ipc" | "ignore" | "inherit" | Stream | number | null | undefined; + + export async function createWorker(command: string, args?: readonly string[], stdio?: StdioOptions | "logfile", detached = true): Promise { + if (stdio === "logfile") { + const log_fd = await Logger.create(command, args); + stdio = ["ignore", log_fd, log_fd]; + } + const child = spawn(command, args, { detached, stdio }); + child.unref(); + return child; + } + +} + +export namespace Logger { + + const logPath = pathFromRoot("./logs"); + + export async function initialize() { + if (existsSync(logPath)) { + if (!process.env.SPAWNED) { + await new Promise(resolve => rimraf(logPath, resolve)); + } + } + mkdirSync(logPath); + } + + export async function create(command: string, args?: readonly string[]): Promise { + return fileDescriptorFromStream(generate_log_path(command, args)); + } + + function generate_log_path(command: string, args?: readonly string[]) { + return pathFromRoot(`./logs/${command}-${args?.length}-${new Date().toUTCString()}.log`); + } + +} \ No newline at end of file diff --git a/src/server/index.ts b/src/server/index.ts index bc481e579..2cc35ccec 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -23,7 +23,7 @@ import GeneralGoogleManager from "./ApiManagers/GeneralGoogleManager"; import GooglePhotosManager from "./ApiManagers/GooglePhotosManager"; import { yellow, red } from "colors"; import { disconnect } from "../server/Initialization"; -import { ProcessFactory, Logger } from "./ChildProcessUtilities/ProcessFactory"; +import { ProcessFactory, Logger } from "./ProcessFactory"; export const publicDirectory = path.resolve(__dirname, "public"); export const filesDirectory = path.resolve(publicDirectory, "files"); diff --git a/src/server/session_manager/config.ts b/src/server/session_manager/config.ts new file mode 100644 index 000000000..47d3375e0 --- /dev/null +++ b/src/server/session_manager/config.ts @@ -0,0 +1,32 @@ +import { resolve } from 'path'; +import { yellow } from "colors"; + +export const latency = 10; +export const ports = [1050, 4321]; +export const onWindows = process.platform === "win32"; +export const LOCATION = "http://localhost"; +export const heartbeat = `${LOCATION}:1050/serverHeartbeat`; +export const recipient = "samuel_wilkins@brown.edu"; +export const { pid, platform } = process; + +/** + * Logging + */ +export const identifier = yellow("__session_manager__:"); + +/** + * Paths + */ +export const logPath = resolve(__dirname, "./logs"); +export const crashPath = resolve(logPath, "./crashes"); + +/** + * State + */ +export enum SessionState { + INITIALIZING, + LISTENING, + AUTOMATIC_RESTART, + MANUAL_RESTART, + EXITING +} \ No newline at end of file diff --git a/src/server/session_manager/input_manager.ts b/src/server/session_manager/input_manager.ts new file mode 100644 index 000000000..a95e6baae --- /dev/null +++ b/src/server/session_manager/input_manager.ts @@ -0,0 +1,101 @@ +import { createInterface, Interface } from "readline"; +import { red } from "colors"; + +export interface Configuration { + identifier: string; + onInvalid?: (culprit?: string) => string | string; + isCaseSensitive?: boolean; +} + +export interface Registration { + argPattern: RegExp[]; + action: (parsedArgs: IterableIterator) => any | Promise; +} + +export default class InputManager { + private identifier: string; + private onInvalid: ((culprit?: string) => string) | string; + private isCaseSensitive: boolean; + private commandMap = new Map(); + public interface: Interface; + private busy = false; + private keys: string | undefined; + + constructor({ identifier: prompt, onInvalid, isCaseSensitive }: Configuration) { + this.identifier = prompt; + this.onInvalid = onInvalid || this.usage; + this.isCaseSensitive = isCaseSensitive ?? true; + this.interface = createInterface(process.stdin, process.stdout).on('line', this.considerInput); + } + + private usage = () => { + const resolved = this.keys; + if (resolved) { + return resolved; + } + const members: string[] = []; + const keys = this.commandMap.keys(); + let next: IteratorResult; + while (!(next = keys.next()).done) { + members.push(next.value); + } + return `${this.identifier} commands: { ${members.sort().join(", ")} }`; + } + + public registerCommand = (basename: string, argPattern: RegExp[], action: any | Promise) => { + const existing = this.commandMap.get(basename); + const registration = { argPattern, action }; + if (existing) { + existing.push(registration); + } else { + this.commandMap.set(basename, [registration]); + } + } + + private invalid = (culprit?: string) => { + console.log(red(typeof this.onInvalid === "string" ? this.onInvalid : this.onInvalid(culprit))); + this.busy = false; + } + + private considerInput = async (line: string) => { + if (this.busy) { + console.log(red("Busy")); + return; + } + this.busy = true; + line = line.trim(); + if (this.isCaseSensitive) { + line = line.toLowerCase(); + } + const [command, ...args] = line.split(/\s+/g); + if (!command) { + return this.invalid(); + } + const registered = this.commandMap.get(command); + if (registered) { + const { length } = args; + const candidates = registered.filter(({ argPattern: { length: count } }) => count === length); + for (const { argPattern, action } of candidates) { + const parsed: string[] = []; + let matched = false; + if (length) { + for (let i = 0; i < length; i++) { + let matches: RegExpExecArray | null; + if ((matches = argPattern[i].exec(args[i])) === null) { + break; + } + parsed.push(matches[0]); + } + matched = true; + } + if (!length || matched) { + await action(parsed[Symbol.iterator]()); + this.busy = false; + return; + } + } + } + this.invalid(command); + } + +} \ No newline at end of file diff --git a/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-11T18:52:10.359Z.log b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-11T18:52:10.359Z.log new file mode 100644 index 000000000..4cab8a6a3 --- /dev/null +++ b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-11T18:52:10.359Z.log @@ -0,0 +1 @@ +Detected a server crash @ 2019-12-11T18:52:20.416Z. diff --git a/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:38:44.803Z.log b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:38:44.803Z.log new file mode 100644 index 000000000..3c226445d --- /dev/null +++ b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:38:44.803Z.log @@ -0,0 +1 @@ +Detected a server crash @ 2019-12-12T00:38:54.828Z. diff --git a/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:42:11.945Z.log b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:42:11.945Z.log new file mode 100644 index 000000000..59f14f288 --- /dev/null +++ b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:42:11.945Z.log @@ -0,0 +1 @@ +Detected a server crash @ 2019-12-12T00:42:21.970Z. diff --git a/src/server/session_manager/logs/current_daemon_pid.log b/src/server/session_manager/logs/current_daemon_pid.log new file mode 100644 index 000000000..557e3d7c3 --- /dev/null +++ b/src/server/session_manager/logs/current_daemon_pid.log @@ -0,0 +1 @@ +26860 diff --git a/src/server/session_manager/logs/current_server_pid.log b/src/server/session_manager/logs/current_server_pid.log new file mode 100644 index 000000000..6a2f267b3 --- /dev/null +++ b/src/server/session_manager/logs/current_server_pid.log @@ -0,0 +1 @@ +50888 created @ 2019-12-14T06:59:59.767Z diff --git a/src/server/session_manager/logs/current_session_manager_pid.log b/src/server/session_manager/logs/current_session_manager_pid.log new file mode 100644 index 000000000..ab19403b4 --- /dev/null +++ b/src/server/session_manager/logs/current_session_manager_pid.log @@ -0,0 +1 @@ +50846 diff --git a/src/server/session_manager/session_manager.ts b/src/server/session_manager/session_manager.ts new file mode 100644 index 000000000..6e9b03c79 --- /dev/null +++ b/src/server/session_manager/session_manager.ts @@ -0,0 +1,176 @@ +import * as request from "request-promise"; +import { log_execution, pathFromRoot } from "../ActionUtilities"; +import { red, yellow, cyan, green, Color } from "colors"; +import * as nodemailer from "nodemailer"; +import { MailOptions } from "nodemailer/lib/json-transport"; +import { writeFileSync, existsSync, mkdirSync } from "fs"; +import { resolve } from 'path'; +import { ChildProcess, exec, execSync } from "child_process"; +import InputManager from "./input_manager"; +import { identifier, logPath, crashPath, onWindows, pid, ports, heartbeat, recipient, LOCATION, latency } from "./config"; +const killport = require("kill-port"); + +process.on('SIGINT', endPrevious); + +const { registerCommand } = new InputManager({ identifier }); + +let manualRestartActive = false; +registerCommand("restart", [], async () => { + manualRestartActive = true; + identifiedLog(cyan("Initializing manual restart...")); + await endPrevious(); +}); + +registerCommand("exit", [], async () => { + identifiedLog(cyan("Initializing session end")); + await endPrevious(); + identifiedLog("Cleanup complete. Exiting session...\n"); + execSync(killAllCommand()); +}); + +if (!existsSync(logPath)) { + mkdirSync(logPath); +} +if (!existsSync(crashPath)) { + mkdirSync(crashPath); +} + +const crashLogPath = resolve(crashPath, `./session_crashes_${new Date().toISOString()}.log`); +function addLogEntry(message: string, color: Color) { + const formatted = color(`${message} ${timestamp()}.`); + identifiedLog(formatted); + // appendFileSync(crashLogPath, `${formatted}\n`); +} + +function identifiedLog(message?: any, ...optionalParams: any[]) { + console.log(identifier, message, ...optionalParams); +} + +if (!["win32", "darwin"].includes(process.platform)) { + identifiedLog(red("Invalid operating system: this script is supported only on Mac and Windows.")); + process.exit(1); +} + +let restarting = false; +let count = 0; + +function startServerCommand() { + if (onWindows) { + return '"C:\\Program Files\\Git\\git-bash.exe" -c "npm run start-release"'; + } + return `osascript -e 'tell app "Terminal"\ndo script "cd ${pathFromRoot()} && npm run start-release"\nend tell'`; +} + +function killAllCommand() { + if (onWindows) { + return "taskkill /f /im node.exe"; + } + return "killall -9 node"; +} + +identifiedLog("Initializing session..."); + +writeLocalPidLog("session_manager", pid); + +function writeLocalPidLog(filename: string, contents: any) { + const path = `./logs/current_${filename}_pid.log`; + identifiedLog(cyan(`${contents} written to ${path}`)); + writeFileSync(resolve(__dirname, path), `${contents}\n`); +} + +function timestamp() { + return `@ ${new Date().toISOString()}`; +} + +async function endPrevious() { + identifiedLog(yellow("Cleaning up previous connections...")); + current_backup?.kill("SIGKILL"); + await Promise.all(ports.map(port => { + const task = killport(port, 'tcp'); + return task.catch((error: any) => identifiedLog(red(error))); + })); + identifiedLog(yellow("Done. Any failures will be printed in red immediately above.")); +} + +let current_backup: ChildProcess | undefined = undefined; + +async function checkHeartbeat() { + let error: any; + try { + count && !restarting && process.stdout.write(`${identifier} 👂 `); + await request.get(heartbeat); + count && !restarting && console.log('⇠ 💚'); + if (restarting || manualRestartActive) { + addLogEntry(count++ ? "Backup server successfully restarted" : "Server successfully started", green); + restarting = false; + } + } catch (e) { + count && !restarting && console.log("⇠ 💔"); + error = e; + } finally { + if (error) { + if (!restarting || manualRestartActive) { + restarting = true; + if (count && !manualRestartActive) { + console.log(); + addLogEntry("Detected a server crash", red); + identifiedLog(red(error.message)); + await endPrevious(); + await log_execution({ + startMessage: identifier + " Sending crash notification email", + endMessage: ({ error, result }) => { + const success = error === null && result === true; + return identifier + ` ${(success ? `Notification successfully sent to` : `Failed to notify`)} ${recipient} ${timestamp()}`; + }, + action: async () => notify(error || "Hmm, no error to report..."), + color: cyan + }); + identifiedLog(green("Initiating server restart...")); + } + manualRestartActive = false; + current_backup = exec(startServerCommand(), err => identifiedLog(err?.message || count ? "Previous server process exited." : "Spawned initial server.")); + writeLocalPidLog("server", `${(current_backup?.pid ?? -2) + 1} created ${timestamp()}`); + } + } + setTimeout(checkHeartbeat, 1000 * latency); + } +} + +async function startListening() { + identifiedLog(yellow(`After initialization, will poll server heartbeat repeatedly...\n`)); + if (!LOCATION) { + identifiedLog(red("No location specified for session manager. Please include as a command line environment variable or in a .env file.")); + process.exit(0); + } + await checkHeartbeat(); +} + +function emailText(error: any) { + return [ + `Hey ${recipient.split("@")[0]},`, + "You, as a Dash Administrator, are being notified of a server crash event. Here's what we know:", + `Location: ${LOCATION}\nError: ${error}`, + "The server should already be restarting itself, but if you're concerned, use the Remote Desktop Connection to monitor progress." + ].join("\n\n"); +} + +async function notify(error: any) { + const smtpTransport = nodemailer.createTransport({ + service: 'Gmail', + auth: { + user: 'brownptcdash@gmail.com', + pass: 'browngfx1' + } + }); + const mailOptions = { + to: recipient, + from: 'brownptcdash@gmail.com', + subject: 'Dash Server Crash', + text: emailText(error) + } as MailOptions; + return new Promise(resolve => { + smtpTransport.sendMail(mailOptions, (dispatchError: Error | null) => resolve(dispatchError === null)); + }); +} + +startListening(); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From a1beec1e1ed18ffefc518876fb783b7a14282960 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 14 Dec 2019 03:05:07 -0500 Subject: repaired state logic --- src/server/session_manager/config.ts | 11 ++-- .../session_manager/logs/current_server_pid.log | 2 +- .../logs/current_session_manager_pid.log | 2 +- src/server/session_manager/session_manager.ts | 72 ++++++++++++---------- 4 files changed, 46 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/server/session_manager/config.ts b/src/server/session_manager/config.ts index 47d3375e0..a373b986e 100644 --- a/src/server/session_manager/config.ts +++ b/src/server/session_manager/config.ts @@ -24,9 +24,10 @@ export const crashPath = resolve(logPath, "./crashes"); * State */ export enum SessionState { - INITIALIZING, - LISTENING, - AUTOMATIC_RESTART, - MANUAL_RESTART, - EXITING + STARTING = "STARTING", + INITIALIZED = "INITIALIZED", + LISTENING = "LISTENING", + CRASH_RESTARTING = "CRASH_RESTARTING", + MANUALLY_RESTARTING = "MANUALLY_RESTARTING", + EXITING = "EXITING" } \ No newline at end of file diff --git a/src/server/session_manager/logs/current_server_pid.log b/src/server/session_manager/logs/current_server_pid.log index 6a2f267b3..85fdb7ae0 100644 --- a/src/server/session_manager/logs/current_server_pid.log +++ b/src/server/session_manager/logs/current_server_pid.log @@ -1 +1 @@ -50888 created @ 2019-12-14T06:59:59.767Z +54649 created @ 2019-12-14T08:04:42.391Z diff --git a/src/server/session_manager/logs/current_session_manager_pid.log b/src/server/session_manager/logs/current_session_manager_pid.log index ab19403b4..75c23b35a 100644 --- a/src/server/session_manager/logs/current_session_manager_pid.log +++ b/src/server/session_manager/logs/current_session_manager_pid.log @@ -1 +1 @@ -50846 +54643 diff --git a/src/server/session_manager/session_manager.ts b/src/server/session_manager/session_manager.ts index 6e9b03c79..51aba26a0 100644 --- a/src/server/session_manager/session_manager.ts +++ b/src/server/session_manager/session_manager.ts @@ -7,27 +7,32 @@ import { writeFileSync, existsSync, mkdirSync } from "fs"; import { resolve } from 'path'; import { ChildProcess, exec, execSync } from "child_process"; import InputManager from "./input_manager"; -import { identifier, logPath, crashPath, onWindows, pid, ports, heartbeat, recipient, LOCATION, latency } from "./config"; +import { identifier, logPath, crashPath, onWindows, pid, ports, heartbeat, recipient, LOCATION, latency, SessionState } from "./config"; const killport = require("kill-port"); process.on('SIGINT', endPrevious); +let state: SessionState = SessionState.STARTING; +const is = (...reference: SessionState[]) => reference.includes(state); +const set = (reference: SessionState) => state = reference; const { registerCommand } = new InputManager({ identifier }); -let manualRestartActive = false; registerCommand("restart", [], async () => { - manualRestartActive = true; + set(SessionState.MANUALLY_RESTARTING); identifiedLog(cyan("Initializing manual restart...")); await endPrevious(); }); registerCommand("exit", [], async () => { + set(SessionState.EXITING); identifiedLog(cyan("Initializing session end")); await endPrevious(); identifiedLog("Cleanup complete. Exiting session...\n"); execSync(killAllCommand()); }); +registerCommand("state", [], () => identifiedLog(state)); + if (!existsSync(logPath)) { mkdirSync(logPath); } @@ -51,9 +56,6 @@ if (!["win32", "darwin"].includes(process.platform)) { process.exit(1); } -let restarting = false; -let count = 0; - function startServerCommand() { if (onWindows) { return '"C:\\Program Files\\Git\\git-bash.exe" -c "npm run start-release"'; @@ -95,42 +97,44 @@ async function endPrevious() { let current_backup: ChildProcess | undefined = undefined; async function checkHeartbeat() { + const listening = is(SessionState.LISTENING); let error: any; try { - count && !restarting && process.stdout.write(`${identifier} 👂 `); + listening && process.stdout.write(`${identifier} 👂 `); await request.get(heartbeat); - count && !restarting && console.log('⇠ 💚'); - if (restarting || manualRestartActive) { - addLogEntry(count++ ? "Backup server successfully restarted" : "Server successfully started", green); - restarting = false; + listening && console.log('⇠ 💚'); + if (!listening) { + addLogEntry(is(SessionState.INITIALIZED) ? "Server successfully started" : "Backup server successfully restarted", green); + set(SessionState.LISTENING); } } catch (e) { - count && !restarting && console.log("⇠ 💔"); + listening && console.log("⇠ 💔"); error = e; } finally { - if (error) { - if (!restarting || manualRestartActive) { - restarting = true; - if (count && !manualRestartActive) { - console.log(); - addLogEntry("Detected a server crash", red); - identifiedLog(red(error.message)); - await endPrevious(); - await log_execution({ - startMessage: identifier + " Sending crash notification email", - endMessage: ({ error, result }) => { - const success = error === null && result === true; - return identifier + ` ${(success ? `Notification successfully sent to` : `Failed to notify`)} ${recipient} ${timestamp()}`; - }, - action: async () => notify(error || "Hmm, no error to report..."), - color: cyan - }); - identifiedLog(green("Initiating server restart...")); - } - manualRestartActive = false; - current_backup = exec(startServerCommand(), err => identifiedLog(err?.message || count ? "Previous server process exited." : "Spawned initial server.")); - writeLocalPidLog("server", `${(current_backup?.pid ?? -2) + 1} created ${timestamp()}`); + if (error && !is(SessionState.CRASH_RESTARTING, SessionState.INITIALIZED)) { + if (is(SessionState.STARTING)) { + set(SessionState.INITIALIZED); + } else if (is(SessionState.MANUALLY_RESTARTING)) { + set(SessionState.CRASH_RESTARTING); + } else { + set(SessionState.CRASH_RESTARTING); + console.log(); + addLogEntry("Detected a server crash", red); + identifiedLog(red(error.message)); + await endPrevious(); + await log_execution({ + startMessage: identifier + " Sending crash notification email", + endMessage: ({ error, result }) => { + const success = error === null && result === true; + return identifier + ` ${(success ? `Notification successfully sent to` : `Failed to notify`)} ${recipient} ${timestamp()}`; + }, + action: async () => notify(error || "Hmm, no error to report..."), + color: cyan + }); + identifiedLog(green("Initiating server restart...")); } + current_backup = exec(startServerCommand(), err => identifiedLog(err?.message || is(SessionState.INITIALIZED) ? "Spawned initial server." : "Previous server process exited.")); + writeLocalPidLog("server", `${(current_backup?.pid ?? -2) + 1} created ${timestamp()}`); } setTimeout(checkHeartbeat, 1000 * latency); } -- cgit v1.2.3-70-g09d2 From 1587e3ce712d08b3e6a43dd770c4d586e82f1b23 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 14 Dec 2019 11:24:20 -0500 Subject: constant changes --- src/server/session_manager/config.ts | 5 ++--- src/server/session_manager/session_manager.ts | 22 +++++++--------------- 2 files changed, 9 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/server/session_manager/config.ts b/src/server/session_manager/config.ts index a373b986e..bb84a166d 100644 --- a/src/server/session_manager/config.ts +++ b/src/server/session_manager/config.ts @@ -4,8 +4,7 @@ import { yellow } from "colors"; export const latency = 10; export const ports = [1050, 4321]; export const onWindows = process.platform === "win32"; -export const LOCATION = "http://localhost"; -export const heartbeat = `${LOCATION}:1050/serverHeartbeat`; +export const heartbeat = `http://localhost:1050/serverHeartbeat`; export const recipient = "samuel_wilkins@brown.edu"; export const { pid, platform } = process; @@ -27,7 +26,7 @@ export enum SessionState { STARTING = "STARTING", INITIALIZED = "INITIALIZED", LISTENING = "LISTENING", - CRASH_RESTARTING = "CRASH_RESTARTING", + AUTOMATICALLY_RESTARTING = "CRASH_RESTARTING", MANUALLY_RESTARTING = "MANUALLY_RESTARTING", EXITING = "EXITING" } \ No newline at end of file diff --git a/src/server/session_manager/session_manager.ts b/src/server/session_manager/session_manager.ts index 51aba26a0..97b71403b 100644 --- a/src/server/session_manager/session_manager.ts +++ b/src/server/session_manager/session_manager.ts @@ -7,7 +7,7 @@ import { writeFileSync, existsSync, mkdirSync } from "fs"; import { resolve } from 'path'; import { ChildProcess, exec, execSync } from "child_process"; import InputManager from "./input_manager"; -import { identifier, logPath, crashPath, onWindows, pid, ports, heartbeat, recipient, LOCATION, latency, SessionState } from "./config"; +import { identifier, logPath, crashPath, onWindows, pid, ports, heartbeat, recipient, latency, SessionState } from "./config"; const killport = require("kill-port"); process.on('SIGINT', endPrevious); @@ -111,13 +111,13 @@ async function checkHeartbeat() { listening && console.log("⇠ 💔"); error = e; } finally { - if (error && !is(SessionState.CRASH_RESTARTING, SessionState.INITIALIZED)) { + if (error && !is(SessionState.AUTOMATICALLY_RESTARTING, SessionState.INITIALIZED)) { if (is(SessionState.STARTING)) { set(SessionState.INITIALIZED); } else if (is(SessionState.MANUALLY_RESTARTING)) { - set(SessionState.CRASH_RESTARTING); + set(SessionState.AUTOMATICALLY_RESTARTING); } else { - set(SessionState.CRASH_RESTARTING); + set(SessionState.AUTOMATICALLY_RESTARTING); console.log(); addLogEntry("Detected a server crash", red); identifiedLog(red(error.message)); @@ -140,20 +140,11 @@ async function checkHeartbeat() { } } -async function startListening() { - identifiedLog(yellow(`After initialization, will poll server heartbeat repeatedly...\n`)); - if (!LOCATION) { - identifiedLog(red("No location specified for session manager. Please include as a command line environment variable or in a .env file.")); - process.exit(0); - } - await checkHeartbeat(); -} - function emailText(error: any) { return [ `Hey ${recipient.split("@")[0]},`, "You, as a Dash Administrator, are being notified of a server crash event. Here's what we know:", - `Location: ${LOCATION}\nError: ${error}`, + `Location: ${heartbeat}\nError: ${error}`, "The server should already be restarting itself, but if you're concerned, use the Remote Desktop Connection to monitor progress." ].join("\n\n"); } @@ -177,4 +168,5 @@ async function notify(error: any) { }); } -startListening(); \ No newline at end of file +identifiedLog(yellow(`After initialization, will poll server heartbeat repeatedly...\n`)); +checkHeartbeat(); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 0ed6eea09a91146e0bbd51d52f90c513ba92ed19 Mon Sep 17 00:00:00 2001 From: Sam Wilkins <35748010+samwilkins333@users.noreply.github.com> Date: Sat, 14 Dec 2019 11:47:03 -0500 Subject: Delete session_crashes_@ 2019-12-11T18:52:10.359Z.log --- .../logs/crashes/session_crashes_@ 2019-12-11T18:52:10.359Z.log | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-11T18:52:10.359Z.log (limited to 'src') diff --git a/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-11T18:52:10.359Z.log b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-11T18:52:10.359Z.log deleted file mode 100644 index 4cab8a6a3..000000000 --- a/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-11T18:52:10.359Z.log +++ /dev/null @@ -1 +0,0 @@ -Detected a server crash @ 2019-12-11T18:52:20.416Z. -- cgit v1.2.3-70-g09d2 From bdd6cdb375752531da68477ae136faeb3b2a7813 Mon Sep 17 00:00:00 2001 From: Sam Wilkins <35748010+samwilkins333@users.noreply.github.com> Date: Sat, 14 Dec 2019 11:47:09 -0500 Subject: Delete session_crashes_@ 2019-12-12T00:38:44.803Z.log --- .../logs/crashes/session_crashes_@ 2019-12-12T00:38:44.803Z.log | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:38:44.803Z.log (limited to 'src') diff --git a/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:38:44.803Z.log b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:38:44.803Z.log deleted file mode 100644 index 3c226445d..000000000 --- a/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:38:44.803Z.log +++ /dev/null @@ -1 +0,0 @@ -Detected a server crash @ 2019-12-12T00:38:54.828Z. -- cgit v1.2.3-70-g09d2 From 6d74e1870fcbcd0fa873ce308709f1f3741de538 Mon Sep 17 00:00:00 2001 From: Sam Wilkins <35748010+samwilkins333@users.noreply.github.com> Date: Sat, 14 Dec 2019 11:47:16 -0500 Subject: Delete session_crashes_@ 2019-12-12T00:42:11.945Z.log --- .../logs/crashes/session_crashes_@ 2019-12-12T00:42:11.945Z.log | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:42:11.945Z.log (limited to 'src') diff --git a/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:42:11.945Z.log b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:42:11.945Z.log deleted file mode 100644 index 59f14f288..000000000 --- a/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:42:11.945Z.log +++ /dev/null @@ -1 +0,0 @@ -Detected a server crash @ 2019-12-12T00:42:21.970Z. -- cgit v1.2.3-70-g09d2 From b913591895e18fad58a5a12ad3beb522073c4b04 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 14 Dec 2019 11:50:38 -0500 Subject: test --- src/server/session_manager/session_manager.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/server/session_manager/session_manager.ts b/src/server/session_manager/session_manager.ts index 97b71403b..9fe4b1ab8 100644 --- a/src/server/session_manager/session_manager.ts +++ b/src/server/session_manager/session_manager.ts @@ -40,11 +40,10 @@ if (!existsSync(crashPath)) { mkdirSync(crashPath); } -const crashLogPath = resolve(crashPath, `./session_crashes_${new Date().toISOString()}.log`); function addLogEntry(message: string, color: Color) { const formatted = color(`${message} ${timestamp()}.`); identifiedLog(formatted); - // appendFileSync(crashLogPath, `${formatted}\n`); + // appendFileSync(resolve(crashPath, `./session_crashes_${new Date().toISOString()}.log`), `${formatted}\n`); } function identifiedLog(message?: any, ...optionalParams: any[]) { -- cgit v1.2.3-70-g09d2 From e959463fcc494eb6a3e92809cbeb27024169c8f0 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 14 Dec 2019 12:02:36 -0500 Subject: updating --- src/server/session_manager/config.ts | 3 ++- src/server/session_manager/session_manager.ts | 12 +++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/server/session_manager/config.ts b/src/server/session_manager/config.ts index bb84a166d..ebbd999c6 100644 --- a/src/server/session_manager/config.ts +++ b/src/server/session_manager/config.ts @@ -28,5 +28,6 @@ export enum SessionState { LISTENING = "LISTENING", AUTOMATICALLY_RESTARTING = "CRASH_RESTARTING", MANUALLY_RESTARTING = "MANUALLY_RESTARTING", - EXITING = "EXITING" + EXITING = "EXITING", + UPDATING = "UPDATING" } \ No newline at end of file diff --git a/src/server/session_manager/session_manager.ts b/src/server/session_manager/session_manager.ts index 9fe4b1ab8..b620c8502 100644 --- a/src/server/session_manager/session_manager.ts +++ b/src/server/session_manager/session_manager.ts @@ -31,6 +31,16 @@ registerCommand("exit", [], async () => { execSync(killAllCommand()); }); +registerCommand("update", [], async () => { + set(SessionState.UPDATING); + await new Promise(resolve => { + exec("git pull && npm install", () => { + resolve(); + }); + }); + set(SessionState.MANUALLY_RESTARTING); +}); + registerCommand("state", [], () => identifiedLog(state)); if (!existsSync(logPath)) { @@ -110,7 +120,7 @@ async function checkHeartbeat() { listening && console.log("⇠ 💔"); error = e; } finally { - if (error && !is(SessionState.AUTOMATICALLY_RESTARTING, SessionState.INITIALIZED)) { + if (error && !is(SessionState.AUTOMATICALLY_RESTARTING, SessionState.INITIALIZED, SessionState.UPDATING)) { if (is(SessionState.STARTING)) { set(SessionState.INITIALIZED); } else if (is(SessionState.MANUALLY_RESTARTING)) { -- cgit v1.2.3-70-g09d2 From 559a709a4901ccb1932d8d2845a199d91093153c Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 14 Dec 2019 12:05:00 -0500 Subject: log during update --- src/server/session_manager/session_manager.ts | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/server/session_manager/session_manager.ts b/src/server/session_manager/session_manager.ts index b620c8502..37b32d621 100644 --- a/src/server/session_manager/session_manager.ts +++ b/src/server/session_manager/session_manager.ts @@ -33,12 +33,15 @@ registerCommand("exit", [], async () => { registerCommand("update", [], async () => { set(SessionState.UPDATING); + identifiedLog(cyan("Initializing server update from version control...")); + await endPrevious(); await new Promise(resolve => { exec("git pull && npm install", () => { resolve(); }); }); set(SessionState.MANUALLY_RESTARTING); + identifiedLog("Update complete. Initializing manual restart...\n"); }); registerCommand("state", [], () => identifiedLog(state)); -- cgit v1.2.3-70-g09d2 From b9ca80873fdfb3c0e2b48ee715e9cbc4ff968aba Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 14 Dec 2019 12:09:05 -0500 Subject: update --- src/server/session_manager/session_manager.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/session_manager/session_manager.ts b/src/server/session_manager/session_manager.ts index 37b32d621..d5ef94dc7 100644 --- a/src/server/session_manager/session_manager.ts +++ b/src/server/session_manager/session_manager.ts @@ -36,7 +36,10 @@ registerCommand("update", [], async () => { identifiedLog(cyan("Initializing server update from version control...")); await endPrevious(); await new Promise(resolve => { - exec("git pull && npm install", () => { + exec(updateCommand(), error => { + if (error) { + identifiedLog(red(error.message)); + } resolve(); }); }); @@ -68,6 +71,13 @@ if (!["win32", "darwin"].includes(process.platform)) { process.exit(1); } +function updateCommand() { + if (onWindows) { + return '"C:\\Program Files\\Git\\git-bash.exe" -c "git pull && npm install"'; + } + return `osascript -e 'tell app "Terminal"\ndo script "cd ${pathFromRoot()} && git pull && npm install"\nend tell'`; +} + function startServerCommand() { if (onWindows) { return '"C:\\Program Files\\Git\\git-bash.exe" -c "npm run start-release"'; -- cgit v1.2.3-70-g09d2 From e38cf2b6186378eb85ba49eda481233b220ccb7b Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 14 Dec 2019 12:15:27 -0500 Subject: draft update protocl --- src/server/session_manager/session_manager.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/server/session_manager/session_manager.ts b/src/server/session_manager/session_manager.ts index d5ef94dc7..35cc833f2 100644 --- a/src/server/session_manager/session_manager.ts +++ b/src/server/session_manager/session_manager.ts @@ -23,13 +23,15 @@ registerCommand("restart", [], async () => { await endPrevious(); }); -registerCommand("exit", [], async () => { +registerCommand("exit", [], exit); + +async function exit() { set(SessionState.EXITING); identifiedLog(cyan("Initializing session end")); await endPrevious(); identifiedLog("Cleanup complete. Exiting session...\n"); execSync(killAllCommand()); -}); +} registerCommand("update", [], async () => { set(SessionState.UPDATING); @@ -43,8 +45,7 @@ registerCommand("update", [], async () => { resolve(); }); }); - set(SessionState.MANUALLY_RESTARTING); - identifiedLog("Update complete. Initializing manual restart...\n"); + await exit(); }); registerCommand("state", [], () => identifiedLog(state)); -- cgit v1.2.3-70-g09d2 From d7bc3d445fdf0ffc86812da27cf07e51bfbfe9c5 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 14 Dec 2019 12:38:31 -0500 Subject: factored out commands --- src/server/session_manager/session_manager.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/server/session_manager/session_manager.ts b/src/server/session_manager/session_manager.ts index 35cc833f2..92f1eaa05 100644 --- a/src/server/session_manager/session_manager.ts +++ b/src/server/session_manager/session_manager.ts @@ -72,18 +72,23 @@ if (!["win32", "darwin"].includes(process.platform)) { process.exit(1); } +const windowsPrepend = (command: string) => `"C:\\Program Files\\Git\\git-bash.exe" -c "${command}"`; +const macPrepend = (command: string) => `osascript -e 'tell app "Terminal"\ndo script "cd ${pathFromRoot()} && ${command}"\nend tell'`; + function updateCommand() { + const command = "git pull && npm install"; if (onWindows) { - return '"C:\\Program Files\\Git\\git-bash.exe" -c "git pull && npm install"'; + return windowsPrepend(command); } - return `osascript -e 'tell app "Terminal"\ndo script "cd ${pathFromRoot()} && git pull && npm install"\nend tell'`; + return macPrepend(command); } function startServerCommand() { + const command = "npm run start-release"; if (onWindows) { - return '"C:\\Program Files\\Git\\git-bash.exe" -c "npm run start-release"'; + return windowsPrepend(command); } - return `osascript -e 'tell app "Terminal"\ndo script "cd ${pathFromRoot()} && npm run start-release"\nend tell'`; + return macPrepend(command); } function killAllCommand() { -- cgit v1.2.3-70-g09d2 From 50940d2f1680aabbadcf9dd6e5455b7c7517115a Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 14 Dec 2019 12:39:20 -0500 Subject: newline --- src/server/session_manager/session_manager.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/server/session_manager/session_manager.ts b/src/server/session_manager/session_manager.ts index 92f1eaa05..d8b2f6e74 100644 --- a/src/server/session_manager/session_manager.ts +++ b/src/server/session_manager/session_manager.ts @@ -136,7 +136,7 @@ async function checkHeartbeat() { set(SessionState.LISTENING); } } catch (e) { - listening && console.log("⇠ 💔"); + listening && console.log("⇠ 💔\n"); error = e; } finally { if (error && !is(SessionState.AUTOMATICALLY_RESTARTING, SessionState.INITIALIZED, SessionState.UPDATING)) { @@ -146,7 +146,6 @@ async function checkHeartbeat() { set(SessionState.AUTOMATICALLY_RESTARTING); } else { set(SessionState.AUTOMATICALLY_RESTARTING); - console.log(); addLogEntry("Detected a server crash", red); identifiedLog(red(error.message)); await endPrevious(); -- cgit v1.2.3-70-g09d2