Try Documentalist,
my app that offers fast, offline access to 190+ programmer API docs.
type Context interface {
// Deadline returns the time when work done
// on behalf of this context should be canceled.
Deadline() (deadline time.Time, ok bool)
// Done returns a channel that's closed when work done
// on behalf of this context should be canceled.
Done() <-chan struct{}
// Err returns a non-nil error value after Done is closed.
Err() error
// Value returns the value associated with this context for key
Value(key interface{}) interface{}
}
func Background() Context
func TODO() Context
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithValue(parent Context, key, val interface{}) Context
// modify context of http.Request
func middleware(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Use request method context, which returns context, if ctx is nil
// then creates new background context - context.Background()
ctx = r.Context()
// Build context variations on top of background context
ctx = context.WithValue(ctx, "some_key", "some_value")
// tctx, cancelFunc := context.WithTimeout(ctx, time.Duration(5 * time.Second))
// deadline := time.Now().Add(time.Duration(30 * time.Second))
// dctx, cancelFunc := context.WithDeadline(ctx, deadline)
// WithContext returns a shallow copy of r with its context changed to ctx.
r = r.WithContext(ctx)
h(w, r)
}
}
// pattern for setting/getting value in a context
type contextKey string
// making it un-exported package variable avoid naming conflics between
// packages
var userContextKey contextKey = "user"
func NewUserContext(ctx context.Context, user *User) context.Context {
return context.WithValue(ctx, userContextKey, user)
}
func UserFromContext(ctx context.Context) (*User, bool) {
u, ok := ctx.Value(userContextKey).(*User)
return u, ok
}
func UserMustFromContext(ctx context.Context) *User {
u, ok := ctx.Value(userContextKey).(*User)
if !ok {
panic("user not found in context")
}
return u
}
func handlerRequestWithCancelation(w http.ResponseWriter, r *http.Request) {
longRunningCalculation := func(ctx context.Context) {
for i := 0; ; i++ {
select {
case <-ctx.Done():
return
default:
time.Sleep(1 * time.Second)
fmt.Printf("Worker %d \n", i)
}
}
}
// the context is canceled when the ServeHTTP method returns
go longRunningCalculation(r.Context())
// give some time for longRunningCalculation to do some work
time.Sleep(5 * time.Second)
io.WriteString(w, "bazinga!")
return
}
// explicitly cancelling context
func handlerSearchCancel(w http.ResponseWriter, r *http.Request) {
var ctx context.Context
var cancel context.CancelFunc
ctx, cancel = context.WithCancel(r.Context())
defer cancel()
// Close context.Done channel in 4 seconds
go func() {
time.Sleep(4 * time.Second)
cancel()
}()
select {
case <-ctx.Done():
log.Print(ctx.Err())
return
case result := <-longRunningCalculation():
io.WriteString(w, result)
}
return
}
How can I use WithTimeout and WithDeadline ?
Context with timeout
ctx, cancel = context.WithTimeout(ctx, time.Duration(7 * time.Second))
defer cancel()
Context with deadline
deadline := time.Now().Add(time.Duration(30 * time.Second))
dctx, cancel := context.WithDeadline(ctx, deadline)
defer cancel()
Pattern here is the same, you have to wait for signal from ctx.Done
select {
case <-ctx.Done():
log.Print(ctx.Err())
return
case result := <-longRunningCalculation():
io.WriteString(w, result)
}
func handlerSearchTimeout(w http.ResponseWriter, r *http.Request) {
var ctx context.Context
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(r.Context(), time.Duration(2*time.Second))
defer cancel()
request, err := http.NewRequest(http.MethodGet, "http://localhost:8181/timeout", nil)
if err != nil {
log.Println(err.Error())
return
}
// You can context separately for each request
request = request.WithContext(ctx)
client := &http.Client{}
response, err := client.Do(request)
// You will get an error "net/http: request canceled" when request timeout exceeds limits
if err != nil {
log.Println(err.Error())
return
}
// ......