ingredient/locker: Unlock even after cancel
This commit is contained in:
parent
7006277409
commit
b86e6294de
2 changed files with 73 additions and 1 deletions
67
pkg/cancel/anyways.go
Normal file
67
pkg/cancel/anyways.go
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
package cancel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Anyways behaves like context.WithTimeout, except that if the Done() channel of ctx is closed before Anyways is called, the returned context's Done() channel is only closed after timeout.
|
||||
func Anyways(ctx context.Context, timeout time.Duration) (context.Context, context.CancelFunc) {
|
||||
// context is not yet cancelled => return as-is
|
||||
if err := ctx.Err(); err == nil {
|
||||
return context.WithTimeout(ctx, timeout)
|
||||
}
|
||||
|
||||
// create a new anyways
|
||||
any := &anyways{
|
||||
done: make(chan struct{}),
|
||||
parent: ctx,
|
||||
deadline: time.Now().Add(timeout),
|
||||
}
|
||||
|
||||
// start waiting for the timer (or the cancel to be called)
|
||||
finish := make(chan struct{})
|
||||
go func() {
|
||||
t := time.NewTimer(timeout)
|
||||
defer t.Stop()
|
||||
|
||||
defer close(any.done)
|
||||
|
||||
select {
|
||||
case <-t.C:
|
||||
case <-finish:
|
||||
}
|
||||
}()
|
||||
|
||||
return any, func() {
|
||||
close(finish)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type anyways struct {
|
||||
done chan struct{}
|
||||
|
||||
parent context.Context
|
||||
deadline time.Time
|
||||
}
|
||||
|
||||
func (a anyways) Deadline() (deadline time.Time, ok bool) {
|
||||
return a.deadline, true
|
||||
}
|
||||
|
||||
func (a anyways) Done() <-chan struct{} {
|
||||
return a.done
|
||||
}
|
||||
func (a anyways) Err() error {
|
||||
select {
|
||||
case <-a.done:
|
||||
return context.DeadlineExceeded
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (a anyways) Value(key any) any {
|
||||
return a.parent.Done()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue