refactor(backend): refactor ChartManagementService
This commit is contained in:
parent
72253a1029
commit
3010dc207a
|
@ -1,5 +1,4 @@
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { beforeShutdown } from '@/misc/before-shutdown.js';
|
|
||||||
|
|
||||||
import FederationChart from './charts/federation.js';
|
import FederationChart from './charts/federation.js';
|
||||||
import NotesChart from './charts/notes.js';
|
import NotesChart from './charts/notes.js';
|
||||||
|
@ -13,9 +12,13 @@ import HashtagChart from './charts/hashtag.js';
|
||||||
import PerUserFollowingChart from './charts/per-user-following.js';
|
import PerUserFollowingChart from './charts/per-user-following.js';
|
||||||
import PerUserDriveChart from './charts/per-user-drive.js';
|
import PerUserDriveChart from './charts/per-user-drive.js';
|
||||||
import ApRequestChart from './charts/ap-request.js';
|
import ApRequestChart from './charts/ap-request.js';
|
||||||
|
import type { OnApplicationShutdown } from '@nestjs/common';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ChartManagementService {
|
export class ChartManagementService implements OnApplicationShutdown {
|
||||||
|
private charts;
|
||||||
|
private saveIntervalId: NodeJS.Timer;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private federationChart: FederationChart,
|
private federationChart: FederationChart,
|
||||||
private notesChart: NotesChart,
|
private notesChart: NotesChart,
|
||||||
|
@ -29,10 +32,8 @@ export class ChartManagementService {
|
||||||
private perUserFollowingChart: PerUserFollowingChart,
|
private perUserFollowingChart: PerUserFollowingChart,
|
||||||
private perUserDriveChart: PerUserDriveChart,
|
private perUserDriveChart: PerUserDriveChart,
|
||||||
private apRequestChart: ApRequestChart,
|
private apRequestChart: ApRequestChart,
|
||||||
) {}
|
) {
|
||||||
|
this.charts = [
|
||||||
public async run() {
|
|
||||||
const charts = [
|
|
||||||
this.federationChart,
|
this.federationChart,
|
||||||
this.notesChart,
|
this.notesChart,
|
||||||
this.usersChart,
|
this.usersChart,
|
||||||
|
@ -46,14 +47,21 @@ export class ChartManagementService {
|
||||||
this.perUserDriveChart,
|
this.perUserDriveChart,
|
||||||
this.apRequestChart,
|
this.apRequestChart,
|
||||||
];
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public async run() {
|
||||||
// 20分おきにメモリ情報をDBに書き込み
|
// 20分おきにメモリ情報をDBに書き込み
|
||||||
setInterval(() => {
|
this.saveIntervalId = setInterval(() => {
|
||||||
for (const chart of charts) {
|
for (const chart of this.charts) {
|
||||||
chart.save();
|
chart.save();
|
||||||
}
|
}
|
||||||
}, 1000 * 60 * 20);
|
}, 1000 * 60 * 20);
|
||||||
|
}
|
||||||
|
|
||||||
beforeShutdown(() => Promise.all(charts.map(chart => chart.save())));
|
async onApplicationShutdown(signal: string): Promise<void> {
|
||||||
|
clearInterval(this.saveIntervalId);
|
||||||
|
await Promise.all(
|
||||||
|
this.charts.map(chart => chart.save()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,94 +0,0 @@
|
||||||
// https://gist.github.com/nfantone/1eaa803772025df69d07f4dbf5df7e58
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @callback BeforeShutdownListener
|
|
||||||
* @param {string} [signalOrEvent] The exit signal or event name received on the process.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* System signals the app will listen to initiate shutdown.
|
|
||||||
* @const {string[]}
|
|
||||||
*/
|
|
||||||
const SHUTDOWN_SIGNALS = ['SIGINT', 'SIGTERM'];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Time in milliseconds to wait before forcing shutdown.
|
|
||||||
* @const {number}
|
|
||||||
*/
|
|
||||||
const SHUTDOWN_TIMEOUT = 15000;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A queue of listener callbacks to execute before shutting
|
|
||||||
* down the process.
|
|
||||||
* @type {BeforeShutdownListener[]}
|
|
||||||
*/
|
|
||||||
const shutdownListeners: ((signalOrEvent: string) => void)[] = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listen for signals and execute given `fn` function once.
|
|
||||||
* @param {string[]} signals System signals to listen to.
|
|
||||||
* @param {function(string)} fn Function to execute on shutdown.
|
|
||||||
*/
|
|
||||||
const processOnce = (signals: string[], fn: (signalOrEvent: string) => void) => {
|
|
||||||
for (const sig of signals) {
|
|
||||||
process.once(sig, fn);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a forced shutdown mechanism that will exit the process after `timeout` milliseconds.
|
|
||||||
* @param {number} timeout Time to wait before forcing shutdown (milliseconds)
|
|
||||||
*/
|
|
||||||
const forceExitAfter = (timeout: number) => () => {
|
|
||||||
setTimeout(() => {
|
|
||||||
// Force shutdown after timeout
|
|
||||||
console.warn(`Could not close resources gracefully after ${timeout}ms: forcing shutdown`);
|
|
||||||
return process.exit(1);
|
|
||||||
}, timeout).unref();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main process shutdown handler. Will invoke every previously registered async shutdown listener
|
|
||||||
* in the queue and exit with a code of `0`. Any `Promise` rejections from any listener will
|
|
||||||
* be logged out as a warning, but won't prevent other callbacks from executing.
|
|
||||||
* @param {string} signalOrEvent The exit signal or event name received on the process.
|
|
||||||
*/
|
|
||||||
async function shutdownHandler(signalOrEvent: string) {
|
|
||||||
if (process.env.NODE_ENV === 'test') return process.exit(0);
|
|
||||||
|
|
||||||
console.warn(`Shutting down: received [${signalOrEvent}] signal`);
|
|
||||||
|
|
||||||
for (const listener of shutdownListeners) {
|
|
||||||
try {
|
|
||||||
await listener(signalOrEvent);
|
|
||||||
} catch (err) {
|
|
||||||
if (err instanceof Error) {
|
|
||||||
console.warn(`A shutdown handler failed before completing with: ${err.message ?? err}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return process.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a new shutdown listener to be invoked before exiting
|
|
||||||
* the main process. Listener handlers are guaranteed to be called in the order
|
|
||||||
* they were registered.
|
|
||||||
* @param {BeforeShutdownListener} listener The shutdown listener to register.
|
|
||||||
* @returns {BeforeShutdownListener} Echoes back the supplied `listener`.
|
|
||||||
*/
|
|
||||||
export function beforeShutdown(listener: () => void) {
|
|
||||||
shutdownListeners.push(listener);
|
|
||||||
return listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register shutdown callback that kills the process after `SHUTDOWN_TIMEOUT` milliseconds
|
|
||||||
// This prevents custom shutdown handlers from hanging the process indefinitely
|
|
||||||
processOnce(SHUTDOWN_SIGNALS, forceExitAfter(SHUTDOWN_TIMEOUT));
|
|
||||||
|
|
||||||
// Register process shutdown callback
|
|
||||||
// Will listen to incoming signal events and execute all registered handlers in the stack
|
|
||||||
processOnce(SHUTDOWN_SIGNALS, shutdownHandler);
|
|
Loading…
Reference in New Issue