-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtask.go
More file actions
132 lines (113 loc) · 3.18 KB
/
task.go
File metadata and controls
132 lines (113 loc) · 3.18 KB
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
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
// Package task provides some helper to work with common routines so that it can be
// cancellable or repeatable.
package task
import (
"context"
"errors"
"sync"
"time"
)
// Task repeasents a (maybe) cancellable routine.
type Task func(context.Context) error
// Exec runs the task with empty context ([context.Background]).
func (t Task) Exec() error {
return t(context.Background())
}
// Run runs the task, equals to t(ctx).
func (t Task) Run(ctx context.Context) error {
return t(ctx)
}
// NoCtx converts the task into a simple function by feeding empty context when run.
func (t Task) NoCtx() func() error {
return func() error { return t(context.Background()) }
}
// NoErr converts the task into a simple function by feeding empty context when run.
func (t Task) NoErr() func() {
return func() { t(context.Background()) }
}
// Go runs t in separated goroutine and returns a channel to retrieve error.
//
// It's safe to ignore the channel if you don't need the result.
func (t Task) Go(ctx context.Context) <-chan error {
ret := make(chan error, 1)
t.GoWithChan(ctx, ret)
return ret
}
// GoWithChan runs t in separated goroutine and sends returned error into ch.
func (t Task) GoWithChan(ctx context.Context, ch chan<- error) {
go func() { ch <- t.Run(ctx) }()
}
// CtxMod defines how you modify a context.
type CtxMod func(context.Context) (context.Context, func())
// Timeout creates a CtxMod which adds timeout info to a context.
func Timeout(dur time.Duration) CtxMod {
return func(ctx context.Context) (context.Context, func()) {
return context.WithTimeout(ctx, dur)
}
}
// With creates a task that the context is derived using modder before running t.
func (t Task) With(modder CtxMod) Task {
return func(ctx context.Context) error {
x, c := modder(ctx)
defer c()
return t.Run(x)
}
}
var ErrOnce = errors.New("the task can only be executed once.")
// Once creates a task that can be run only once, further attempt returns ErrOnce.
func (t Task) Once() Task {
var once sync.Once
return func(ctx context.Context) (err error) {
err = ErrOnce
once.Do(func() {
err = t(ctx)
})
return
}
}
// Cached wraps t to cache the result, and reuse it in later call.
func (t Task) Cached() Task {
var (
once sync.Once
err error
)
return func(ctx context.Context) error {
once.Do(func() {
err = t(ctx)
})
return err
}
}
// Defer wraps t to run f after it.
func (t Task) Defer(f func()) Task {
return func(ctx context.Context) (err error) {
err = t(ctx)
f()
return err
}
}
// Pre wraps t to run f before it.
func (t Task) Pre(f func()) Task {
return func(ctx context.Context) (err error) {
f()
err = t(ctx)
return
}
}
// Post wraps t to run f after it.
func (t Task) Post(f func(error)) Task {
return func(ctx context.Context) (err error) {
err = t(ctx)
f(err)
return
}
}
// AlterError wraps t to run f to alter the error before returning.
func (t Task) AlterError(f func(error) error) Task {
return func(ctx context.Context) error {
return f(t(ctx))
}
}