Running parse in express app, basic configuration on MacBook Air start use node app.js, starts up fine.
Do Ctrl+C to stop, parse does not stop
Start Parse from command line using node app.js
Try Ctrl+C.
Parse/express to showdown
No response, app stays running
Server
Database
express:application set "x-powered-by" to true +0ms
express:application set "etag" to 'weak' +5ms
express:application set "etag fn" to [Function: wetag] +3ms
express:application set "env" to 'development' +0ms
express:application set "query parser" to 'extended' +0ms
express:application set "query parser fn" to [Function: parseExtendedQueryString] +1ms
express:application set "subdomain offset" to 2 +0ms
express:application set "trust proxy" to false +0ms
express:application set "trust proxy fn" to [Function: trustNone] +1ms
express:application booting in development mode +0ms
express:application set "view" to [Function: View] +0ms
express:application set "views" to '/Users/craig/Code/webApps/####/views' +1ms
express:application set "jsonp callback name" to 'callback' +0ms
express:router:route new '/files/:appId/:filename' +1ms
express:router:layer new '/files/:appId/:filename' +1ms
express:router:route get '/files/:appId/:filename' +2ms
express:router:layer new '/' +0ms
express:router:route new '/files' +1ms
express:router:layer new '/files' +0ms
express:router:route post '/files' +1ms
express:router:layer new '/' +0ms
express:router:route new '/files/:filename' +24ms
express:router:layer new '/files/:filename' +0ms
express:router:route post '/files/:filename' +1ms
express:router:layer new '/' +0ms
express:router:route post '/files/:filename' +0ms
express:router:layer new '/' +0ms
express:router:route post '/files/:filename' +0ms
express:router:layer new '/' +1ms
express:router:route post '/files/:filename' +0ms
express:router:layer new '/' +0ms
express:router:route new '/files/:filename' +0ms
express:router:layer new '/files/:filename' +0ms
express:router:route delete '/files/:filename' +1ms
express:router:layer new '/' +0ms
express:router:route delete '/files/:filename' +0ms
express:router:layer new '/' +0ms
express:router:route delete '/files/:filename' +0ms
express:router:layer new '/' +0ms
express:router:route delete '/files/:filename' +0ms
express:router:layer new '/' +0ms
express:router use '/' query +1ms
express:router:layer new '/' +0ms
express:router use '/' expressInit +1ms
express:router:layer new '/' +0ms
express:router use '/' allowCrossDomain +0ms
express:router:layer new '/' +0ms
express:router use '/' router +0ms
express:router:layer new '/' +0ms
express:router use '/health'
express:router:layer new '/health' +1ms
express:router:layer new '/apps/:appId/verify_email' +4ms
express:router:layer new '/apps/choose_password' +1ms
express:router:layer new '/apps/:appId/request_password_reset' +0ms
express:router:layer new '/apps/:appId/request_password_reset' +0ms
express:router use '/apps' serveStatic +1ms
express:router:layer new '/apps' +0ms
express:router:route new '/apps/:appId/verify_email' +1ms
express:router:layer new '/apps/:appId/verify_email' +1ms
express:router:route get '/apps/:appId/verify_email' +0ms
express:router:layer new '/' +0ms
express:router:route new '/apps/choose_password' +0ms
express:router:layer new '/apps/choose_password' +0ms
express:router:route get '/apps/choose_password' +0ms
express:router:layer new '/' +1ms
express:router:route new '/apps/:appId/request_password_reset' +0ms
express:router:layer new '/apps/:appId/request_password_reset' +0ms
express:router:route post '/apps/:appId/request_password_reset' +0ms
express:router:layer new '/' +0ms
express:router:route new '/apps/:appId/request_password_reset' +0ms
express:router:layer new '/apps/:appId/request_password_reset' +0ms
express:router:route get '/apps/:appId/request_password_reset' +1ms
express:router:layer new '/' +0ms
express:router use '/' router +0ms
express:router:layer new '/' +0ms
express:router use '/' urlencodedParser +0ms
express:router:layer new '/' +0ms
express:router use '/' router +0ms
express:router:layer new '/' +1ms
express:router use '/' jsonParser +2ms
express:router:layer new '/' +1ms
express:router use '/' allowCrossDomain +0ms
express:router:layer new '/' +0ms
express:router use '/' allowMethodOverride +0ms
express:router:layer new '/' +0ms
express:router use '/' handleParseHeaders +0ms
express:router:layer new '/' +0ms
express:router:layer new '/classes/:className' +1ms
express:router:layer new '/classes/:className/:objectId' +0ms
express:router:layer new '/classes/:className' +0ms
express:router:layer new '/classes/:className/:objectId' +0ms
express:router:layer new '/classes/:className/:objectId' +0ms
express:router:layer new '/users' +1ms
express:router:layer new '/users' +0ms
express:router:layer new '/users/me' +0ms
express:router:layer new '/users/:objectId' +0ms
express:router:layer new '/users/:objectId' +0ms
express:router:layer new '/users/:objectId' +0ms
express:router:layer new '/login' +1ms
express:router:layer new '/logout' +0ms
express:router:layer new '/requestPasswordReset' +0ms
express:router:layer new '/verificationEmailRequest' +0ms
express:router:layer new '/sessions/me' +0ms
express:router:layer new '/sessions' +1ms
express:router:layer new '/sessions/:objectId' +0ms
express:router:layer new '/sessions' +0ms
express:router:layer new '/sessions/:objectId' +0ms
express:router:layer new '/sessions/:objectId' +0ms
express:router:layer new '/upgradeToRevocableSession' +1ms
express:router:layer new '/roles' +1ms
express:router:layer new '/roles/:objectId' +1ms
express:router:layer new '/roles' +1ms
express:router:layer new '/roles/:objectId' +1ms
express:router:layer new '/roles/:objectId' +0ms
express:router:layer new '/events/AppOpened' +1ms
express:router:layer new '/events/:eventName' +0ms
express:router:layer new '/installations' +1ms
express:router:layer new '/installations/:objectId' +1ms
express:router:layer new '/installations' +0ms
express:router:layer new '/installations/:objectId' +0ms
express:router:layer new '/installations/:objectId' +0ms
express:router:layer new '/functions/:functionName' +1ms
express:router:layer new '/jobs/:jobName' +1ms
express:router:layer new '/jobs' +1ms
express:router:layer new '/schemas' +1ms
express:router:layer new '/schemas/:className' +0ms
express:router:layer new '/schemas' +1ms
express:router:layer new '/schemas/:className' +0ms
express:router:layer new '/schemas/:className' +0ms
express:router:layer new '/schemas/:className' +1ms
express:router:layer new '/push' +1ms
express:router:layer new '/scriptlog' +0ms
express:router:layer new '/validate_purchase' +4ms
express:router:layer new '/serverInfo' +1ms
express:router:layer new '/config' +1ms
express:router:layer new '/config' +0ms
express:router:layer new '/purge/:className' +1ms
express:router:layer new '/hooks/functions' +0ms
express:router:layer new '/hooks/triggers' +0ms
express:router:layer new '/hooks/functions/:functionName' +1ms
express:router:layer new '/hooks/triggers/:className/:triggerName' +0ms
express:router:layer new '/hooks/functions' +0ms
express:router:layer new '/hooks/triggers' +0ms
express:router:layer new '/hooks/functions/:functionName' +1ms
express:router:layer new '/hooks/triggers/:className/:triggerName' +0ms
express:router:layer new '/cloud_code/jobs' +0ms
express:router:layer new '/batch' +1ms
express:router:route new '/classes/:className' +0ms
express:router:layer new '/classes/:className' +0ms
express:router:route get '/classes/:className' +0ms
express:router:layer new '/' +1ms
express:router:route new '/classes/:className/:objectId' +0ms
express:router:layer new '/classes/:className/:objectId' +0ms
express:router:route get '/classes/:className/:objectId' +0ms
express:router:layer new '/' +1ms
express:router:route new '/classes/:className' +0ms
express:router:layer new '/classes/:className' +0ms
express:router:route post '/classes/:className' +0ms
express:router:layer new '/' +0ms
express:router:route new '/classes/:className/:objectId' +1ms
express:router:layer new '/classes/:className/:objectId' +0ms
express:router:route put '/classes/:className/:objectId' +0ms
express:router:layer new '/' +0ms
express:router:route new '/classes/:className/:objectId' +0ms
express:router:layer new '/classes/:className/:objectId' +0ms
express:router:route delete '/classes/:className/:objectId' +1ms
express:router:layer new '/' +0ms
express:router:route new '/users' +0ms
express:router:layer new '/users' +0ms
express:router:route get '/users' +0ms
express:router:layer new '/' +0ms
express:router:route new '/users' +0ms
express:router:layer new '/users' +1ms
express:router:route post '/users' +0ms
express:router:layer new '/' +0ms
express:router:route new '/users/me' +0ms
express:router:layer new '/users/me' +0ms
express:router:route get '/users/me' +0ms
express:router:layer new '/' +0ms
express:router:route new '/users/:objectId' +1ms
express:router:layer new '/users/:objectId' +0ms
express:router:route get '/users/:objectId' +0ms
express:router:layer new '/' +0ms
express:router:route new '/users/:objectId' +0ms
express:router:layer new '/users/:objectId' +0ms
express:router:route put '/users/:objectId' +0ms
express:router:layer new '/' +1ms
express:router:route new '/users/:objectId' +0ms
express:router:layer new '/users/:objectId' +0ms
express:router:route delete '/users/:objectId' +0ms
express:router:layer new '/' +0ms
express:router:route new '/login' +1ms
express:router:layer new '/login' +0ms
express:router:route get '/login' +0ms
express:router:layer new '/' +0ms
express:router:route new '/logout' +2ms
express:router:layer new '/logout' +0ms
express:router:route post '/logout' +0ms
express:router:layer new '/' +1ms
express:router:route new '/requestPasswordReset' +0ms
express:router:layer new '/requestPasswordReset' +0ms
express:router:route post '/requestPasswordReset' +0ms
express:router:layer new '/' +0ms
express:router:route new '/verificationEmailRequest' +0ms
express:router:layer new '/verificationEmailRequest' +1ms
express:router:route post '/verificationEmailRequest' +0ms
express:router:layer new '/' +0ms
express:router:route new '/sessions/me' +0ms
express:router:layer new '/sessions/me' +0ms
express:router:route get '/sessions/me' +0ms
express:router:layer new '/' +1ms
express:router:route new '/sessions' +0ms
express:router:layer new '/sessions' +16ms
express:router:route get '/sessions' +0ms
express:router:layer new '/' +0ms
express:router:route new '/sessions/:objectId' +0ms
express:router:layer new '/sessions/:objectId' +0ms
express:router:route get '/sessions/:objectId' +0ms
express:router:layer new '/' +0ms
express:router:route new '/sessions' +1ms
express:router:layer new '/sessions' +0ms
express:router:route post '/sessions' +0ms
express:router:layer new '/' +0ms
express:router:route new '/sessions/:objectId' +1ms
express:router:layer new '/sessions/:objectId' +0ms
express:router:route put '/sessions/:objectId' +0ms
express:router:layer new '/' +0ms
express:router:route new '/sessions/:objectId' +1ms
express:router:layer new '/sessions/:objectId' +0ms
express:router:route delete '/sessions/:objectId' +0ms
express:router:layer new '/' +0ms
express:router:route new '/upgradeToRevocableSession' +0ms
express:router:layer new '/upgradeToRevocableSession' +0ms
express:router:route post '/upgradeToRevocableSession' +0ms
express:router:layer new '/' +1ms
express:router:route new '/roles' +0ms
express:router:layer new '/roles' +0ms
express:router:route get '/roles' +1ms
express:router:layer new '/' +0ms
express:router:route new '/roles/:objectId' +0ms
express:router:layer new '/roles/:objectId' +0ms
express:router:route get '/roles/:objectId' +0ms
express:router:layer new '/' +0ms
express:router:route new '/roles' +1ms
express:router:layer new '/roles' +0ms
express:router:route post '/roles' +0ms
express:router:layer new '/' +0ms
express:router:route new '/roles/:objectId' +0ms
express:router:layer new '/roles/:objectId' +0ms
express:router:route put '/roles/:objectId' +1ms
express:router:layer new '/' +0ms
express:router:route new '/roles/:objectId' +0ms
express:router:layer new '/roles/:objectId' +0ms
express:router:route delete '/roles/:objectId' +0ms
express:router:layer new '/' +0ms
express:router:route new '/events/AppOpened' +1ms
express:router:layer new '/events/AppOpened' +0ms
express:router:route post '/events/AppOpened' +0ms
express:router:layer new '/' +0ms
express:router:route new '/events/:eventName' +1ms
express:router:layer new '/events/:eventName' +0ms
express:router:route post '/events/:eventName' +0ms
express:router:layer new '/' +0ms
express:router:route new '/installations' +2ms
express:router:layer new '/installations' +1ms
express:router:route get '/installations' +0ms
express:router:layer new '/' +0ms
express:router:route new '/installations/:objectId' +0ms
express:router:layer new '/installations/:objectId' +1ms
express:router:route get '/installations/:objectId' +0ms
express:router:layer new '/' +0ms
express:router:route new '/installations' +0ms
express:router:layer new '/installations' +0ms
express:router:route post '/installations' +0ms
express:router:layer new '/' +0ms
express:router:route new '/installations/:objectId' +0ms
express:router:layer new '/installations/:objectId' +1ms
express:router:route put '/installations/:objectId' +0ms
express:router:layer new '/' +0ms
express:router:route new '/installations/:objectId' +0ms
express:router:layer new '/installations/:objectId' +0ms
express:router:route delete '/installations/:objectId' +0ms
express:router:layer new '/' +0ms
express:router:route new '/functions/:functionName' +1ms
express:router:layer new '/functions/:functionName' +0ms
express:router:route post '/functions/:functionName' +1ms
express:router:layer new '/' +0ms
express:router:route new '/jobs/:jobName' +0ms
express:router:layer new '/jobs/:jobName' +1ms
express:router:route post '/jobs/:jobName' +0ms
express:router:layer new '/' +0ms
express:router:route new '/jobs' +1ms
express:router:layer new '/jobs' +0ms
express:router:route post '/jobs' +0ms
express:router:layer new '/' +0ms
express:router:route new '/schemas' +1ms
express:router:layer new '/schemas' +0ms
express:router:route get '/schemas' +0ms
express:router:layer new '/' +0ms
express:router:route new '/schemas/:className' +1ms
express:router:layer new '/schemas/:className' +0ms
express:router:route get '/schemas/:className' +1ms
express:router:layer new '/' +0ms
express:router:route new '/schemas' +1ms
express:router:layer new '/schemas' +0ms
express:router:route post '/schemas' +0ms
express:router:layer new '/' +1ms
express:router:route new '/schemas/:className' +0ms
express:router:layer new '/schemas/:className' +0ms
express:router:route post '/schemas/:className' +1ms
express:router:layer new '/' +0ms
express:router:route new '/schemas/:className' +1ms
express:router:layer new '/schemas/:className' +0ms
express:router:route put '/schemas/:className' +1ms
express:router:layer new '/' +0ms
express:router:route new '/schemas/:className' +0ms
express:router:layer new '/schemas/:className' +1ms
express:router:route delete '/schemas/:className' +0ms
express:router:layer new '/' +0ms
express:router:route new '/push' +0ms
express:router:layer new '/push' +1ms
express:router:route post '/push' +0ms
express:router:layer new '/' +0ms
express:router:route new '/scriptlog' +0ms
express:router:layer new '/scriptlog' +0ms
express:router:route get '/scriptlog' +1ms
express:router:layer new '/' +0ms
express:router:route new '/validate_purchase' +0ms
express:router:layer new '/validate_purchase' +0ms
express:router:route post '/validate_purchase' +0ms
express:router:layer new '/' +1ms
express:router:route new '/serverInfo' +0ms
express:router:layer new '/serverInfo' +0ms
express:router:route get '/serverInfo' +0ms
express:router:layer new '/' +1ms
express:router:route new '/config' +0ms
express:router:layer new '/config' +0ms
express:router:route get '/config' +0ms
express:router:layer new '/' +0ms
express:router:route new '/config' +0ms
express:router:layer new '/config' +1ms
express:router:route put '/config' +0ms
express:router:layer new '/' +0ms
express:router:route new '/purge/:className' +0ms
express:router:layer new '/purge/:className' +0ms
express:router:route delete '/purge/:className' +0ms
express:router:layer new '/' +0ms
express:router:route new '/hooks/functions' +1ms
express:router:layer new '/hooks/functions' +0ms
express:router:route get '/hooks/functions' +0ms
express:router:layer new '/' +0ms
express:router:route new '/hooks/triggers' +0ms
express:router:layer new '/hooks/triggers' +0ms
express:router:route get '/hooks/triggers' +1ms
express:router:layer new '/' +0ms
express:router:route new '/hooks/functions/:functionName' +0ms
express:router:layer new '/hooks/functions/:functionName' +0ms
express:router:route get '/hooks/functions/:functionName' +0ms
express:router:layer new '/' +0ms
express:router:route new '/hooks/triggers/:className/:triggerName' +0ms
express:router:layer new '/hooks/triggers/:className/:triggerName' +1ms
express:router:route get '/hooks/triggers/:className/:triggerName' +0ms
express:router:layer new '/' +0ms
express:router:route new '/hooks/functions' +0ms
express:router:layer new '/hooks/functions' +0ms
express:router:route post '/hooks/functions' +1ms
express:router:layer new '/' +0ms
express:router:route new '/hooks/triggers' +0ms
express:router:layer new '/hooks/triggers' +0ms
express:router:route post '/hooks/triggers' +0ms
express:router:layer new '/' +0ms
express:router:route new '/hooks/functions/:functionName' +1ms
express:router:layer new '/hooks/functions/:functionName' +0ms
express:router:route put '/hooks/functions/:functionName' +0ms
express:router:layer new '/' +0ms
express:router:route new '/hooks/triggers/:className/:triggerName' +1ms
express:router:layer new '/hooks/triggers/:className/:triggerName' +0ms
express:router:route put '/hooks/triggers/:className/:triggerName' +0ms
express:router:layer new '/' +0ms
express:router:route new '/cloud_code/jobs' +0ms
express:router:layer new '/cloud_code/jobs' +0ms
express:router:route get '/cloud_code/jobs' +1ms
express:router:layer new '/' +0ms
express:router:route new '/batch' +0ms
express:router:layer new '/batch' +0ms
express:router:route post '/batch' +0ms
express:router:layer new '/' +1ms
express:router use '/' router +0ms
express:router:layer new '/' +0ms
express:router use '/' handleParseErrors +0ms
express:router:layer new '/' +0ms
express:application set "x-powered-by" to true +1ms
express:application set "etag" to 'weak' +0ms
express:application set "etag fn" to [Function: wetag] +0ms
express:application set "env" to 'development' +2ms
express:application set "query parser" to 'extended' +1ms
express:application set "query parser fn" to [Function: parseExtendedQueryString] +0ms
express:application set "subdomain offset" to 2 +1ms
express:application set "trust proxy" to false +0ms
express:application set "trust proxy fn" to [Function: trustNone] +0ms
express:application booting in development mode +0ms
express:application set "view" to [Function: View] +1ms
express:application set "views" to '/Users/craig/Code/webApps/#####/views' +0ms
express:application set "jsonp callback name" to 'callback' +0ms
express:application set "port" to '3000' +0ms
express:router use '/' query +0ms
express:router:layer new '/' +1ms
express:router use '/' expressInit +0ms
express:router:layer new '/' +0ms
express:application .use app under / +0ms
express:router use '/' mounted_app +0ms
express:router:layer new '/' +1ms
✓ App is running at http://localhost:3000 in development mode
Press CTRL-C to stop
^C^C^C^C^C^C^C^C^C^C^C^C^C^C
If I comment out the following that was added in #3706
process.on('SIGTERM', this.handleShutdown(this));
process.on('SIGINT', this.handleShutdown(this));
The process shuts down immediately.
I gather it something in the shutdown handler for mongo, but to be honest, I am very new to the Parse code, but I will go through and see if I can nail down the issue more.
Did you get something else? nodejs don't shutdown if it has open connections.
Hi @flovilmart,
I can't seem to see where it is hanging so I have added process.exit() in the express app instead, which forces the shutdown. When I have time I will take a look and see what connections could possibly be open, as the mongo connections seem to be closing.
Thanks
Same for me. Used to work before recent parse-server update. Maybe it's something with SIGINT not being received.
Works with 2.3.7
@oallouch I am running parse in an express app, so I have just added the following after app.listen as a temp workaround until I get a chance to take a proper look.
process.on('SIGINT', () => {
console.log('Shutting Down Parse');
process.exit();
});
process.on('SIGTERM', () => {
console.log('Shutting Down Parse');
process.exit();
});
You should probably close all pending connections and the server if you want to implement properly graceful shutdown. Have a look at how it's done in the CLI module of parse-server
@flovilmart, I will look at adding that to the express side, but there definitely seems to be an issue in 2.3.8, even in development mode. If you run node app.js and then immediately hit Ctrl+C the server cannot be shutdown.
Can you share the command you're running?
We've added a signal handler for mongodb as between 2.3.7 and 2.3.8, the server refused to die in certain cases. Also, we need to have a proper graceful shutdown as some adapters require to cleanup their subscriptions (gcloud-pubsub) before the process exits.
I am just running:
node app.js
I have created a very basic parse/express app, and it won't shutdown either. I have attached it.
testparse.zip
Same for me.
Same for me.
same works with 2.3.7
same here
I isolated the issue, related with graceful shutdowns, I'll work on a fix for the next release.
In the meantime, you can register a SIGINT handler to exit the process:
process.on('SIGINT', function() {
console.log('SIGINT');
process.exit();
});
spent 2 hours to understand what went wrong after parse-server version bump to 2.3.8 😞 and to get here
same here
@trylovetom update to the latest version. ( or at least 2.4.0 -> https://github.com/parse-community/parse-server/releases/tag/2.4.0 )
@jeremypiednoel I have updated to the latest version. I use the latest version in ny unit test. When I closed the express server, parse doesn't close either. Maybe is same issue.
@trylovetom did you try calling handleShutdown on parseServer ?
we've recently introduced: ParseServer.start(options, callback)
You can use it this way (as in the cli.js)
const options = {
appId: ...
masterKey: ...
port: ...
};
const server = ParseServer.start(options, () => {
logOptions();
console.log('');
console.log('[' + process.pid + '] parse-server running on ' + options.serverURL);
});
// *on shutdown
server.handleShutdown();
@flovilmart How about in the express like this #4343 ?
I don't have any idea.
see
import ParseServer from 'parse-server'
const parseServer = new ParseServer({ // create parse server
appId: 'Parse',
databaseURI: 'mongodb://localhost:27017/parse',
masterKey: 'Key',
serverURL: 'http://localhost:3000/'
})
app.use('/', parseServer.app) // mount it
function shutdown () {
server.forceShutdown((err) => { // use force shutdown, it not only close http server also kill the socket connection
if (err) {
console.log(err)
}
parseServer.handleShutdown();
console.log('Closed')
})
}
let me know.
@flovilmart Lastest Updated
import http from 'http'
import express from 'express'
import { ParseServer } from 'parse-server'
const app = express() // create express app
const server = require('http-shutdown')(http.createServer(app)) // use force shutdown
const parseServer = new ParseServer({ // create parse server
appId: 'Parse',
databaseURI: 'mongodb://localhost:27017/parse',
masterKey: 'Key',
serverURL: 'http://localhost:3000/'
})
app.use('/', parseServer) // mount it
function create () { // listen on 3000 port
server.listen(3000, () => {
console.log('Awaken On Port 3000')
shutdown() // when server on raise, close it
})
}
function shutdown () {
parseServer.handleShutdown() // use parse handle shutdown function
server.forceShutdown((err) => { // use force shutdown, it not only close http server also kill the socket connection
if (err) {
console.log(err)
}
console.log('Closed')
})
}
create() // start the test
Output
Awaken On Port 3000
/Users/zhangziyan/Documents/Work/ParseYourMom/node_modules/parse-server/lib/ParseServer.js:260
throw err;
^
TypeError: parseServer.handleShutdown is not a function
at /Users/zhangziyan/Documents/Work/ParseYourMom/src/test.js:30:17
at /Users/zhangziyan/Documents/Work/ParseYourMom/node_modules/http-shutdown/index.js:53:39
at _combinedTickCallback (internal/process/next_tick.js:131:7)
at process._tickDomainCallback (internal/process/next_tick.js:218:9)
at Function.Module.runMain (module.js:655:11)
at Object.<anonymous> (/usr/local/lib/node_modules/babel-cli/lib/_babel-node.js:154:22)
at Module._compile (module.js:612:30)
at Object.Module._extensions..js (module.js:623:10)
at Module.load (module.js:531:32)
at tryModuleLoad (module.js:494:12)
@trylovetom, you’re using the wrong interfaces, double check the example I provided, you’ll notice the import is different, as well as using parseServer.app etc...
I have rewrote, but it is't work.
@flovilmart

After I survey the shutdown code, I found handleShutdown only be implemented in monogo adapter.
It is't work. When I call this handleShutdown function, this.databse get undefined. Because mongo adapter doesn't create a connection yet.
Then, I wait a 3 second, and close it again. It works the mongo db connection!!

In postgres adapter I hasn't see it.
@flovilmart
I think we need a function which shutdown the parse itself, express app, and all connections between http server.
And so dose the postgres adapter. #4352
In case anyone drops in here from searching around, I had the same issue using a standalone Parse server without express. Only Parse running from node_modules/.bin/parse-server. I had the same problem where the server wouldn't shut down. There were two problems:
1) In one of my cloud functions I was connecting to a Redis server but wasn't closing the connection before the end of the cloud function.
2) I was using a cron via Node Cron in my main.js which wasn't closing the server down on ctrl + c. I changed this over to Cron (actually might not have needed to do this) but assigned the cron to a variable and closed it on SIGINT.
On the last option, I actually had a few crons running. I just did this:
const jobs = [
new CronJob('10 * * * *', () => Parse.Cloud.run('Sync REX Products', { days: 1 }), null, true, 'Australia/Sydney'),
new CronJob('0,15,30,45 * * * *', () => Parse.Cloud.run('Sync REX Stock Levels'), null, true, 'Australia/Sydney')
]
process.on('SIGINT', () => {
jobs.forEach(job => job.stop())
})
Hopefully this helps anyone who comes across the same problem.
Most helpful comment
I isolated the issue, related with graceful shutdowns, I'll work on a fix for the next release.
In the meantime, you can register a SIGINT handler to exit the process: