You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

109 lines
1.7 KiB

package async
import (
"context"
"os"
"os/signal"
"sync"
)
// Option configure async closer.
type Option func(*Closer)
// WithHandleError configure async error handler.
func WithHandleError(he func(error)) Option {
return func(async *Closer) {
async.handler = he
}
}
// New create new closer with options.
func New(opts ...Option) *Closer {
a := &Closer{}
for _, o := range opts {
o(a)
}
return a
}
// Closer closer.
type Closer struct {
sync.Mutex
once sync.Once
done chan struct{}
fnc []func() error
handler func(error)
}
// Wait when done context or notify signals or close all.
func (c *Closer) Wait(ctx context.Context, sig ...os.Signal) {
go func() {
ch := make(chan os.Signal, 1)
if len(sig) > 0 {
signal.Notify(ch, sig...)
defer signal.Stop(ch)
}
select {
case <-ch:
case <-ctx.Done():
}
_ = c.Close()
}()
<-c.wait()
}
func (c *Closer) wait() chan struct{} {
c.Lock()
if c.done == nil {
c.done = make(chan struct{})
}
c.Unlock()
return c.done
}
// Add close functions.
func (c *Closer) Add(f ...func() error) {
c.Lock()
c.fnc = append(c.fnc, f...)
c.Unlock()
}
// Close close all closers async.
func (c *Closer) Close() error {
c.once.Do(func() {
defer close(c.wait())
c.Lock()
eh := func(error) {}
if c.handler != nil {
eh = c.handler
}
funcs := c.fnc
c.fnc = nil
c.Unlock()
errs := make(chan error, len(funcs))
for _, f := range funcs {
go func(f func() error) {
errs <- f()
}(f)
}
for i := 0; i < cap(errs); i++ {
if err := <-errs; err != nil {
eh(err)
}
}
})
return nil
}
func (c *Closer) SetErrHandler(e func(error)) {
c.Lock()
c.handler = e
c.Unlock()
}