81 lines
1.6 KiB
Go
81 lines
1.6 KiB
Go
|
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
||
|
// Use of this source code is governed by the Drone Non-Commercial License
|
||
|
// that can be found in the LICENSE file.
|
||
|
|
||
|
package queue
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"sync"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
type canceller struct {
|
||
|
sync.Mutex
|
||
|
|
||
|
subscribers map[chan struct{}]int64
|
||
|
cancelled map[int64]time.Time
|
||
|
}
|
||
|
|
||
|
func newCanceller() *canceller {
|
||
|
return &canceller{
|
||
|
subscribers: make(map[chan struct{}]int64),
|
||
|
cancelled: make(map[int64]time.Time),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (c *canceller) Cancel(ctx context.Context, id int64) error {
|
||
|
c.Lock()
|
||
|
c.cancelled[id] = time.Now().Add(time.Minute * 5)
|
||
|
for subscriber, build := range c.subscribers {
|
||
|
if id == build {
|
||
|
close(subscriber)
|
||
|
}
|
||
|
}
|
||
|
c.collect()
|
||
|
c.Unlock()
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (c *canceller) Cancelled(ctx context.Context, id int64) (bool, error) {
|
||
|
subscriber := make(chan struct{})
|
||
|
c.Lock()
|
||
|
c.subscribers[subscriber] = id
|
||
|
c.Unlock()
|
||
|
|
||
|
defer func() {
|
||
|
c.Lock()
|
||
|
delete(c.subscribers, subscriber)
|
||
|
c.Unlock()
|
||
|
}()
|
||
|
|
||
|
for {
|
||
|
select {
|
||
|
case <-ctx.Done():
|
||
|
return false, ctx.Err()
|
||
|
case <-time.After(time.Minute):
|
||
|
c.Lock()
|
||
|
_, ok := c.cancelled[id]
|
||
|
c.Unlock()
|
||
|
if ok {
|
||
|
return true, nil
|
||
|
}
|
||
|
case <-subscriber:
|
||
|
return true, nil
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (c *canceller) collect() {
|
||
|
// the list of cancelled builds is stored with a ttl, and
|
||
|
// is not removed until the ttl is reached. This provides
|
||
|
// adequate window for clients with connectivity issues to
|
||
|
// reconnect and receive notification of cancel events.
|
||
|
now := time.Now()
|
||
|
for build, timestamp := range c.cancelled {
|
||
|
if now.After(timestamp) {
|
||
|
delete(c.cancelled, build)
|
||
|
}
|
||
|
}
|
||
|
}
|