Russian Qt Forum
Сентябрь 30, 2024, 02:31 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Перезапуск зависающих приложений/слежение за зависаниями  (Прочитано 5809 раз)
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« : Сентябрь 09, 2013, 11:34 »

Привет. Нужно как то следить за нашими приложениями, которые написаны на Qt (4.8/5.x) под Ubuntu.
Предложения представляют собой автоматизированные рабочие места, которые должны работать в режиме 24/7.
Проблема в том, что иногда они подвисают. Выяснить причины их зависаний пока не могу (может код кривой, а может глюки системы).
Поэтому возникла мысль написать демона, который бы следил за "жизнью" моих приложений, и при отслеживании что оно зависло, выдавало сообещние пользователю с предлодением о
перезапуске.
Как бы это сделать. Приложения многопоточные, используется сеть, графические сцены (довольно сложные с большим количеством объектов на них), интенсивный парсинг JSON и много чего еще.
Что и где подвешивает их уже не прослдеить. Погнятное дело что я их постоянно оптимизирую, довожу до ума, но на предприятии где они сейчас работают нужно как то логировать их поведение.
Думал в каждом потоке завести сигнал, дергать его по таймеру и остлеживать допустимость таймаутов. Если таймаут больше разрешимого, считать что приложение зависло.
Думаю использовать DBus. Но вот почитав доки Qt толком не понял как его использовать. Есть какие то примеры простые что бы понять, как поднять свой сервис и ловить сообщения. Ну и как подключиться к сервису и слать на него события?
Записан
Bepec
Гость
« Ответ #1 : Сентябрь 09, 2013, 13:02 »

Моё видение:
1) радикальное - разобраться с багами и всё исправить.
2) поднять свой сервер (если терминалы в одной сети) и туда по таймеру тумкать пакеты.
3) в принципе тот же сервер, но локальный в виде службы (самый простой вариант).
4) своя реализация типа modbus, но мне терпения не хватило её освоить Веселый

Мне 3 вариант импонирует после первого Улыбающийся
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Сентябрь 09, 2013, 13:27 »

Если приложения Ваши - можно через shared memory (ячейками) + глобальный семафор. При запуске создается семвфор и заводится нитка которая постоянно на нем висит. Когда опрашивающий сигналит, нитка снимается с семафора и пишет в shared block статус приложения (напр "идет расчет"). Получается несложно.
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #3 : Сентябрь 09, 2013, 13:34 »

Так я и рассматриваю создание своей службы, которая будет регистрироваться в dbus.
Приложения, при запуске будут искать нужный сервис, и если таковой имеется будут слать на него какие то пакеты, отвечающие о том, как оно живет и что делает.
Если сервис не запущен, то просто будет работать как и раньше.
А сервис будет следить за приложениями (думаю в качестве ключа будет pid) и логировать в файл.

Вот набросал клиент и сервер согласно примерам ping/pong но клиент не может отсладить регистрацию сервера.
Если сервис уже запущен, то он его видит.

Сервис
Код:
#include <QObject>
#include <QtCore/QObject>
#include <QtDBus/QDBusAbstractAdaptor>
#include <QtDBus/QDBusVariant>

class CListener : public QDBusAbstractAdaptor
{
    Q_OBJECT
    Q_CLASSINFO("D-Bus Interface", "com.mycompany.hangapp.service")
    Q_PROPERTY(QString  message_text    READ    messageText WRITE   setMessageText)

    QString fmessageText;

public:
    explicit CListener(QObject *parent = 0);
    
    QString messageText()   const;
    void    setMessageText(const QString & value);

signals:
    
    void    aboutToQuit();

public slots:

    QDBusVariant    query(const QString & query);
    Q_NOREPLY       void    quit();
    
};
Код:
#include "clistener.h"
#include <QTimer>

CListener::CListener(QObject *parent) :
    QDBusAbstractAdaptor(parent)
{
}

QString CListener::messageText() const
{
    return  fmessageText;
}

void CListener::setMessageText(const QString &value)
{
    fmessageText = value;
}


void CListener::quit()
{
//    QTimer::singleShot(0,QCoreApplication::instance(), SLOT(quit()));
}


QDBusVariant CListener::query(const QString &query)
{
    QString answer = "Answer :"+query;
    return  QDBusVariant(answer);
}
main.cpp
Код:
#include <stdio.h>
#include <QCoreApplication>
#include <QtDBus/QtDBus>

#include "clistener.h"
#include "hangapp_service.h"

using namespace std;

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QObject object;

    printf("Mycompany hangapp service 0.1\n");

    printf("Try to register in D-Bus ");

    CListener   *   listener = new CListener(&object);
    listener->setProperty("message_text","init_value");

    QDBusConnection::sessionBus().registerObject("/",&object);
    if(!QDBusConnection::sessionBus().registerService(SERVICE_NAME))
    {
        printf("failed with reason '%s'\n",qPrintable(QDBusConnection::sessionBus().lastError().message()));
        exit(1);
    }
    else
    {
        printf("ok\nService name is %s\n",SERVICE_NAME);
    }

    return a.exec();
}

А вот клиент
Код:
#include <QMainWindow>
#include <QtDBus/QDBusInterface>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

    QDBusInterface *iface;

    void    checkDBusInterface();
    
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

private slots:
    void    on_pushButton_clicked();

public  slots:
    void    dbus_start_notify(const QString & dbus_name);
    void    dbus_stop_notify(const QString & dbus_name);
};
Код:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtDBus/QtDBus>
#include "hangapp_service.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    iface = NULL;
    connect(QDBusConnection::sessionBus().interface(),SIGNAL(serviceRegistered(QString)),this,SLOT(dbus_start_notify(QString)));
    connect(QDBusConnection::sessionBus().interface(),SIGNAL(serviceUnregistered(QString)),this,SLOT(dbus_stop_notify(QString)));
    checkDBusInterface();
}

void    MainWindow::checkDBusInterface()
{
    iface = new QDBusInterface(SERVICE_NAME, "/", "com.mycompany.hangapp.service",
                               QDBusConnection::sessionBus(), this);
    if (!iface->isValid()) {
        fprintf(stderr, "%s\n",
                qPrintable(QDBusConnection::sessionBus().lastError().message()));
        ui->pushButton->setEnabled(false);
        ui->lineEdit->setEnabled(false);
        ui->listWidget->setEnabled(false);
        delete iface;
        iface = NULL;
    }
    else
    {
        ui->pushButton->setEnabled(true);
        ui->lineEdit->setEnabled(true);
        ui->listWidget->setEnabled(true);
    }
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    QDBusReply<QDBusVariant> reply = iface->call("query", ui->lineEdit->text());
    if(reply.isValid())
        ui->listWidget->addItem(qPrintable(reply.value().variant().toString()));
}

void MainWindow::dbus_start_notify(const QString &dbus_name)
{
    if(dbus_name==SERVICE_NAME)
    {
        checkDBusInterface();
    }
}

void MainWindow::dbus_stop_notify(const QString &dbus_name)
{
    if(dbus_name==SERVICE_NAME)
    {
       ui->pushButton->setEnabled(false);
       ui->lineEdit->setEnabled(false);
       ui->listWidget->setEnabled(false);
       delete iface;
       iface = NULL;
    }
}
main.cpp
Код:
#include "mainwindow.h"
#include <QApplication>
#include <QtDBus>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    if (!QDBusConnection::sessionBus().isConnected())
    {
        fprintf(stderr, "Cannot connect to the D-Bus session bus.\n"
                     "To start it, run:\n"
                     "\teval `dbus-launch --auto-syntax`\n");
        return 1;
    }

    MainWindow w;

    w.show();
    
    return a.exec();
}
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #4 : Сентябрь 09, 2013, 13:36 »

На одной машине обычно запускается одна копия приложения, но одновременно может быть запущено еще 1-2, с разным функционалом но общим ядром. Нужно их различать.
Записан
Alex Custov
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2063


Просмотр профиля
« Ответ #5 : Сентябрь 09, 2013, 13:38 »

стандартная практика - watchdog. Локальный процесс, который по каким-либо условиям определяет, что другой процесс завис и перезапускает его. Например, watchdog открывает локальный сокет и передаёт путь к нему программе, за которой нужно следить. Программа раз в период пишет туда данные, watchdog их читает. Если данных нет - программа зависла, её нужно перезапустить.
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #6 : Сентябрь 09, 2013, 13:53 »

Вот такой ватчдог хочу сделать, только централизированный, который будет собирать данные со всех запущенных моих приложений на машине(машинах в сети в будущем), который по мимо того что будет перезапускать программы, будет писать когда запустилась, когда зависла (какой поток). Т.к. приезжаю на объект не часто (раз в 2-3 месяца), а потом слышу - прога зависла, а когда и почему не знают. Сначала думал что прога сама будет писать логи, но при зависании записать уже ничего не получалось. + Сервер будет слать событе о необходимости обновления клиента на новую версию + какое то дополнительное сопровождение на будущее. Поэтому dbus рассматриваю. Пока все крутится на ubuntu (есть версии под винду, но они сделаны для некритичных участков, т.е. там как бы остлеживания не важны, но не помешали бы).

Какая у меня идея.
Есть прога. Есть потоки. Потоку впринципе можно задать имя через objectName. В каждом потоке (и в гуи тоже) будет таймер, который преиодически будет слать импульсы.
Будет отдельный поток, который все эти импульсы будет перенаправлять уже в DBUS с названием потоков. Что бы можно было более детально понять, какой именно поток подвисает, например сетевой, поток парсинга json, поток гуи и т.д.
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #7 : Сентябрь 09, 2013, 17:07 »

Разобрался с подключением к сервису и отправкой сообщений.
Я так понял что при создании системного процесса нужно записать конфигурацию в /etc/dbus-1/system.d
Вопрос, что туда писать, посмотрел несколько файлов, но не совсем понял как и что туда прописывать.
Ну и скорее всего сервис нужно запускать под рутом? Из среды когда запускаю, выдает ошибку что невозможно зарегестрировать системный процесс.
Записан
Alex Custov
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2063


Просмотр профиля
« Ответ #8 : Сентябрь 09, 2013, 19:44 »

системный сервис должны быть явно разрешён политиками в указанном каталоге. Если политика для сервиса отсутствует или неверна, то сервис не сможет зарегистрироваться. Сессионные сервисы этого не требуют, зачем использовать именно системные?
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #9 : Сентябрь 10, 2013, 11:28 »

Ну хотя бы потому, что пользователь может случайно выйти с системы (было уже не раз). Т.е. что бы прога работала между сессиями.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.048 секунд. Запросов: 23.