Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
dms3
go-unixfs
Commits
fd3e0bb3
Commit
fd3e0bb3
authored
Jan 11, 2015
by
Juan Batiz-Benet
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
added temp-err-catcher
parent
456719ed
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
496 additions
and
0 deletions
+496
-0
Godeps/Godeps.json
Godeps/Godeps.json
+4
-0
Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/.travis.yml
...ace/src/github.com/jbenet/go-temp-err-catcher/.travis.yml
+9
-0
Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/README.md
...space/src/github.com/jbenet/go-temp-err-catcher/README.md
+78
-0
Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/doc.go
...orkspace/src/github.com/jbenet/go-temp-err-catcher/doc.go
+62
-0
Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/example/example.go
.../github.com/jbenet/go-temp-err-catcher/example/example.go
+47
-0
Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/tec_test.go
...ace/src/github.com/jbenet/go-temp-err-catcher/tec_test.go
+172
-0
Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/temp_err_catcher.go
...github.com/jbenet/go-temp-err-catcher/temp_err_catcher.go
+124
-0
No files found.
Godeps/Godeps.json
View file @
fd3e0bb3
...
...
@@ -150,6 +150,10 @@
"ImportPath"
:
"github.com/jbenet/go-random"
,
"Rev"
:
"2e83344e7dc7898f94501665af34edd4aa95a013"
},
{
"ImportPath"
:
"github.com/jbenet/go-temp-err-catcher"
,
"Rev"
:
"c531232018e678b2a702cfb86b5c3f68d1c8beb8"
},
{
"ImportPath"
:
"github.com/jbenet/goprocess"
,
"Rev"
:
"162148a58668ca38b0b8f0459ccc6ca88e32f1f4"
...
...
Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/.travis.yml
0 → 100644
View file @
fd3e0bb3
language
:
go
go
:
-
1.3
-
release
-
tip
script
:
-
go test -v
Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/README.md
0 → 100644
View file @
fd3e0bb3
# go-temp-err-catcher
This is a little package to use with your net.Listeners.
Docs: https://godoc.org/github.com/jbenet/go-temp-err-catcher
Get:
go get github.com/jbenet/go-temp-err-catcher
## Examples
It is meant to be used with things like net.Lister.Accept:
```
go
import
(
tec
"github.com/jbenet/go-temp-err-catcher"
)
func
listen
(
listener
net
.
Listener
)
{
var
c
tec
.
TempErrCatcher
for
{
conn
,
err
:=
listener
.
Accept
()
if
err
!=
nil
&&
c
.
IsTemporary
(
c
)
{
continue
}
return
conn
,
err
}
}
```
You can make your errors implement
`Temporary`
:
```
go
type
errTemp
struct
{
e
error
}
func
(
e
errTemp
)
Temporary
()
bool
{
return
true
}
func
(
e
errTemp
)
Error
()
string
{
return
e
.
e
.
Error
()
}
err
:=
errors
.
New
(
"beep boop"
)
var
c
tec
.
TempErrCatcher
c
.
IsTemporary
(
err
)
// false
c
.
IsTemporary
(
errTemp
{
err
})
// true
```
Or just use
`ErrTemp`
:
```
go
err
:=
errors
.
New
(
"beep boop"
)
var
c
tec
.
TempErrCatcher
c
.
IsTemporary
(
err
)
// false
c
.
IsTemporary
(
tec
.
ErrTemp
{
err
})
// true
```
You can also define an
`IsTemp`
function to classify errors:
```
go
var
ErrSkip
=
errors
.
New
(
"this should be skipped"
)
var
ErrNotSkip
=
errors
.
New
(
"this should not be skipped"
)
var
c
tec
.
TempErrCatcher
c
.
IsTemp
=
func
(
e
error
)
bool
{
return
e
==
ErrSkip
}
c
.
IsTemporary
(
ErrSkip
)
// true
c
.
IsTemporary
(
ErrNotSkip
)
// false
c
.
IsTemporary
(
ErrTemp
)
// false! no longer accepts Temporary()
```
Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/doc.go
0 → 100644
View file @
fd3e0bb3
// Package temperrcatcher provides a TempErrCatcher object,
// which implements simple error-retrying functionality.
// It is meant to be used with things like net.Lister.Accept:
//
// import (
// tec "github.com/jbenet/go-temp-err-catcher"
// )
//
// func listen(listener net.Listener) {
// var c tec.TempErrCatcher
//
// for {
// conn, err := listener.Accept()
// if err != nil && c.IsTemporary(c) {
// continue
// }
// return conn, err
// }
// }
//
// You can make your errors implement `Temporary`:
//
// type errTemp struct {
// e error
// }
//
// func (e errTemp) Temporary() bool {
// return true
// }
//
// func (e errTemp) Error() string {
// return e.e.Error()
// }
//
// err := errors.New("beep boop")
// var c tec.TempErrCatcher
// c.IsTemporary(err) // false
// c.IsTemporary(errTemp{err}) // true
//
// Or just use `ErrTemp`:
//
// err := errors.New("beep boop")
// var c tec.TempErrCatcher
// c.IsTemporary(err) // false
// c.IsTemporary(tec.ErrTemp{err}) // true
//
//
// You can also define an `IsTemp` function to classify errors:
//
// var ErrSkip = errors.New("this should be skipped")
// var ErrNotSkip = errors.New("this should not be skipped")
//
// var c tec.TempErrCatcher
// c.IsTemp = func(e error) bool {
// return e == ErrSkip
// }
//
// c.IsTemporary(ErrSkip) // true
// c.IsTemporary(ErrNotSkip) // false
// c.IsTemporary(ErrTemp) // false! no longer accepts Temporary()
//
package
temperrcatcher
Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/example/example.go
0 → 100644
View file @
fd3e0bb3
package
main
import
(
"fmt"
tec
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher"
)
var
(
ErrTemp
=
tec
.
ErrTemporary
{
fmt
.
Errorf
(
"ErrTemp"
)}
ErrSkip
=
fmt
.
Errorf
(
"ErrSkip"
)
ErrOther
=
fmt
.
Errorf
(
"ErrOther"
)
)
func
main
()
{
var
normal
tec
.
TempErrCatcher
var
skipper
tec
.
TempErrCatcher
skipper
.
IsTemp
=
func
(
e
error
)
bool
{
return
e
==
ErrSkip
}
fmt
.
Println
(
"trying normal (uses Temporary interface)"
)
tryTec
(
normal
)
fmt
.
Println
(
""
)
fmt
.
Println
(
"trying skipper (uses our IsTemp function)"
)
tryTec
(
skipper
)
}
func
tryTec
(
c
tec
.
TempErrCatcher
)
{
errs
:=
[]
error
{
ErrTemp
,
ErrSkip
,
ErrOther
,
ErrTemp
,
ErrSkip
,
ErrOther
,
}
for
_
,
e
:=
range
errs
{
if
c
.
IsTemporary
(
e
)
{
fmt
.
Printf
(
"
\t
IsTemporary: true - skipped %s
\n
"
,
e
)
continue
}
fmt
.
Printf
(
"
\t
IsTemporary: false - not skipped %s
\n
"
,
e
)
}
}
Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/tec_test.go
0 → 100644
View file @
fd3e0bb3
package
temperrcatcher
import
(
"fmt"
"testing"
"time"
)
var
(
ErrTemp
=
ErrTemporary
{
fmt
.
Errorf
(
"ErrTemp"
)}
ErrSkip
=
fmt
.
Errorf
(
"ErrSkip"
)
ErrOther
=
fmt
.
Errorf
(
"ErrOther"
)
)
func
testTec
(
t
*
testing
.
T
,
c
TempErrCatcher
,
errs
map
[
error
]
bool
)
{
for
e
,
expected
:=
range
errs
{
if
c
.
IsTemporary
(
e
)
!=
expected
{
t
.
Error
(
"expected %s to be %v"
,
e
,
expected
)
}
}
}
func
TestNil
(
t
*
testing
.
T
)
{
var
c
TempErrCatcher
testTec
(
t
,
c
,
map
[
error
]
bool
{
ErrTemp
:
true
,
ErrSkip
:
false
,
ErrOther
:
false
,
})
}
func
TestWait
(
t
*
testing
.
T
)
{
var
c
TempErrCatcher
worked
:=
make
(
chan
time
.
Duration
,
3
)
c
.
Wait
=
func
(
t
time
.
Duration
)
{
worked
<-
t
}
testTec
(
t
,
c
,
map
[
error
]
bool
{
ErrTemp
:
true
,
ErrSkip
:
false
,
ErrOther
:
false
,
})
// should've called it once
select
{
case
<-
worked
:
default
:
t
.
Error
(
"did not call our Wait func"
)
}
// should've called it ONLY once
select
{
case
<-
worked
:
t
.
Error
(
"called our Wait func more than once"
)
default
:
}
}
func
TestTemporary
(
t
*
testing
.
T
)
{
var
c
TempErrCatcher
testTec
(
t
,
c
,
map
[
error
]
bool
{
ErrTemp
:
true
,
ErrSkip
:
false
,
ErrOther
:
false
,
})
}
func
TestDoubles
(
t
*
testing
.
T
)
{
last
:=
time
.
Now
()
diff
:=
func
()
time
.
Duration
{
now
:=
time
.
Now
()
diff
:=
now
.
Sub
(
last
)
last
=
now
return
diff
}
testDiff
:=
func
(
low
,
hi
time
.
Duration
)
{
d
:=
diff
()
grace
:=
time
.
Duration
(
time
.
Microsecond
)
if
(
d
+
grace
)
<
low
{
t
.
Error
(
"time difference is smaller than"
,
low
,
d
)
}
if
(
d
-
grace
)
>
hi
{
t
.
Error
(
"time difference is greater than"
,
hi
,
d
)
}
}
var
c
TempErrCatcher
testDiff
(
0
,
c
.
Start
)
c
.
IsTemporary
(
ErrTemp
)
testDiff
(
c
.
Start
,
2
*
c
.
Start
)
// first time.
c
.
IsTemporary
(
ErrTemp
)
testDiff
(
2
*
c
.
Start
,
4
*
c
.
Start
)
// second time.
c
.
IsTemporary
(
ErrTemp
)
testDiff
(
4
*
c
.
Start
,
8
*
c
.
Start
)
// third time.
}
func
TestDifferentStart
(
t
*
testing
.
T
)
{
last
:=
time
.
Now
()
diff
:=
func
()
time
.
Duration
{
now
:=
time
.
Now
()
diff
:=
now
.
Sub
(
last
)
last
=
now
return
diff
}
testDiff
:=
func
(
low
,
hi
time
.
Duration
)
{
d
:=
diff
()
grace
:=
time
.
Duration
(
time
.
Microsecond
)
if
(
d
+
grace
)
<
low
{
t
.
Error
(
"time difference is smaller than"
,
low
,
d
)
}
if
(
d
-
grace
)
>
hi
{
t
.
Error
(
"time difference is greater than"
,
hi
,
d
)
}
}
var
c
TempErrCatcher
f
:=
time
.
Millisecond
testDiff
(
0
,
f
)
c
.
IsTemporary
(
ErrTemp
)
testDiff
(
f
,
2
*
f
)
// first time.
c
.
IsTemporary
(
ErrTemp
)
testDiff
(
2
*
f
,
4
*
f
)
// second time.
c
.
IsTemporary
(
ErrTemp
)
testDiff
(
4
*
f
,
8
*
f
)
// third time.
c
.
Reset
()
c
.
Start
=
10
*
time
.
Millisecond
f
=
c
.
Start
testDiff
(
0
,
f
)
c
.
IsTemporary
(
ErrTemp
)
testDiff
(
f
,
2
*
f
)
// first time.
c
.
IsTemporary
(
ErrTemp
)
testDiff
(
2
*
f
,
4
*
f
)
// second time.
c
.
IsTemporary
(
ErrTemp
)
testDiff
(
4
*
f
,
8
*
f
)
// third time.
}
func
TestDifferentStreaks
(
t
*
testing
.
T
)
{
var
c
TempErrCatcher
// one streak
c
.
IsTemporary
(
ErrTemp
)
// 1
c
.
IsTemporary
(
ErrTemp
)
// 2
c
.
IsTemporary
(
ErrTemp
)
// 4
expect
:=
4
*
time
.
Millisecond
if
c
.
delay
!=
expect
{
t
.
Error
(
"delay should be:"
,
expect
,
c
.
delay
)
}
<-
time
.
After
(
c
.
delay
*
10
)
// a different streak
c
.
IsTemporary
(
ErrTemp
)
// 1
c
.
IsTemporary
(
ErrTemp
)
// 2
c
.
IsTemporary
(
ErrTemp
)
// 4
if
c
.
delay
!=
expect
{
t
.
Error
(
"delay should be:"
,
expect
,
c
.
delay
)
}
}
func
TestFunc
(
t
*
testing
.
T
)
{
var
c
TempErrCatcher
c
.
IsTemp
=
func
(
e
error
)
bool
{
return
e
==
ErrSkip
}
testTec
(
t
,
c
,
map
[
error
]
bool
{
ErrTemp
:
false
,
ErrSkip
:
true
,
ErrOther
:
false
,
})
}
Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher/temp_err_catcher.go
0 → 100644
View file @
fd3e0bb3
// Package temperrcatcher provides a TempErrCatcher object,
// which implements simple error-retrying functionality.
package
temperrcatcher
import
(
"time"
)
// InitialDelay governs how long to wait the first time.
// This is defaulted to time.Millisecond, which makes sense
// for network listener failures. You may want a much smaller
// delay. You can configure this package wide, or in each
// TempErrCatcher
var
InitialDelay
=
time
.
Millisecond
// Temporary is an interface errors can implement to
// ensure they are correctly classified by the default
// TempErrCatcher classifier
type
Temporary
interface
{
Temporary
()
bool
}
// ErrIsTemporary returns whether an error is Temporary(),
// iff it implements the Temporary interface.
func
ErrIsTemporary
(
e
error
)
bool
{
te
,
ok
:=
e
.
(
Temporary
)
return
ok
&&
te
.
Temporary
()
}
// TempErrCatcher catches temporary errors for you. It then sleeps
// for a bit before returning (you should then try again). This may
// seem odd, but it's exactly what net/http does:
// http://golang.org/src/net/http/server.go?s=51504:51550#L1728
//
// You can set a few options in TempErrCatcher. They all have defaults
// so a zero TempErrCatcher is ready to be used:
//
// var c tec.TempErrCatcher
// c.IsTemporary(tempErr)
//
type
TempErrCatcher
struct
{
IsTemp
func
(
error
)
bool
// the classifier to use. default: ErrIsTemporary
Wait
func
(
time
.
Duration
)
// the wait func to call. default: time.Sleep
Max
time
.
Duration
// the maximum time to wait. default: time.Second
Start
time
.
Duration
// the delay to start with. default: InitialDelay
delay
time
.
Duration
last
time
.
Time
}
func
(
tec
*
TempErrCatcher
)
init
()
{
if
tec
.
Max
==
0
{
tec
.
Max
=
time
.
Second
}
if
tec
.
IsTemp
==
nil
{
tec
.
IsTemp
=
ErrIsTemporary
}
if
tec
.
Wait
==
nil
{
tec
.
Wait
=
time
.
Sleep
}
if
tec
.
Start
==
0
{
tec
.
Start
=
InitialDelay
}
}
// IsTemporary checks whether an error is temporary. It will call
// tec.Wait before returning, with a delay. The delay is also
// doubled, so we do not constantly spin. This is the strategy
// net.Listener uses.
//
// Note: you will want to call Reset() if you get a success,
// so that the stored delay is brough back to 0.
func
(
tec
*
TempErrCatcher
)
IsTemporary
(
e
error
)
bool
{
tec
.
init
()
if
tec
.
IsTemp
(
e
)
{
now
:=
time
.
Now
()
if
now
.
Sub
(
tec
.
last
)
>
(
tec
.
delay
*
5
)
{
// this is a "new streak" of temp failures. reset.
tec
.
Reset
()
}
if
tec
.
delay
==
0
{
// init case.
tec
.
delay
=
tec
.
Start
}
else
{
tec
.
delay
*=
2
}
if
tec
.
delay
>
tec
.
Max
{
tec
.
delay
=
tec
.
Max
}
tec
.
Wait
(
tec
.
delay
)
tec
.
last
=
now
return
true
}
tec
.
Reset
()
// different failure. call reset
return
false
}
// Reset sets the internal delay counter to 0
func
(
tec
*
TempErrCatcher
)
Reset
()
{
tec
.
delay
=
0
}
// ErrTemporary wraps any error and implements Temporary function.
//
// err := errors.New("beep boop")
// var c tec.TempErrCatcher
// c.IsTemporary(err) // false
// c.IsTemporary(tec.ErrTemp{err}) // true
//
type
ErrTemporary
struct
{
Err
error
}
func
(
e
ErrTemporary
)
Temporary
()
bool
{
return
true
}
func
(
e
ErrTemporary
)
Error
()
string
{
return
e
.
Err
.
Error
()
}
func
(
e
ErrTemporary
)
String
()
string
{
return
e
.
Error
()
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment