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.
pull/9/head
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);
}
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();
QString getError() { return m_error; }
public slots:
void shutdown(QUrl url);
protected:
void run();

View File

@ -148,6 +148,7 @@ void TrayIcon::createActions()
connect(m_logAction, SIGNAL(triggered()), this, SLOT(onLog()));
m_quitAction = new QAction(tr("&Shutdown server"), this);
m_quitAction->setEnabled(false);
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))
{
// Emit the signal to shutdown the python server.
emit shutdownSignal(m_appServerUrl);
exit(0);
}
}
void TrayIcon::enableShutdownMenu()
{
if (m_quitAction != NULL)
{
m_quitAction->setEnabled(true);
}
}

View File

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

View File

@ -239,6 +239,7 @@ int main(int argc, char * argv[])
exit(1);
}
QObject::connect(server, SIGNAL(finished()), server, SLOT(deleteLater()));
server->start();
// 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!
trayicon->setAppServerUrl(appServerUrl);
// Enable the shutdown server menu as server started successfully.
trayicon->enableShutdownMenu();
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);
return app.exec();
@ -435,3 +440,44 @@ unsigned long sdbm(unsigned char *str)
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 cleanup();
unsigned long sdbm(unsigned char *str);
bool shutdownServer(QUrl url);
#endif // PGADMIN4_H

View File

@ -10,7 +10,7 @@
"""A blueprint module providing utility functions for the application."""
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 pgadmin.utils import PgAdminModule
from pgadmin.utils.preferences import Preferences
@ -116,3 +116,17 @@ def explain_js():
status=200,
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 ''