github.com/chain5j/chain5j-pkg@v1.0.7/pool/groupwork/group.go (about)

     1  // Package groupwork
     2  //
     3  // @author: xwc1125
     4  package groupwork
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"runtime"
    10  	"sync"
    11  
    12  	"github.com/chain5j/chain5j-pkg/pool/pool"
    13  	"github.com/chain5j/logger"
    14  )
    15  
    16  type Group struct {
    17  	pool *pool.Pool
    18  
    19  	cancel func()
    20  
    21  	wg sync.WaitGroup
    22  
    23  	errOnce sync.Once
    24  	err     error
    25  
    26  	okOnce sync.Once
    27  	ok     interface{}
    28  }
    29  
    30  func WithContext(ctx context.Context, poolSize int) (*Group, context.Context) {
    31  	ctx, cancel := context.WithCancel(ctx)
    32  	newPool, _ := pool.NewPool(poolSize)
    33  	return &Group{
    34  		cancel: cancel,
    35  		pool:   newPool,
    36  	}, ctx
    37  }
    38  
    39  func (g *Group) WaitErr() error {
    40  	g.wg.Wait()
    41  	if g.cancel != nil {
    42  		g.cancel()
    43  	}
    44  	return g.err
    45  }
    46  func (g *Group) WaitOk() interface{} {
    47  	g.wg.Wait()
    48  	if g.cancel != nil {
    49  		g.cancel()
    50  	}
    51  	return g.ok
    52  }
    53  
    54  func (g *Group) OnceErr(f func() error) {
    55  	g.wg.Add(1)
    56  	g.pool.Submit(func() {
    57  		defer g.wg.Done()
    58  
    59  		if err := f(); err != nil {
    60  			g.errOnce.Do(func() {
    61  				g.err = err
    62  				if g.cancel != nil {
    63  					g.cancel()
    64  				}
    65  			})
    66  		}
    67  	})
    68  }
    69  func (g *Group) OnceOk(f func() (interface{}, error)) {
    70  	g.wg.Add(1)
    71  	g.pool.Submit(func() {
    72  		defer g.wg.Done()
    73  
    74  		if data, err := f(); err == nil {
    75  			g.okOnce.Do(func() {
    76  				g.ok = data
    77  				if g.cancel != nil {
    78  					g.cancel()
    79  				}
    80  			})
    81  		}
    82  	})
    83  }
    84  
    85  func GoAndWaitErr(handlers ...func() error) (err error) {
    86  	var wg sync.WaitGroup
    87  	var once sync.Once
    88  	for _, f := range handlers {
    89  		wg.Add(1)
    90  		go func(handler func() error) {
    91  			defer func() {
    92  				if e := recover(); e != nil {
    93  					buf := make([]byte, 1024)
    94  					buf = buf[:runtime.Stack(buf, false)]
    95  					logger.Error("[PANIC]%v\n%s\n", e, buf)
    96  					once.Do(func() {
    97  						err = errors.New("panic found in call handlers")
    98  					})
    99  				}
   100  				wg.Done()
   101  			}()
   102  			if e := handler(); e != nil {
   103  				once.Do(func() {
   104  					err = e
   105  				})
   106  			}
   107  		}(f)
   108  	}
   109  	wg.Wait()
   110  	return err
   111  }
   112  func GoAndWaitOk(handlers ...func() (interface{}, error)) (result interface{}, err error) {
   113  	var wg sync.WaitGroup
   114  	var once sync.Once
   115  	for _, f := range handlers {
   116  		wg.Add(1)
   117  		go func(handler func() (interface{}, error)) {
   118  			defer func() {
   119  				if e := recover(); e != nil {
   120  					buf := make([]byte, 1024)
   121  					buf = buf[:runtime.Stack(buf, false)]
   122  					logger.Error("[PANIC]%v\n%s\n", e, buf)
   123  					err = errors.New("panic found in call handlers")
   124  				}
   125  				wg.Done()
   126  			}()
   127  			if f, e := handler(); e == nil {
   128  				once.Do(func() {
   129  					result = f
   130  				})
   131  			}
   132  		}(f)
   133  	}
   134  	wg.Wait()
   135  	return result, err
   136  }