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