Skip to content

Instantly share code, notes, and snippets.

@alzobnin
Last active October 20, 2020 09:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alzobnin/451f03405c4e9553ebd37b1814fd3ad1 to your computer and use it in GitHub Desktop.
Save alzobnin/451f03405c4e9553ebd37b1814fd3ad1 to your computer and use it in GitHub Desktop.

Разбор задачи «Retry»

Условие

Иногда некоторые действия не получается выполнить с первого раза. Например, обращение по сети в сторонний сервис может обернуться неудачей из-за сетевых проблем или перегрузки сервиса. В таких случаях иногда пишут код, пытающийся повторить такое действие несколько раз подряд.

Вам надо написать реализацию функции DoWithRetry с таким заголовком:

#include <exception>
#include <functional>
#include <optional>

template <typename Result, typename Exception = std::exception>
std::optional<Result> DoWithRetry(std::function<Result()> func, int retryCount, int sleepTime, bool throwLast);

Функция принимает на вход другую функцию без аргументов, возвращающую значение типа Result, количество повторов, таймаут между повторами и флажок throwLast. Одним из шаблонных параметров функции является тип исключения, на которое функция реагирует. Функция должна вызвать func, и если произошло исключение указанного типа, то вызвать нашу функцию Sleep с параметром sleepTime, а затем повторить попытку (если попытки еще остались). Максимальное количество вызовов func, которое может получиться, равно retryCount + 1. Если на последней попытке происходит исключение указанного типа, и throwLast истинно, этот же объект исключения должен проброситься дальше из функции. Если же throwLast ложно, то надо просто вернуть пустой объект std::optional. Если же вызов func закончился успешно, то надо просто вернуть результат func.

Про std::optional можно прочитать здесь. Если исключение произошло на последней попытке, то после нее "спать" не надо.

Решение

#include <exception>
#include <functional>
#include <optional>

template <typename Result, typename Exception = std::exception>
std::optional<Result> DoWithRetry(std::function<Result()> func, int retryCount, int sleepTime, bool throwLast) {
    for (int i = 0; i < retryCount + 1; ++i) {
        try {
            return func();
        } catch (const Exception&) {
            if (i == retryCount) {
                if (throwLast) {
                    throw;
                } else {
                    return {};
                }
            } else {
                Sleep(sleepTime);
            }
        }
    }
    return {};
}

Здесь мы перехватываем потенциальные исключения, приводящиеся к типу Exception (важно ловить именно их, а не писать catch (...)). При этом сам объект исключения нам не нужен, поэтому мы его имя не указываем. При необходимости (после последней попытки при возведенном throwLast) мы перекидываем пойманное исключение дальше с помощью throw без аргументов

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment