-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy patherrs.go
143 lines (126 loc) · 3.07 KB
/
errs.go
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Copyright 2021 Airbus Defence and Space
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package errs
import (
"context"
"errors"
"io"
"os"
"strings"
"syscall"
"cloud.google.com/go/compute/metadata"
"google.golang.org/api/googleapi"
)
//Temporary inspects the error trace and returns wether the error is transient
func Temporary(err error) bool {
if err == nil {
return false
}
//override some default syscall temporary statuses
var errno syscall.Errno
if errors.As(err, &errno) {
switch errno {
case syscall.EIO, syscall.EBUSY, syscall.ECANCELED, syscall.ECONNABORTED, syscall.ECONNRESET, syscall.ENOMEM, syscall.EPIPE:
return true
}
}
//check explicitely marked error
type tempIf interface{ Temporary() bool }
var tmp tempIf
if errors.As(err, &tmp) {
return tmp.Temporary()
}
//google api errors
var gapiError *googleapi.Error
if errors.As(err, &gapiError) {
switch gapiError.Code {
case 429, 500, 502, 503, 504:
return true
}
}
//errors raised when querying compute-engine metadata server
var metaErr *metadata.Error
if errors.As(err, &metaErr) {
switch metaErr.Code {
case 429, 500, 502, 503, 504:
return true
}
}
//not really needed, as context.DeadlineExceeded implements Temporary()
if errors.Is(err, os.ErrDeadlineExceeded) {
return true
}
//cancelled contexts
if errors.Is(err, context.Canceled) {
return true
}
//hack for https://github.com/golang/oauth2/pull/380
errmsg := err.Error()
if strings.Contains(errmsg, "i/o timeout") ||
strings.Contains(errmsg, "connection reset by peer") ||
strings.Contains(errmsg, "TLS handshake timeout") ||
strings.Contains(errmsg, "oauth2: cannot fetch token") {
return true
}
return false
}
type tempErr struct {
error
}
type permErr struct {
error
}
func (t *tempErr) Temporary() bool {
return true
}
func (t *permErr) Temporary() bool {
return false
}
func (t *tempErr) Unwrap() error {
return t.error
}
func (t *permErr) Unwrap() error {
return t.error
}
func (t *tempErr) Cause() error {
return t.error
}
func (t *permErr) Cause() error {
return t.error
}
func MakeTemporary(err error) error {
return &tempErr{err}
}
func MakePermanent(err error) error {
return &permErr{err}
}
type werr struct {
error
}
func (t *werr) Temporary() bool {
return Temporary(t.error)
}
// AddTemporary ensures that err exposes a `Temporary() bool` method
func AddTemporaryCheck(err error) error {
if err == nil || err == io.EOF || err == io.ErrUnexpectedEOF {
return err
}
type terr interface {
Temporary() bool
}
if _, ok := err.(terr); ok {
return err
}
return &werr{err}
}