ingredient/locker: Unlock even after cancel
This commit is contained in:
parent
7006277409
commit
b86e6294de
2 changed files with 73 additions and 1 deletions
|
|
@ -2,9 +2,11 @@ package locker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/wisski/ingredient"
|
"github.com/FAU-CDI/wisski-distillery/internal/wisski/ingredient"
|
||||||
|
"github.com/FAU-CDI/wisski-distillery/pkg/cancel"
|
||||||
"github.com/tkw1536/goprogram/exit"
|
"github.com/tkw1536/goprogram/exit"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -34,8 +36,11 @@ func (lock *Locker) TryLock(ctx context.Context) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TryUnlock attempts to unlock this WissKI and reports if it succeeded.
|
// TryUnlock attempts to unlock this WissKI and reports if it succeeded.
|
||||||
// An unlock can only
|
// An Unlock is also attempted when ctx is cancelled.
|
||||||
func (lock *Locker) TryUnlock(ctx context.Context) bool {
|
func (lock *Locker) TryUnlock(ctx context.Context) bool {
|
||||||
|
ctx, close := cancel.Anyways(ctx, time.Second)
|
||||||
|
defer close()
|
||||||
|
|
||||||
table, err := lock.Malt.SQL.QueryTable(ctx, true, models.LockTable)
|
table, err := lock.Malt.SQL.QueryTable(ctx, true, models.LockTable)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
|
|
|
||||||
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