GrpcServer.js

const grpc = require('grpc');

class GrpcServer {
	/**
	 * @classdesc gRPC server will be the entry point to your microservice
	 * @example
	 * const server = new GrpcServer({
	 * 	host: 'localhost',
	 *	port: 5000,
	 *	services: [
	 *		UsersService
	 *	],
	 *	onStart: async () => {
	 *		return database.connect();
	 *	},
	 *	onConnected: () => {
	 *		console.log('Users service is up');
	 *	}
	 * });
	 * server.start(); 
	 * @param {object} config
	 * @param {string} config.host Server host
	 * @param {number} config.port Server port
	 * @param {GrpcService[]} config.services Array of GrpcService derived classes to be exposed
	 * @param {function} [config.onConnected] Function to be executed after server connection
	 * @param {function} [config.onStart] Function to be executed before server start (ex. db connection)
	 * @param {function} [config.onClose] Function to be executed before server shutdown (ex. close db connection)
	*/
	constructor(config) {
		const { host, port, services, onStart, onStarted, onClose } = config;
		this._host = host || 'localhost';
		// eslint-disable-next-line no-undef
		this._port = port || process.env.PORT;
		this._services = services || [];

		this._onStart = onStart;
		this._onStarted = onStarted;
		this._onClose = onClose;
		this._server = new grpc.Server();
	}

	/**
	 * Initialize and register services
	 * @async
	 * @private
	 */
	async _initialize() {
		this._services.forEach((service) => {
			const serviceName = service.constructor.name;
			const descriptor = service.descriptor();
			this._server.addService(descriptor[serviceName].service, service.implementation());
		});
	}

	/**
	 * Get original gRPC server object
	 * @return {object}
	 */
	get server(){
		return this._server;
	}

	/**
	 * Start gRPC server
	 * @async
	 */
	async start() {
		if(typeof(this._onStart) === 'function'){
			await this._onStart();
		}

		await this._initialize();
		this._server.bind(`${this._host}:${this._port}`, grpc.ServerCredentials.createInsecure());
		this._server.start();

		if(typeof(this._onStarted) === 'function'){
			await this._onStarted();
		}
	}

	/**
	 * Shutdown gRPC server
	 * @async
	 */
	async shutdown() {
		await new Promise(async (resolve) => {
			if(typeof(this._onClose) === 'function'){
				await this._onClose();
			}

			this._server.tryShutdown(resolve);
		});
	}
}

module.exports = GrpcServer;