Add retry logic to EventHandler for FETCH_TRANSACTIONS script errors and timeouts, with a maximum of two retries per event. Update related event and task handling to ensure retry tracking and cleanup.
This commit is contained in:
parent
b8da23fa6c
commit
3832a658ce
@ -271,8 +271,58 @@ static void sendEventStatus(const QString &deviceId, const QString &externalId,
|
||||
paymentThread->start();
|
||||
}
|
||||
|
||||
bool EventHandler::tryRetry(const QString &key, const EventInfo &event, const QString &reason) {
|
||||
constexpr int kMaxRetries = 2; // ещё 2 попытки сверх первой → всего 3 запуска
|
||||
const int used = m_retryCount.value(event.id, 0);
|
||||
if (used >= kMaxRetries) {
|
||||
m_retryCount.remove(event.id); // попытки исчерпаны — пусть caller обработает как ошибку
|
||||
return false;
|
||||
}
|
||||
const int attempt = used + 1;
|
||||
m_retryCount[event.id] = attempt;
|
||||
|
||||
qWarning() << "[EventHandler] FETCH_TRANSACTIONS retry" << attempt << "/" << kMaxRetries
|
||||
<< "for event" << event.id << "reason:" << reason;
|
||||
GeneralLogDAO::insert("WARNING", "EventHandler",
|
||||
QString("[FETCH_TRANSACTIONS] retry %1/%2 device=%3 material=%4: %5")
|
||||
.arg(QString::number(attempt), QString::number(kMaxRetries),
|
||||
event.deviceId, event.externalId, reason));
|
||||
|
||||
// Чистим артефакты прошлой попытки
|
||||
m_screenshots.remove(key);
|
||||
m_parsedTxs.remove(key);
|
||||
|
||||
// Снимаем текущий поток/таймер (в timeout-ветке они уже сняты — take() вернёт null)
|
||||
if (const auto tm = m_timers.take(key)) {
|
||||
tm->stop();
|
||||
tm->deleteLater();
|
||||
}
|
||||
m_threads.remove(key);
|
||||
|
||||
// Сбрасываем банковское приложение, чтобы попытка стартовала с чистого экрана
|
||||
const MaterialInfo account = MaterialDAO::getAccountById(event.accountId);
|
||||
const BankProfileInfo app = BankProfileDAO::getApplication(event.deviceId, account.appCode);
|
||||
if (!app.package.isEmpty()) {
|
||||
const DeviceInfo device = DeviceDAO::getDeviceById(event.deviceId);
|
||||
const QString adbSerial = device.adbSerial.isEmpty() ? event.deviceId : device.adbSerial;
|
||||
AdbUtils::tryToKillApplication(adbSerial, app.package);
|
||||
}
|
||||
|
||||
// Держим событие InProgress и перезапускаем скрипт
|
||||
EventDAO::updateEvent(event.id, EventStatus::InProgress, "");
|
||||
startThreadForTask(account, event);
|
||||
return true;
|
||||
}
|
||||
|
||||
void EventHandler::updateEventThread(const QString &key, const EventInfo &event, const QString &result) {
|
||||
|
||||
// Поиск транзакции: при ошибке скрипта перезапускаем (ещё до 2 раз) вместо
|
||||
// немедленной отправки ошибки на сервер.
|
||||
if (!result.isEmpty() && event.type == EventType::FetchTransactions
|
||||
&& tryRetry(key, event, result)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const EventStatus newStatus = result.isEmpty() ? EventStatus::Complete : EventStatus::Error;
|
||||
|
||||
if (!EventDAO::updateEvent(event.id, newStatus, result)) {
|
||||
@ -368,12 +418,14 @@ void EventHandler::updateEventThread(const QString &key, const EventInfo &event,
|
||||
const QJsonObject parsedTx = m_parsedTxs.take(key);
|
||||
if (parsedTx.isEmpty()) {
|
||||
qWarning() << "[EventHandler] FETCH_TRANSACTIONS: script did not emit parsed tx";
|
||||
if (tryRetry(key, event, "Transaction not parsed from screen")) return;
|
||||
sendTaskError(eventTypeToString(event.type), event.externalId, event.bankName,
|
||||
"Transaction not parsed from screen", {}, -1, event.transactionId);
|
||||
EventDAO::updateEvent(event.id, EventStatus::Error,
|
||||
"Transaction not parsed from screen");
|
||||
EventDAO::markSentToServer(event.id);
|
||||
m_threads.remove(key);
|
||||
m_retryCount.remove(event.id);
|
||||
return;
|
||||
}
|
||||
QJsonArray arr;
|
||||
@ -507,6 +559,7 @@ void EventHandler::updateEventThread(const QString &key, const EventInfo &event,
|
||||
tm->deleteLater();
|
||||
}
|
||||
m_threads.remove(key);
|
||||
m_retryCount.remove(event.id);
|
||||
|
||||
// Убиваем банковское приложение на устройстве после завершения задачи
|
||||
{
|
||||
@ -659,6 +712,12 @@ void EventHandler::startThreadForTask(const MaterialInfo &account, const EventIn
|
||||
}
|
||||
m_threads.remove(key);
|
||||
|
||||
// Поиск транзакции: таймаут тоже ретраим (ещё до 2 раз)
|
||||
if (event.type == EventType::FetchTransactions
|
||||
&& tryRetry(key, event, "Script timeout (5 min)")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Помечаем событие как ошибку
|
||||
EventDAO::updateEvent(event.id, EventStatus::Error, "Script timeout (5 min)");
|
||||
const QString logMsg = QString("[%1] bank=%2 material=%3: Script timeout")
|
||||
|
||||
@ -35,6 +35,7 @@ private:
|
||||
QMap<QString, QTimer *> m_timers;
|
||||
QMap<QString, QByteArray> m_screenshots; // deviceId → скриншот от скрипта
|
||||
QMap<QString, QJsonObject> m_parsedTxs; // key → распарсенная транзакция для FETCH_TRANSACTIONS
|
||||
QMap<int, int> m_retryCount; // event.id → число уже сделанных ретраев (только FETCH_TRANSACTIONS)
|
||||
QTimer *m_pollTimer = nullptr;
|
||||
NetworkService *m_network = nullptr;
|
||||
|
||||
@ -42,6 +43,10 @@ private:
|
||||
|
||||
void updateEventThread(const QString &key, const EventInfo &event, const QString &result);
|
||||
|
||||
// Перезапускает скрипт поиска транзакции при ошибке (до 2 ретраев). Возвращает
|
||||
// true, если ретрай запущен; false — если попытки исчерпаны (обрабатывать как ошибку).
|
||||
bool tryRetry(const QString &key, const EventInfo &event, const QString &reason);
|
||||
|
||||
void startThreadForTask(const MaterialInfo &account, const EventInfo &event);
|
||||
|
||||
void processNextTask(const QString &deviceId);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user