forked from Silverfish/proton-bridge
GODT-2038: interrupt gRPC initialisation of bridge process terminates.
This commit is contained in:
committed by
Romain LE JEUNE
parent
a949a113cf
commit
f5148074fd
@ -49,7 +49,7 @@ void QMLBackend::init(GRPCConfig const &serviceConfig)
|
|||||||
this->connectGrpcEvents();
|
this->connectGrpcEvents();
|
||||||
|
|
||||||
QString error;
|
QString error;
|
||||||
if (app().grpc().connectToServer(serviceConfig, error))
|
if (app().grpc().connectToServer(serviceConfig, app().bridgeMonitor(), error))
|
||||||
app().log().info("Connected to backend via gRPC service.");
|
app().log().info("Connected to backend via gRPC service.");
|
||||||
else
|
else
|
||||||
throw Exception(QString("Cannot connectToServer to go backend via gRPC: %1").arg(error));
|
throw Exception(QString("Cannot connectToServer to go backend via gRPC: %1").arg(error));
|
||||||
|
|||||||
@ -288,7 +288,7 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.info(QString("Retrieving gRPC service configuration from '%1'").arg(QDir::toNativeSeparators(grpcServerConfigPath())));
|
log.info(QString("Retrieving gRPC service configuration from '%1'").arg(QDir::toNativeSeparators(grpcServerConfigPath())));
|
||||||
app().backend().init(GRPCClient::waitAndRetrieveServiceConfig(attach ? 0 : grpcServiceConfigWaitDelayMs));
|
app().backend().init(GRPCClient::waitAndRetrieveServiceConfig(attach ? 0 : grpcServiceConfigWaitDelayMs, app().bridgeMonitor()));
|
||||||
if (!attach)
|
if (!attach)
|
||||||
GRPCClient::removeServiceConfigFile();
|
GRPCClient::removeServiceConfigFile();
|
||||||
|
|
||||||
@ -312,7 +312,7 @@ int main(int argc, char *argv[])
|
|||||||
if (bridgeMonitor)
|
if (bridgeMonitor)
|
||||||
{
|
{
|
||||||
const ProcessMonitor::MonitorStatus& status = bridgeMonitor->getStatus();
|
const ProcessMonitor::MonitorStatus& status = bridgeMonitor->getStatus();
|
||||||
if (!status.running && !attach)
|
if (status.ended && !attach)
|
||||||
{
|
{
|
||||||
// ProcessMonitor already stopped meaning we are attached to an orphan Bridge.
|
// ProcessMonitor already stopped meaning we are attached to an orphan Bridge.
|
||||||
// Restart the full process to be sure there is no more bridge orphans
|
// Restart the full process to be sure there is no more bridge orphans
|
||||||
|
|||||||
@ -19,6 +19,7 @@
|
|||||||
#include "GRPCClient.h"
|
#include "GRPCClient.h"
|
||||||
#include "GRPCUtils.h"
|
#include "GRPCUtils.h"
|
||||||
#include "../Exception/Exception.h"
|
#include "../Exception/Exception.h"
|
||||||
|
#include "../ProcessMonitor.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace google::protobuf;
|
using namespace google::protobuf;
|
||||||
@ -56,9 +57,10 @@ void GRPCClient::removeServiceConfigFile()
|
|||||||
|
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
/// \param[in] timeoutMs The timeout in milliseconds
|
/// \param[in] timeoutMs The timeout in milliseconds
|
||||||
|
/// \param[in] serverProcess An optional server process to monitor. If the process it, no need and retry, as connexion cannot be established. Ignored if null.
|
||||||
/// \return The service config.
|
/// \return The service config.
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
GRPCConfig GRPCClient::waitAndRetrieveServiceConfig(qint64 timeoutMs)
|
GRPCConfig GRPCClient::waitAndRetrieveServiceConfig(qint64 timeoutMs, ProcessMonitor *serverProcess)
|
||||||
{
|
{
|
||||||
QString const path = grpcServerConfigPath();
|
QString const path = grpcServerConfigPath();
|
||||||
QFile file(path);
|
QFile file(path);
|
||||||
@ -68,6 +70,9 @@ GRPCConfig GRPCClient::waitAndRetrieveServiceConfig(qint64 timeoutMs)
|
|||||||
bool found = false;
|
bool found = false;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
if (serverProcess && serverProcess->getStatus().ended)
|
||||||
|
throw Exception("Bridge application exited before providing a gRPC service configuration file.");
|
||||||
|
|
||||||
if (file.exists())
|
if (file.exists())
|
||||||
{
|
{
|
||||||
found = true;
|
found = true;
|
||||||
@ -100,9 +105,10 @@ void GRPCClient::setLog(Log *log)
|
|||||||
|
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
/// \param[out] outError If the function returns false, this variable contains a description of the error.
|
/// \param[out] outError If the function returns false, this variable contains a description of the error.
|
||||||
|
/// \param[in] serverProcess An optional server process to monitor. If the process it, no need and retry, as connexion cannot be established. Ignored if null.
|
||||||
/// \return true iff the connection was successful.
|
/// \return true iff the connection was successful.
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
bool GRPCClient::connectToServer(GRPCConfig const &config, QString &outError)
|
bool GRPCClient::connectToServer(GRPCConfig const &config, ProcessMonitor *serverProcess, QString &outError)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -123,6 +129,9 @@ bool GRPCClient::connectToServer(GRPCConfig const &config, QString &outError)
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
if (serverProcess && serverProcess->getStatus().ended)
|
||||||
|
throw Exception("Bridge application ended before gRPC connexion could be established.");
|
||||||
|
|
||||||
this->logInfo(QString("Connection to gRPC server at %1. attempt #%2").arg(address).arg(++i));
|
this->logInfo(QString("Connection to gRPC server at %1. attempt #%2").arg(address).arg(++i));
|
||||||
|
|
||||||
if (channel_->WaitForConnected(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(grpcConnectionRetryDelayMs, GPR_TIMESPAN))))
|
if (channel_->WaitForConnected(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(grpcConnectionRetryDelayMs, GPR_TIMESPAN))))
|
||||||
|
|||||||
@ -50,7 +50,7 @@ class GRPCClient : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public: // static member functions
|
public: // static member functions
|
||||||
static void removeServiceConfigFile(); ///< Delete the service config file.
|
static void removeServiceConfigFile(); ///< Delete the service config file.
|
||||||
static GRPCConfig waitAndRetrieveServiceConfig(qint64 timeoutMs); ///< Wait and retrieve the service configuration.
|
static GRPCConfig waitAndRetrieveServiceConfig(qint64 timeoutMs, class ProcessMonitor *serverProcess); ///< Wait and retrieve the service configuration.
|
||||||
|
|
||||||
public: // member functions.
|
public: // member functions.
|
||||||
GRPCClient() = default; ///< Default constructor.
|
GRPCClient() = default; ///< Default constructor.
|
||||||
@ -60,7 +60,7 @@ public: // member functions.
|
|||||||
GRPCClient &operator=(GRPCClient const &) = delete; ///< Disabled assignment operator.
|
GRPCClient &operator=(GRPCClient const &) = delete; ///< Disabled assignment operator.
|
||||||
GRPCClient &operator=(GRPCClient &&) = delete; ///< Disabled move assignment operator.
|
GRPCClient &operator=(GRPCClient &&) = delete; ///< Disabled move assignment operator.
|
||||||
void setLog(Log *log); ///< Set the log for the client.
|
void setLog(Log *log); ///< Set the log for the client.
|
||||||
bool connectToServer(GRPCConfig const &config, QString &outError); ///< Establish connection to the gRPC server.
|
bool connectToServer(GRPCConfig const &config, class ProcessMonitor *serverProcess, QString &outError); ///< Establish connection to the gRPC server.
|
||||||
|
|
||||||
grpc::Status checkTokens(QString const &clientConfigPath, QString &outReturnedClientToken); ///< Performs a token check.
|
grpc::Status checkTokens(QString const &clientConfigPath, QString &outReturnedClientToken); ///< Performs a token check.
|
||||||
grpc::Status addLogEntry(Log::Level level, QString const &package, QString const &message); ///< Performs the "AddLogEntry" gRPC call.
|
grpc::Status addLogEntry(Log::Level level, QString const &package, QString const &message); ///< Performs the "AddLogEntry" gRPC call.
|
||||||
|
|||||||
@ -33,6 +33,8 @@ ProcessMonitor::ProcessMonitor(QString const &exePath, QStringList const &args,
|
|||||||
: Worker(parent)
|
: Worker(parent)
|
||||||
, exePath_(exePath)
|
, exePath_(exePath)
|
||||||
, args_(args)
|
, args_(args)
|
||||||
|
, out_(stdout)
|
||||||
|
, err_(stderr)
|
||||||
{
|
{
|
||||||
QFileInfo fileInfo(exePath);
|
QFileInfo fileInfo(exePath);
|
||||||
if (!fileInfo.exists())
|
if (!fileInfo.exists())
|
||||||
@ -42,6 +44,26 @@ ProcessMonitor::ProcessMonitor(QString const &exePath, QStringList const &args,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
//
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
void ProcessMonitor::forwardProcessOutput(QProcess &p) {
|
||||||
|
QByteArray array = p.readAllStandardError();
|
||||||
|
if (!array.isEmpty())
|
||||||
|
{
|
||||||
|
err_ << array;
|
||||||
|
err_.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
array = p.readAllStandardOutput();
|
||||||
|
if (!array.isEmpty())
|
||||||
|
{
|
||||||
|
out_ << array;
|
||||||
|
out_.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
//
|
//
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
@ -49,35 +71,31 @@ void ProcessMonitor::run()
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&statusMutex_);
|
||||||
|
status_.ended = false;
|
||||||
|
status_.pid = -1;
|
||||||
|
}
|
||||||
|
|
||||||
emit started();
|
emit started();
|
||||||
|
|
||||||
QProcess p;
|
QProcess p;
|
||||||
p.start(exePath_, args_);
|
p.start(exePath_, args_);
|
||||||
p.waitForStarted();
|
p.waitForStarted();
|
||||||
|
|
||||||
status_.running = true;
|
|
||||||
status_.pid = p.processId();
|
|
||||||
|
|
||||||
QTextStream out(stdout), err(stderr);
|
|
||||||
QByteArray array;
|
|
||||||
while (!p.waitForFinished(100))
|
|
||||||
{
|
{
|
||||||
array = p.readAllStandardError();
|
QMutexLocker locker(&statusMutex_);
|
||||||
if (!array.isEmpty())
|
status_.pid = p.processId();
|
||||||
{
|
|
||||||
err << array;
|
|
||||||
err.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
array = p.readAllStandardOutput();
|
|
||||||
if (!array.isEmpty())
|
|
||||||
{
|
|
||||||
out << array;
|
|
||||||
out.flush();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
status_.running = false;
|
while (!p.waitForFinished(100))
|
||||||
|
{
|
||||||
|
this->forwardProcessOutput(p);
|
||||||
|
}
|
||||||
|
this->forwardProcessOutput(p);
|
||||||
|
|
||||||
|
QMutexLocker locker(&statusMutex_);
|
||||||
|
status_.ended = true;
|
||||||
status_.returnCode = p.exitCode();
|
status_.returnCode = p.exitCode();
|
||||||
|
|
||||||
emit processExited(status_.returnCode);
|
emit processExited(status_.returnCode);
|
||||||
@ -93,8 +111,9 @@ void ProcessMonitor::run()
|
|||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
/// \return status of the monitored process
|
/// \return status of the monitored process
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
const ProcessMonitor::MonitorStatus &ProcessMonitor::getStatus()
|
const ProcessMonitor::MonitorStatus ProcessMonitor::getStatus()
|
||||||
{
|
{
|
||||||
|
QMutexLocker locker(&statusMutex_);
|
||||||
return status_;
|
return status_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -36,7 +36,7 @@ Q_OBJECT
|
|||||||
public: // static member functions
|
public: // static member functions
|
||||||
struct MonitorStatus
|
struct MonitorStatus
|
||||||
{
|
{
|
||||||
bool running = false;
|
bool ended = false;
|
||||||
int returnCode = 0;
|
int returnCode = 0;
|
||||||
qint64 pid = 0;
|
qint64 pid = 0;
|
||||||
};
|
};
|
||||||
@ -49,15 +49,21 @@ public: // member functions.
|
|||||||
ProcessMonitor &operator=(ProcessMonitor const &) = delete; ///< Disabled assignment operator.
|
ProcessMonitor &operator=(ProcessMonitor const &) = delete; ///< Disabled assignment operator.
|
||||||
ProcessMonitor &operator=(ProcessMonitor &&) = delete; ///< Disabled move assignment operator.
|
ProcessMonitor &operator=(ProcessMonitor &&) = delete; ///< Disabled move assignment operator.
|
||||||
void run() override; ///< Run the worker.
|
void run() override; ///< Run the worker.
|
||||||
MonitorStatus const &getStatus();
|
MonitorStatus const getStatus(); ///< Retrieve the current status of the process.
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void processExited(int code); ///< Slot for the exiting of the process.
|
void processExited(int code); ///< Slot for the exiting of the process.
|
||||||
|
|
||||||
|
private: // member functions
|
||||||
|
void forwardProcessOutput(QProcess &p); ///< Forward the standard output and error from the process to this application standard output and error.
|
||||||
|
|
||||||
private: // data members
|
private: // data members
|
||||||
|
QMutex statusMutex_; ///< The status mutex.
|
||||||
QString const exePath_; ///< The path to the executable.
|
QString const exePath_; ///< The path to the executable.
|
||||||
QStringList args_; ///< arguments to be passed to the brigde.
|
QStringList args_; ///< arguments to be passed to the brigde.
|
||||||
MonitorStatus status_; ///< Status of the monitoring.
|
MonitorStatus status_; ///< Status of the monitoring.
|
||||||
|
QTextStream out_; ///< The standard output stream.
|
||||||
|
QTextStream err_; ///< The standard error stream.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user