250 lines
7.4 KiB
C++
Executable File
250 lines
7.4 KiB
C++
Executable File
/**
|
|
* The ServiceHandler class handles all service related classes and writes the services state to DDS.
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by Hannes Baeuerle, SLSE, 2016-02-15
|
|
*/
|
|
|
|
#include "service_handler.h"
|
|
|
|
#include <QCoreApplication>
|
|
#include <QDateTime>
|
|
#include <QTimer>
|
|
|
|
#include "service.h"
|
|
#include "service_process.h"
|
|
#include "dds_handler.h"
|
|
#include "settings.h"
|
|
#include <LtsUtilsCore/data_modification_enum.h>
|
|
|
|
ServiceManagement::ServiceHandler::ServiceHandler(const std::shared_ptr<DdsHandler> &ddsHandler,
|
|
const std::shared_ptr<LicenceDonator> &licenceDonator)
|
|
: ServiceDonator()
|
|
, Interface::Fts::RestartServiceRequestHandler(ddsHandler->fts())
|
|
, m_heartBeatObserverTimer(new QTimer(this))
|
|
, m_ddsHandler(ddsHandler)
|
|
, m_licenceDonator(licenceDonator)
|
|
, m_logger(getLogger("ServiceHandler"))
|
|
{
|
|
connect(qApp, &QCoreApplication::aboutToQuit,
|
|
this, &ServiceHandler::stopAllServices);
|
|
}
|
|
|
|
ServiceManagement::ServiceHandler::~ServiceHandler()
|
|
{
|
|
qDeleteAll(m_services);
|
|
m_services.clear();
|
|
}
|
|
|
|
bool ServiceManagement::ServiceHandler::init()
|
|
{
|
|
DEBUG_LOG(m_logger) << "Initializing ServiceHandler ...";
|
|
|
|
connect(m_heartBeatObserverTimer, &QTimer::timeout,
|
|
this, &ServiceHandler::onHeartBeatObserverTimerTimeout);
|
|
|
|
|
|
HEARTBEAT_OBSERVER_INTERVAL = Settings::observerIntervall();
|
|
DEBUG_LOG(m_logger) << HEARTBEAT_OBSERVER_INTERVAL;
|
|
m_heartBeatObserverTimer->start(HEARTBEAT_OBSERVER_INTERVAL);
|
|
|
|
DEBUG_LOG(m_logger) << "ServiceHandler successfully initialized.";
|
|
return true;
|
|
}
|
|
|
|
void ServiceManagement::ServiceHandler::addService(ServiceManagement::Service *service)
|
|
{
|
|
service->setParent(this);
|
|
service->setLicenceDonator(m_licenceDonator);
|
|
|
|
connect(service, &Service::newServiceInfo,
|
|
this, &ServiceHandler::onNewServiceInfoFromProc);
|
|
|
|
m_services.append(service);
|
|
}
|
|
|
|
ServiceManagement::ServiceProcess *ServiceManagement::ServiceHandler::getProcess(int serviceId,
|
|
const GroupRequest &groupData)
|
|
{
|
|
Service *service = serviceFromId(serviceId);
|
|
|
|
if (service == nullptr)
|
|
return nullptr;
|
|
|
|
return service->toServiceProcess(groupData);
|
|
}
|
|
|
|
void ServiceManagement::ServiceHandler::onRestartServiceRequest(const rti::core::SampleIdentity &cookie,
|
|
const RestartServiceRequest &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onRestartServiceRequest " << request;
|
|
|
|
ServiceProcess *proc = serviceProcessFromServiceProcId(request.id());
|
|
|
|
Core::FunctionReplyObject ret(request.id());
|
|
if (proc == nullptr)
|
|
{
|
|
INFO_LOG(m_logger) << "Got restart request for non existing service ID "
|
|
<< request.id();
|
|
ret.setStr(tr_lts("dds", "There is no ServiceProcess with id %1")).arg(request.id());
|
|
m_ddsHandler->fts()->restartServiceReply(cookie, ret);
|
|
return;
|
|
}
|
|
|
|
DEBUG_LOG(m_logger) << "Restart request for service "
|
|
<< proc->serviceName()
|
|
<< ", domain "
|
|
<< proc->domainId()
|
|
<< ", exercisePartitionId "
|
|
<< proc->exercisePartitionId()
|
|
<< ", replayPartitionId "
|
|
<< proc->replayPartitionId();
|
|
|
|
proc->restart();
|
|
|
|
m_ddsHandler->fts()->restartServiceReply(cookie, ret);
|
|
}
|
|
|
|
void ServiceManagement::ServiceHandler::stopAllServices()
|
|
{
|
|
INFO_LOG(m_logger) << "Stopping all Services ...";
|
|
|
|
// shutdown async
|
|
for (Service *service : qAsConst(m_services))
|
|
service->stopAllProcs();
|
|
for (Service *service : qAsConst(m_services))
|
|
service->waitForStopped();
|
|
|
|
INFO_LOG(m_logger) << "... all Services stopped :)";
|
|
}
|
|
|
|
void ServiceManagement::ServiceHandler::onNewServiceInfoFromProc(const ServiceInformation &info)
|
|
{
|
|
TRACE_LOG(m_logger) << "Publishing new ServiceInformation: " << info;
|
|
|
|
m_ddsHandler->dts()->publish(info);
|
|
|
|
m_unknownPidsWarned.remove(info.pid());
|
|
}
|
|
|
|
void ServiceManagement::ServiceHandler::onNewServiceInfoFromDds(const Core::CurrentRunningState &data, DataModification type)
|
|
{
|
|
if (type == DataModification::eRemoved)
|
|
return;
|
|
|
|
TRACE_LOG(m_logger) << "Got new CurrentRunningState: " << data;
|
|
|
|
if (!data.pid())
|
|
{
|
|
INFO_LOG(m_logger) << "PID 0 is not allowed.";
|
|
return;
|
|
}
|
|
|
|
ServiceProcess *proc = serviceProcessFromPid(data.pid());
|
|
Core::CurrentRunningState retData = data;
|
|
|
|
if (proc == nullptr)
|
|
{
|
|
bool found = false;
|
|
for (Service *currentService : qAsConst(m_services))
|
|
{
|
|
for (ServiceProcess *currentProc : qAsConst(currentService->allProcs()))
|
|
{
|
|
if (currentProc->remotePid() == data.pid())
|
|
{
|
|
DEBUG_LOG(m_logger) << "Found my prog " << data.pid() << " to "<< currentProc->pid() << " " << currentProc->serviceName();
|
|
proc = currentProc;
|
|
retData.pid() = proc->processId();
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (found)
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
if (proc == nullptr)
|
|
{
|
|
if (!m_unknownPidsWarned.contains(data.pid()))
|
|
{
|
|
ERROR_LOG(m_logger) << "Got CurrentRunningState for non existing process with PID "
|
|
<< data.pid();
|
|
m_unknownPidsWarned += data.pid();
|
|
}
|
|
return;
|
|
}
|
|
|
|
proc->setNewStateFromHeartbeat(retData);
|
|
}
|
|
|
|
ServiceManagement::Service *ServiceManagement::ServiceHandler::serviceFromId(int id)
|
|
{
|
|
for (Service *service : qAsConst(m_services))
|
|
{
|
|
if (service->id() == id)
|
|
return service;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
ServiceManagement::ServiceProcess *ServiceManagement::ServiceHandler::serviceProcessFromPid(qint64 pid)
|
|
{
|
|
for (Service *service : qAsConst(m_services))
|
|
{
|
|
ServiceProcess *result = service->procFromPid(pid);
|
|
if (result)
|
|
return result;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
ServiceManagement::ServiceProcess *ServiceManagement::ServiceHandler::serviceProcessFromServiceProcId(int32_t id)
|
|
{
|
|
for (Service *service : qAsConst(m_services))
|
|
{
|
|
ServiceProcess *result = service->procFromServiceProcId(id);
|
|
if (result)
|
|
return result;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void ServiceManagement::ServiceHandler::onHeartBeatObserverTimerTimeout()
|
|
{
|
|
const qint64 tNow = QDateTime::currentMSecsSinceEpoch();
|
|
const qint64 minHeartbeatAge = tNow - HEARTBEAT_OBSERVER_INTERVAL;
|
|
const qint64 minHeartbeatAgeStartup = tNow - HEARTBEAT_OBSERVER_INTERVAL * 6;
|
|
|
|
for (Service *currentService : qAsConst(m_services))
|
|
{
|
|
for (ServiceProcess *currentProc : qAsConst(currentService->allProcs()))
|
|
{
|
|
// dev mode for this proc -> we're not repsonsible for
|
|
if (currentProc->devMode())
|
|
continue;
|
|
// stopped on operator demand -> we're not responsible for
|
|
if (currentProc->stoppedFromRequest())
|
|
continue;
|
|
// there is something terribly wrong -> ignore
|
|
if (currentProc->failedStartingAttempts() > 3)
|
|
continue;
|
|
|
|
const qint64 minAge = (currentProc->runningState() == Core::RunningState_def::Starting)
|
|
? minHeartbeatAgeStartup
|
|
: minHeartbeatAge;
|
|
|
|
if (currentProc->lastHeartbeatMSec() < minAge)
|
|
{
|
|
WARNING_LOG(m_logger) << "Heartbeat TIMEOUT for " << currentProc->debugInfo()
|
|
<< " - Restarting ..."
|
|
<< " min heartbeat age: " << QDateTime::fromMSecsSinceEpoch(minHeartbeatAge).toString(QStringLiteral("HH:mm:ss"));
|
|
currentProc->addStartAttempt();
|
|
currentProc->restart();
|
|
}
|
|
}
|
|
}
|
|
}
|