2020-04-18 13:37:47 -04:00
|
|
|
import fs from 'fs'
|
2020-06-12 16:15:04 -04:00
|
|
|
import { config } from '../config'
|
|
|
|
import { logger } from '../logger'
|
|
|
|
import { Revision } from '../models'
|
Improve handling of termination signals
Previously, upon receiving a termination signal, the process tries to
flush all changes to the database, retrying every 0.1s until it
succeeds. However, if the database is not set up properly, this always
fails, and spams the terminal/logging with the error message 10 times a
second.
If the user sends another termination signal, the handleTermSignal
function is called once again, and we get twice the number of error
messages.
This commit changes the behaviour in various ways.
(1) It lowers the retry rate to 0.5s, and aborts after 30 seconds.
(2) If the write to the database errored, the error message explains
that this is due to us flushing the final changes.
(3) We replace realtime.maintenance with realtime.state, which is an
Enum with three possible states --- Starting, Running, and Stopping.
If a termination signal is received in the starting state, the
process simply aborts because there is nothing to clean up. This is
the case when the database is misconfigured, since the application
starts up only after connecting to the databse. If it is in the
Stopping state, the handleTermSignal function returns because
another instance of handleTermSignal is already running.
Fixes #408
Signed-off-by: Dexter Chua <dec41@srcf.net>
2020-06-26 23:06:48 -04:00
|
|
|
import { realtime, State } from '../realtime'
|
2020-04-11 04:22:06 -04:00
|
|
|
|
2020-05-31 15:43:14 -04:00
|
|
|
/*
|
|
|
|
Converts a map from string to something into a plain JS object for transmitting via a websocket
|
|
|
|
*/
|
|
|
|
export function mapToObject<T> (map: Map<string, T>): object {
|
|
|
|
return Array.from(map).reduce((obj, [key, value]) => {
|
|
|
|
obj[key] = value
|
|
|
|
return obj
|
|
|
|
}, {})
|
|
|
|
}
|
|
|
|
|
2020-04-12 14:37:04 -04:00
|
|
|
export function getImageMimeType (imagePath: string): string | undefined {
|
|
|
|
const fileExtension = /[^.]+$/.exec(imagePath)
|
|
|
|
switch (fileExtension?.[0]) {
|
|
|
|
case 'bmp':
|
|
|
|
return 'image/bmp'
|
|
|
|
case 'gif':
|
|
|
|
return 'image/gif'
|
|
|
|
case 'jpg':
|
|
|
|
case 'jpeg':
|
|
|
|
return 'image/jpeg'
|
|
|
|
case 'png':
|
|
|
|
return 'image/png'
|
|
|
|
case 'tiff':
|
|
|
|
return 'image/tiff'
|
|
|
|
case 'svg':
|
|
|
|
return 'image/svg+xml'
|
|
|
|
default:
|
|
|
|
return undefined
|
2020-04-11 05:22:55 -04:00
|
|
|
}
|
2020-04-12 14:37:04 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// [Postgres] Handling NULL bytes
|
|
|
|
// https://github.com/sequelize/sequelize/issues/6485
|
|
|
|
export function stripNullByte (value: string): string {
|
|
|
|
value = '' + value
|
|
|
|
// eslint-disable-next-line no-control-regex
|
|
|
|
return value ? value.replace(/\u0000/g, '') : value
|
|
|
|
}
|
2020-04-11 05:22:55 -04:00
|
|
|
|
2020-05-09 11:08:35 -04:00
|
|
|
export function processData<T> (data: T, _default: T, process?: (T) => T): T | undefined {
|
|
|
|
if (data === undefined) return undefined
|
|
|
|
else if (data === null) return _default
|
|
|
|
else if (process) return process(data)
|
|
|
|
else return data
|
2020-04-11 04:22:06 -04:00
|
|
|
}
|
2020-04-18 13:37:47 -04:00
|
|
|
|
|
|
|
export function handleTermSignals (io): void {
|
Improve handling of termination signals
Previously, upon receiving a termination signal, the process tries to
flush all changes to the database, retrying every 0.1s until it
succeeds. However, if the database is not set up properly, this always
fails, and spams the terminal/logging with the error message 10 times a
second.
If the user sends another termination signal, the handleTermSignal
function is called once again, and we get twice the number of error
messages.
This commit changes the behaviour in various ways.
(1) It lowers the retry rate to 0.5s, and aborts after 30 seconds.
(2) If the write to the database errored, the error message explains
that this is due to us flushing the final changes.
(3) We replace realtime.maintenance with realtime.state, which is an
Enum with three possible states --- Starting, Running, and Stopping.
If a termination signal is received in the starting state, the
process simply aborts because there is nothing to clean up. This is
the case when the database is misconfigured, since the application
starts up only after connecting to the databse. If it is in the
Stopping state, the handleTermSignal function returns because
another instance of handleTermSignal is already running.
Fixes #408
Signed-off-by: Dexter Chua <dec41@srcf.net>
2020-06-26 23:06:48 -04:00
|
|
|
if (realtime.state === State.Starting) {
|
|
|
|
process.exit(0)
|
|
|
|
}
|
|
|
|
if (realtime.state === State.Stopping) {
|
|
|
|
// The function is already running. Do nothing
|
|
|
|
return
|
|
|
|
}
|
2020-04-18 13:37:47 -04:00
|
|
|
logger.info('CodiMD has been killed by signal, try to exit gracefully...')
|
Improve handling of termination signals
Previously, upon receiving a termination signal, the process tries to
flush all changes to the database, retrying every 0.1s until it
succeeds. However, if the database is not set up properly, this always
fails, and spams the terminal/logging with the error message 10 times a
second.
If the user sends another termination signal, the handleTermSignal
function is called once again, and we get twice the number of error
messages.
This commit changes the behaviour in various ways.
(1) It lowers the retry rate to 0.5s, and aborts after 30 seconds.
(2) If the write to the database errored, the error message explains
that this is due to us flushing the final changes.
(3) We replace realtime.maintenance with realtime.state, which is an
Enum with three possible states --- Starting, Running, and Stopping.
If a termination signal is received in the starting state, the
process simply aborts because there is nothing to clean up. This is
the case when the database is misconfigured, since the application
starts up only after connecting to the databse. If it is in the
Stopping state, the handleTermSignal function returns because
another instance of handleTermSignal is already running.
Fixes #408
Signed-off-by: Dexter Chua <dec41@srcf.net>
2020-06-26 23:06:48 -04:00
|
|
|
realtime.state = State.Stopping
|
2020-04-18 13:37:47 -04:00
|
|
|
// disconnect all socket.io clients
|
|
|
|
Object.keys(io.sockets.sockets).forEach(function (key) {
|
|
|
|
const socket = io.sockets.sockets[key]
|
|
|
|
// notify client server going into maintenance status
|
|
|
|
socket.emit('maintenance')
|
|
|
|
setTimeout(function () {
|
|
|
|
socket.disconnect(true)
|
|
|
|
}, 0)
|
|
|
|
})
|
|
|
|
if (config.path) {
|
|
|
|
// ToDo: add a proper error handler
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
2020-05-09 11:08:35 -04:00
|
|
|
fs.unlink(config.path, (_) => {
|
|
|
|
})
|
2020-04-18 13:37:47 -04:00
|
|
|
}
|
|
|
|
const checkCleanTimer = setInterval(function () {
|
|
|
|
if (realtime.isReady()) {
|
|
|
|
Revision.checkAllNotesRevision(function (err, notes) {
|
|
|
|
if (err) {
|
Improve handling of termination signals
Previously, upon receiving a termination signal, the process tries to
flush all changes to the database, retrying every 0.1s until it
succeeds. However, if the database is not set up properly, this always
fails, and spams the terminal/logging with the error message 10 times a
second.
If the user sends another termination signal, the handleTermSignal
function is called once again, and we get twice the number of error
messages.
This commit changes the behaviour in various ways.
(1) It lowers the retry rate to 0.5s, and aborts after 30 seconds.
(2) If the write to the database errored, the error message explains
that this is due to us flushing the final changes.
(3) We replace realtime.maintenance with realtime.state, which is an
Enum with three possible states --- Starting, Running, and Stopping.
If a termination signal is received in the starting state, the
process simply aborts because there is nothing to clean up. This is
the case when the database is misconfigured, since the application
starts up only after connecting to the databse. If it is in the
Stopping state, the handleTermSignal function returns because
another instance of handleTermSignal is already running.
Fixes #408
Signed-off-by: Dexter Chua <dec41@srcf.net>
2020-06-26 23:06:48 -04:00
|
|
|
return logger.error('Error while writing changes to database. We will abort after trying for 30 seconds.\n' + err)
|
2020-04-18 13:37:47 -04:00
|
|
|
}
|
|
|
|
if (!notes || notes.length <= 0) {
|
|
|
|
clearInterval(checkCleanTimer)
|
|
|
|
return process.exit(0)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
Improve handling of termination signals
Previously, upon receiving a termination signal, the process tries to
flush all changes to the database, retrying every 0.1s until it
succeeds. However, if the database is not set up properly, this always
fails, and spams the terminal/logging with the error message 10 times a
second.
If the user sends another termination signal, the handleTermSignal
function is called once again, and we get twice the number of error
messages.
This commit changes the behaviour in various ways.
(1) It lowers the retry rate to 0.5s, and aborts after 30 seconds.
(2) If the write to the database errored, the error message explains
that this is due to us flushing the final changes.
(3) We replace realtime.maintenance with realtime.state, which is an
Enum with three possible states --- Starting, Running, and Stopping.
If a termination signal is received in the starting state, the
process simply aborts because there is nothing to clean up. This is
the case when the database is misconfigured, since the application
starts up only after connecting to the databse. If it is in the
Stopping state, the handleTermSignal function returns because
another instance of handleTermSignal is already running.
Fixes #408
Signed-off-by: Dexter Chua <dec41@srcf.net>
2020-06-26 23:06:48 -04:00
|
|
|
}, 500)
|
|
|
|
setTimeout(function () {
|
|
|
|
logger.error('Failed to write changes to database. Aborting')
|
|
|
|
clearInterval(checkCleanTimer)
|
|
|
|
process.exit(1)
|
|
|
|
}, 30000)
|
2020-04-18 13:37:47 -04:00
|
|
|
}
|