aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/tvmauth/client/misc/last_error.cpp
blob: a6279bb1efeb848766110e13d00e04d9253e4232 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include "last_error.h"

#include <util/string/builder.h>

namespace NTvmAuth {
    TLastError::TLastError()
        : LastErrors_(MakeIntrusiveConst<TLastErrors>())
    {
    }

    TString TLastError::GetLastError(bool isOk, EType* type) const {
        if (isOk) {
            return OK_;
        }

        const TLastErrorsPtr ptr = LastErrors_.Get();

        for (const TLastErr& err : ptr->Errors) {
            if (err && err->first == EType::NonRetriable) {
                if (type) {
                    *type = EType::NonRetriable;
                }
                return err->second;
            }
        }

        for (const TLastErr& err : ptr->Errors) {
            if (err) {
                if (type) {
                    *type = EType::Retriable;
                }
                return err->second;
            }
        }

        if (type) {
            *type = EType::NonRetriable;
        }
        return "Internal client error: failed to collect last useful error message, please report this message to tvm-dev@yandex-team.ru";
    }

    TString TLastError::ProcessHttpError(TLastError::EScope scope,
                                         TStringBuf path,
                                         int code,
                                         const TString& msg) const {
        TString err = TStringBuilder() << "Path:" << path << ".Code=" << code << ": " << msg;

        ProcessError(code >= 400 && code < 500 ? EType::NonRetriable
                                               : EType::Retriable,
                     scope,
                     err);

        return err;
    }

    void TLastError::ProcessError(TLastError::EType type, TLastError::EScope scope, const TStringBuf msg) const {
        Update(scope, [&](TLastErr& lastError) {
            if (lastError && lastError->first == EType::NonRetriable && type == EType::Retriable) {
                return false;
            }

            TString err = TStringBuilder() << scope << ": " << msg;
            err.erase(std::remove(err.begin(), err.vend(), '\r'), err.vend());
            std::replace(err.begin(), err.vend(), '\n', ' ');

            lastError = {type, std::move(err)};
            return true;
        });
    }

    void TLastError::ClearError(TLastError::EScope scope) {
        Update(scope, [&](TLastErr& lastError) {
            if (!lastError) {
                return false;
            }

            lastError.Clear();
            return true;
        });
    }

    void TLastError::ClearErrors() {
        for (size_t idx = 0; idx < (size_t)EScope::COUNT; ++idx) {
            ClearError((EScope)idx);
        }
    }

    void TLastError::ThrowLastError() {
        EType type;
        TString err = GetLastError(false, &type);

        switch (type) {
            case EType::NonRetriable:
                ythrow TNonRetriableException()
                    << "Failed to start TvmClient. Do not retry: "
                    << err;
            case EType::Retriable:
                ythrow TRetriableException()
                    << "Failed to start TvmClient. You can retry: "
                    << err;
        }
    }

    template <typename Func>
    void TLastError::Update(TLastError::EScope scope, Func func) const {
        Y_VERIFY(scope != EScope::COUNT);

        TLastErrors errs = *LastErrors_.Get();
        TLastErr& lastError = errs.Errors[(size_t)scope];

        if (func(lastError)) {
            LastErrors_.Set(MakeIntrusiveConst<TLastErrors>(std::move(errs)));
        }
    }
}