当前位置: 首页 > 科技观察

如何让Nodejs服务器优雅退出

时间:2023-03-15 19:20:41 科技观察

本文转载自微信公众号《编程杂技》,作者theanarkh。转载本文请联系编程杂技公众号。假设我们启动一个服务器并接收一些客户端请求。这时候如果我们要修改一段代码并发布,就需要重启服务器。我们应该做什么?假设我们有以下代码。server.jsconstnet=require('net');constserver=net.createServer().listen(80);client.jsconstnet=require('net');net.connect({port:80})如果我们直接杀死进程,那么库存请求将不会被正常处理。这会影响我们的服务质量。本文介绍如何让nodejs在重启时优雅退出。所谓优雅,就是nodejs进程处理完库存请求后退出。关键是nodejs提供的apiserver.close()。我们来看看这个api的介绍。Stopstheserverfromacceptingnewconnectionsandkeepsexistingconnections.Thisfunctionisasynchronous,theserverisfinallyclosedwhenallconnectionsareendedandtheserveremitsa'close'event.Theoptionalcallbackwillbecalledoncethe'close'eventoccurs.Unlikethatevent,itwillbecalledwithanErrorasitsonlyargumentiftheserverwasnotopenwhenitwasclosed.当我们使用close关闭一个server时,server会等所有的连接关闭后才会触发close事件。Let'slookatthesourcecode.Server.prototype.close=function(cb){//触发回调if(typeofcb==='function'){if(!this._handle){this.once('close',functionclose(){cb(newerrors.Error('ERR_SERVER_NOT_RUNNING'));});}else{this.once('close',cb);}}//关闭底层资源if(this._handle){this._handle.close();this._handle=null;}//判断是否立即触发关闭事件this._emitCloseIfDrained();returnthis;};//服务器下所有连接关闭后触发服务器的关闭事件Server.prototype._emitCloseIfDrained=function(){//另外如果有连接,则不处理this);};Socket.prototype._destroy=function(exception,cb){...//socket所属的serverif(this._server){//server下的连接数减一this._server._connections--;/*是否需要触发服务器的关闭事件,W当所有连接(套接字)关闭时,服务器由关闭事件触发*/if(this._server._emitCloseIfDrained){this._server._emitCloseIfDrained();}}};我们从源码中可以看出,nodejs会先关闭服务器对应的句柄,这样服务器就不会再接收新的请求了。但是服务器并没有触发close事件,而是等到所有连接都断开后才触发close事件。这种通知机制给了我们一些想法。我们可以监听服务端的关闭事件,等待关闭事件触发后再退出进程。constnet=require('net');constserver=net.createServer().listen(80);server.on('close',()=>{process.exit();});//防止进程退出提前挂掉process.on('uncaughtException',()=>{});process.on('SIGINT',function(){server.close();})我们先监听SIGINT信号,当我们使用SIGINT信号在kill进程中,先调用server.close,等待所有连接断开,触发close时退出进程。我们首先启动服务器,然后启动两个客户端。然后按ctrl+c,我们发现此时服务器不会退出,然后我们关闭两个客户端,此时服务器会正??常退出。