mirror of
				https://codeberg.org/yeentown/barkey.git
				synced 2025-11-04 07:24:13 +00:00 
			
		
		
		
	refactor(backend): refactor ChartManagementService
This commit is contained in:
		
							parent
							
								
									72253a1029
								
							
						
					
					
						commit
						3010dc207a
					
				
					 2 changed files with 19 additions and 105 deletions
				
			
		| 
						 | 
					@ -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…
	
	Add table
		
		Reference in a new issue