Sporadically crashes on Windows when exit. Fixes #3177

1) Shutdown the python server properly.
  2) Disabled "Shutdown server" menu till server is not successfully started.

Initial patch sent by Maxim, modified by Akshay Joshi.
This commit is contained in:
Maxim Zakharov 2018-03-15 13:26:24 +05:30 committed by Akshay Joshi
parent 3c4359270e
commit 54b1a79cb6
7 changed files with 91 additions and 1 deletions

View File

@ -328,3 +328,14 @@ void Server::run()
fclose(cp); fclose(cp);
} }
void Server::shutdown(QUrl url)
{
bool shotdown = shutdownServer(url);
if (!shotdown)
setError(tr("Failed to shutdown application server thread."));
QThread::quit();
QThread::wait();
while(!this->isFinished()){}
}

View File

@ -29,6 +29,9 @@ public:
bool Init(); bool Init();
QString getError() { return m_error; } QString getError() { return m_error; }
public slots:
void shutdown(QUrl url);
protected: protected:
void run(); void run();

View File

@ -148,6 +148,7 @@ void TrayIcon::createActions()
connect(m_logAction, SIGNAL(triggered()), this, SLOT(onLog())); connect(m_logAction, SIGNAL(triggered()), this, SLOT(onLog()));
m_quitAction = new QAction(tr("&Shutdown server"), this); m_quitAction = new QAction(tr("&Shutdown server"), this);
m_quitAction->setEnabled(false);
connect(m_quitAction, SIGNAL(triggered()), this, SLOT(onQuit())); connect(m_quitAction, SIGNAL(triggered()), this, SLOT(onQuit()));
} }
@ -239,6 +240,16 @@ void TrayIcon::onQuit()
{ {
if (QMessageBox::Yes == QMessageBox::question(this, tr("Shutdown server?"), QString(tr("Are you sure you want to shutdown the %1 server?")).arg(PGA_APP_NAME), QMessageBox::Yes | QMessageBox::No)) if (QMessageBox::Yes == QMessageBox::question(this, tr("Shutdown server?"), QString(tr("Are you sure you want to shutdown the %1 server?")).arg(PGA_APP_NAME), QMessageBox::Yes | QMessageBox::No))
{ {
// Emit the signal to shutdown the python server.
emit shutdownSignal(m_appServerUrl);
exit(0); exit(0);
} }
} }
void TrayIcon::enableShutdownMenu()
{
if (m_quitAction != NULL)
{
m_quitAction->setEnabled(true);
}
}

View File

@ -31,6 +31,7 @@ public:
bool Init(); bool Init();
void setAppServerUrl(QString appServerUrl); void setAppServerUrl(QString appServerUrl);
void enableShutdownMenu();
private: private:
void createTrayIcon(); void createTrayIcon();
@ -56,6 +57,9 @@ private slots:
void onConfig(); void onConfig();
void onLog(); void onLog();
void onQuit(); void onQuit();
signals:
void shutdownSignal(QUrl);
}; };
#endif // TRAYICON_H #endif // TRAYICON_H

View File

@ -239,6 +239,7 @@ int main(int argc, char * argv[])
exit(1); exit(1);
} }
QObject::connect(server, SIGNAL(finished()), server, SLOT(deleteLater()));
server->start(); server->start();
// This is a hack to give the server a chance to start and potentially fail. As // This is a hack to give the server a chance to start and potentially fail. As
@ -336,6 +337,8 @@ int main(int argc, char * argv[])
// Go! // Go!
trayicon->setAppServerUrl(appServerUrl); trayicon->setAppServerUrl(appServerUrl);
// Enable the shutdown server menu as server started successfully.
trayicon->enableShutdownMenu();
QString cmd = settings.value("BrowserCommand").toString(); QString cmd = settings.value("BrowserCommand").toString();
@ -355,6 +358,8 @@ int main(int argc, char * argv[])
} }
} }
QObject::connect(trayicon, SIGNAL(shutdownSignal(QUrl)), server, SLOT(shutdown(QUrl)));
splash->finish(NULL); splash->finish(NULL);
return app.exec(); return app.exec();
@ -435,3 +440,44 @@ unsigned long sdbm(unsigned char *str)
return hash; return hash;
} }
// Shutdown the application server
bool shutdownServer(QUrl url)
{
QNetworkAccessManager manager;
QEventLoop loop;
QNetworkReply *reply;
QVariant redirectUrl;
url.setPath("/misc/shutdown");
do
{
reply = manager.get(QNetworkRequest(url));
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
url = redirectUrl.toUrl();
if (!redirectUrl.isNull())
delete reply;
} while (!redirectUrl.isNull());
if (reply->error() != QNetworkReply::NoError)
{
return false;
}
QString response = reply->readAll();
if (response != "SHUTDOWN")
{
qDebug() << "Failed to connect, server response: " << response;
return false;
}
return true;
}

View File

@ -39,5 +39,6 @@ bool PingServer(QUrl url);
void delay(int milliseconds); void delay(int milliseconds);
void cleanup(); void cleanup();
unsigned long sdbm(unsigned char *str); unsigned long sdbm(unsigned char *str);
bool shutdownServer(QUrl url);
#endif // PGADMIN4_H #endif // PGADMIN4_H

View File

@ -10,7 +10,7 @@
"""A blueprint module providing utility functions for the application.""" """A blueprint module providing utility functions for the application."""
import pgadmin.utils.driver as driver import pgadmin.utils.driver as driver
from flask import url_for, render_template, Response from flask import url_for, render_template, Response, request
from flask_babel import gettext from flask_babel import gettext
from pgadmin.utils import PgAdminModule from pgadmin.utils import PgAdminModule
from pgadmin.utils.preferences import Preferences from pgadmin.utils.preferences import Preferences
@ -116,3 +116,17 @@ def explain_js():
status=200, status=200,
mimetype="application/javascript" mimetype="application/javascript"
) )
##########################################################################
# A special URL used to shutdown the server
##########################################################################
@blueprint.route("/shutdown", methods=('get', 'post'))
def shutdown():
if config.SERVER_MODE is not True:
func = request.environ.get('werkzeug.server.shutdown')
if func is None:
raise RuntimeError('Not running with the Werkzeug Server')
func()
return 'SHUTDOWN'
else:
return ''