util: Add safe easy ack that allows multiple ack's
Just another sync utility to make code more readable.
This commit is contained in:
29
util/sync.go
29
util/sync.go
@@ -65,6 +65,35 @@ func (obj *EasyOnce) Done() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EasyAckOnce is a wrapper to build ack functionality into a simple interface.
|
||||||
|
// It is safe because the Ack function can be called multiple times safely.
|
||||||
|
type EasyAckOnce struct {
|
||||||
|
done chan struct{}
|
||||||
|
once *sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEasyAckOnce builds the object. This must be called before use.
|
||||||
|
func NewEasyAckOnce() *EasyAckOnce {
|
||||||
|
return &EasyAckOnce{
|
||||||
|
done: make(chan struct{}),
|
||||||
|
once: &sync.Once{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ack sends the acknowledgment message. This can be called as many times as you
|
||||||
|
// like. Only the first Ack is meaningful. Subsequent Ack's are redundant. It is
|
||||||
|
// thread-safe.
|
||||||
|
func (obj *EasyAckOnce) Ack() {
|
||||||
|
fn := func() { close(obj.done) }
|
||||||
|
obj.once.Do(fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait returns a channel that you can wait on for the ack message. The return
|
||||||
|
// channel closes on the first Ack it receives. Subsequent Ack's have no effect.
|
||||||
|
func (obj *EasyAckOnce) Wait() <-chan struct{} {
|
||||||
|
return obj.done
|
||||||
|
}
|
||||||
|
|
||||||
// EasyExit is a struct that helps you build a close switch and signal which can
|
// EasyExit is a struct that helps you build a close switch and signal which can
|
||||||
// be called multiple times safely, and used as a signal many times in parallel.
|
// be called multiple times safely, and used as a signal many times in parallel.
|
||||||
// It can also provide a context, if you prefer to use that as a signal instead.
|
// It can also provide a context, if you prefer to use that as a signal instead.
|
||||||
|
|||||||
@@ -64,6 +64,28 @@ func TestEasyAck3(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEasyAckOnce1(t *testing.T) {
|
||||||
|
eao := NewEasyAckOnce()
|
||||||
|
eao.Ack()
|
||||||
|
eao.Ack() // must not panic
|
||||||
|
eao.Ack()
|
||||||
|
select {
|
||||||
|
case <-eao.Wait(): // we got it!
|
||||||
|
case <-time.After(time.Duration(60) * time.Second):
|
||||||
|
t.Errorf("the Ack did not arrive in time")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEasyAckOnce2(t *testing.T) {
|
||||||
|
eao := NewEasyAckOnce()
|
||||||
|
// never send an ack
|
||||||
|
select {
|
||||||
|
case <-eao.Wait(): // we got it!
|
||||||
|
t.Errorf("the Ack arrived unexpectedly")
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func ExampleSubscribeSync() {
|
func ExampleSubscribeSync() {
|
||||||
fmt.Println("hello")
|
fmt.Println("hello")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user