Awesome
<a href="https://github.com/AaronJan/Hunch"> <img width="160" src="https://user-images.githubusercontent.com/4630940/59684078-ea9d8c80-920b-11e9-9c99-85051dcb8a04.jpg" alt="Housekeeper" title="Hunch" align="right"/> </a>Hunch
Hunch provides functions like: All
, First
, Retry
, Waterfall
etc., that makes asynchronous flow control more intuitive.
About Hunch
Go have several concurrency patterns, here're some articles:
- https://blog.golang.org/pipelines
- https://blog.golang.org/context
- https://blog.golang.org/go-concurrency-patterns-timing-out-and
- https://blog.golang.org/advanced-go-concurrency-patterns
But nowadays, using the context
package is the most powerful pattern.
So base on context
, Hunch provides functions that can help you deal with complex asynchronous logics with ease.
Usage
Installation
go get
$ go get -u -v github.com/aaronjan/hunch
go mod
(Recommended)
import "github.com/aaronjan/hunch"
$ go mod tidy
Types
type Executable func(context.Context) (interface{}, error)
type ExecutableInSequence func(context.Context, interface{}) (interface{}, error)
API
All
func All(parentCtx context.Context, execs ...Executable) ([]interface{}, error)
All returns all the outputs from all Executables, order guaranteed.
Examples
ctx := context.Background()
r, err := hunch.All(
ctx,
func(ctx context.Context) (interface{}, error) {
time.Sleep(300 * time.Millisecond)
return 1, nil
},
func(ctx context.Context) (interface{}, error) {
time.Sleep(200 * time.Millisecond)
return 2, nil
},
func(ctx context.Context) (interface{}, error) {
time.Sleep(100 * time.Millisecond)
return 3, nil
},
)
fmt.Println(r, err)
// Output:
// [1 2 3] <nil>
Take
func Take(parentCtx context.Context, num int, execs ...Executable) ([]interface{}, error)
Take returns the first num
values outputted by the Executables.
Examples
ctx := context.Background()
r, err := hunch.Take(
ctx,
// Only need the first 2 values.
2,
func(ctx context.Context) (interface{}, error) {
time.Sleep(300 * time.Millisecond)
return 1, nil
},
func(ctx context.Context) (interface{}, error) {
time.Sleep(200 * time.Millisecond)
return 2, nil
},
func(ctx context.Context) (interface{}, error) {
time.Sleep(100 * time.Millisecond)
return 3, nil
},
)
fmt.Println(r, err)
// Output:
// [3 2] <nil>
Last
func Last(parentCtx context.Context, num int, execs ...Executable) ([]interface{}, error)
Last returns the last num
values outputted by the Executables.
Examples
ctx := context.Background()
r, err := hunch.Last(
ctx,
// Only need the last 2 values.
2,
func(ctx context.Context) (interface{}, error) {
time.Sleep(300 * time.Millisecond)
return 1, nil
},
func(ctx context.Context) (interface{}, error) {
time.Sleep(200 * time.Millisecond)
return 2, nil
},
func(ctx context.Context) (interface{}, error) {
time.Sleep(100 * time.Millisecond)
return 3, nil
},
)
fmt.Println(r, err)
// Output:
// [2 1] <nil>
Waterfall
func Waterfall(parentCtx context.Context, execs ...ExecutableInSequence) (interface{}, error)
Waterfall runs ExecutableInSequence
s one by one, passing previous result to next Executable as input. When an error occurred, it stop the process then returns the error. When the parent Context canceled, it returns the Err()
of it immediately.
Examples
ctx := context.Background()
r, err := hunch.Waterfall(
ctx,
func(ctx context.Context, n interface{}) (interface{}, error) {
return 1, nil
},
func(ctx context.Context, n interface{}) (interface{}, error) {
return n.(int) + 1, nil
},
func(ctx context.Context, n interface{}) (interface{}, error) {
return n.(int) + 1, nil
},
)
fmt.Println(r, err)
// Output:
// 3 <nil>
Retry
func Retry(parentCtx context.Context, retries int, fn Executable) (interface{}, error)
Retry attempts to get a value from an Executable instead of an Error. It will keeps re-running the Executable when failed no more than retries
times. Also, when the parent Context canceled, it returns the Err()
of it immediately.
Examples
count := 0
getStuffFromAPI := func() (int, error) {
if count == 5 {
return 1, nil
}
count++
return 0, fmt.Errorf("timeout")
}
ctx := context.Background()
r, err := hunch.Retry(
ctx,
10,
func(ctx context.Context) (interface{}, error) {
rs, err := getStuffFromAPI()
return rs, err
},
)
fmt.Println(r, err, count)
// Output:
// 1 <nil> 5
Credits
Heavily inspired by Async and ReactiveX.