Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse server won't shutdown #3718

Closed
cavnit opened this issue Apr 13, 2017 · 27 comments · Fixed by #3786
Closed

Parse server won't shutdown #3718

cavnit opened this issue Apr 13, 2017 · 27 comments · Fixed by #3786
Assignees
Labels
type:bug Impaired feature or lacking behavior that is likely assumed

Comments

@cavnit
Copy link

cavnit commented Apr 13, 2017

Issue Description

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

Steps to reproduce

Start Parse from command line using node app.js
Try Ctrl+C.

Expected Results

Parse/express to showdown

Actual Outcome

No response, app stays running

Environment Setup

  • Server

    • parse-server version (Be specific! Don't say 'latest'.) : 2.3.8
    • Operating System: OS X 10.12.4/ Ubuntu 16.04 LTS
    • Hardware: Macbook Air/ AWS EC2
    • Localhost or remote server? Both
  • Database

    • MongoDB version: 3.4
    • Storage engine: Wired Tiger
    • Hardware: Macbook/ EC2
    • Localhost or remote server? AWS/Local

Logs/Trace

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' +1ms
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

@cavnit
Copy link
Author

cavnit commented Apr 13, 2017

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.

@cavnit cavnit closed this as completed Apr 14, 2017
@flovilmart
Copy link
Contributor

Did you get something else? nodejs don't shutdown if it has open connections.

@cavnit
Copy link
Author

cavnit commented Apr 14, 2017

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

@oallouch
Copy link
Contributor

Same for me. Used to work before recent parse-server update. Maybe it's something with SIGINT not being received.

@oallouch
Copy link
Contributor

Works with 2.3.7

@cavnit cavnit reopened this Apr 18, 2017
@cavnit
Copy link
Author

cavnit commented Apr 18, 2017

@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(); });

@flovilmart
Copy link
Contributor

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

@cavnit
Copy link
Author

cavnit commented Apr 18, 2017

@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.

@flovilmart
Copy link
Contributor

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.

@cavnit
Copy link
Author

cavnit commented Apr 18, 2017

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

@hl4hck
Copy link

hl4hck commented Apr 22, 2017

Same for me.

1 similar comment
@yomybaby
Copy link
Contributor

Same for me.

@jeremypiednoel
Copy link
Contributor

jeremypiednoel commented Apr 25, 2017

same works with 2.3.7

@mmazzarolo
Copy link

same here

@flovilmart
Copy link
Contributor

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();
});

@andrekosak
Copy link

spent 2 hours to understand what went wrong after parse-server version bump to 2.3.8 😞 and to get here

@trylovetom
Copy link
Contributor

same here

@jeremypiednoel
Copy link
Contributor

@trylovetom update to the latest version. ( or at least 2.4.0 -> https://github.com/parse-community/parse-server/releases/tag/2.4.0 )

@trylovetom
Copy link
Contributor

@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.

@flovilmart
Copy link
Contributor

flovilmart commented Nov 14, 2017

@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();

@trylovetom
Copy link
Contributor

@flovilmart How about in the express like this #4343 ?
I don't have any idea.

@flovilmart
Copy link
Contributor

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.

@trylovetom
Copy link
Contributor

trylovetom commented Nov 14, 2017

@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)

@flovilmart
Copy link
Contributor

@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...

@trylovetom
Copy link
Contributor

trylovetom commented Nov 15, 2017

I have rewrote, but it is't work.
@flovilmart
mongo

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!!

mongofix

In postgres adapter I hasn't see it.

@trylovetom
Copy link
Contributor

trylovetom commented Nov 15, 2017

@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

@toddheslin
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:bug Impaired feature or lacking behavior that is likely assumed
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants