github.com/wfusion/gofusion@v1.1.14/routine/construct.go (about)

     1  package routine
     2  
     3  import (
     4  	"context"
     5  	"log"
     6  	"reflect"
     7  	"syscall"
     8  	"time"
     9  
    10  	"github.com/panjf2000/ants/v2"
    11  	"go.uber.org/atomic"
    12  
    13  	"github.com/wfusion/gofusion/common/utils"
    14  	"github.com/wfusion/gofusion/common/utils/inspect"
    15  	"github.com/wfusion/gofusion/config"
    16  
    17  	fusLog "github.com/wfusion/gofusion/log"
    18  
    19  	_ "github.com/wfusion/gofusion/log/customlogger"
    20  )
    21  
    22  const (
    23  	defaultMaxPoolSize = 10000000
    24  )
    25  
    26  func Construct(ctx context.Context, conf Conf, opts ...utils.OptionExtender) func() {
    27  	opt := utils.ApplyOptions[config.InitOption](opts...)
    28  	optU := utils.ApplyOptions[candyOption](opts...)
    29  	if opt.AppName == "" {
    30  		opt.AppName = optU.appName
    31  	}
    32  
    33  	if conf.MaxRoutineAmount <= 0 {
    34  		conf.MaxRoutineAmount = defaultMaxPoolSize
    35  	}
    36  
    37  	rwlock.Lock()
    38  	defer rwlock.Unlock()
    39  	if pools == nil {
    40  		pools = make(map[string]map[string]Pool)
    41  	}
    42  	if pools[opt.AppName] == nil {
    43  		pools[opt.AppName] = make(map[string]Pool)
    44  	}
    45  	if ignored == nil {
    46  		ignored = make(map[string]*atomic.Int64)
    47  	}
    48  	if ignored[opt.AppName] == nil {
    49  		ignored[opt.AppName] = atomic.NewInt64(0)
    50  	}
    51  	if idles == nil {
    52  		idles = make(map[string]*atomic.Int64)
    53  	}
    54  	if idles[opt.AppName] == nil {
    55  		idles[opt.AppName] = atomic.NewInt64(int64(conf.MaxRoutineAmount))
    56  	}
    57  	if utils.IsStrNotBlank(conf.Logger) {
    58  		if defaultLogger == nil {
    59  			defaultLogger = make(map[string]ants.Logger)
    60  		}
    61  		if defaultLogger[opt.AppName] == nil {
    62  			logger := reflect.New(inspect.TypeOf(conf.Logger)).Interface().(ants.Logger)
    63  			defaultLogger[opt.AppName] = logger
    64  			if custom, ok := logger.(customLogger); ok {
    65  				l := fusLog.Use(conf.LogInstance, fusLog.AppName(opt.AppName))
    66  				custom.Init(l, opt.AppName)
    67  			}
    68  		}
    69  	}
    70  	maxReleaseTime := utils.Must(time.ParseDuration(conf.MaxReleaseTimePerPool))
    71  
    72  	go startDaemonRoutines(ctx, opt.AppName, &conf)
    73  
    74  	return func() {
    75  		rwlock.Lock()
    76  		defer rwlock.Unlock()
    77  
    78  		pid := syscall.Getpid()
    79  		app := config.Use(opt.AppName).AppName()
    80  		allExited := func() bool {
    81  			return idles[opt.AppName].Load() == int64(conf.MaxRoutineAmount)-ignored[opt.AppName].Load()
    82  		}
    83  
    84  		// waiting for pool
    85  		if pools != nil {
    86  			for name, pool := range pools[opt.AppName] {
    87  				if err := pool.ReleaseTimeout(maxReleaseTime, ignoreMutex()); err != nil {
    88  					log.Printf("%v [Gofusion] %s %s exit with releasing pool %s failed because %s",
    89  						pid, app, config.ComponentGoroutinePool, name, err)
    90  				}
    91  				delete(pools[opt.AppName], name)
    92  			}
    93  		}
    94  
    95  		log.Printf("%v [Gofusion] %s %s pool routines are recycled", pid, app, config.ComponentGoroutinePool)
    96  
    97  		// waiting for go
    98  		utils.Timeout(maxReleaseTime, utils.TimeoutWg(&wg))
    99  		log.Printf("%v [Gofusion] %s %s go routines are recycled", pid, app, config.ComponentGoroutinePool)
   100  
   101  		if !allExited() {
   102  			log.Printf("%v [Gofusion] %s %s exit without all goroutines recycled [exists%v]",
   103  				pid, app, config.ComponentGoroutinePool, showRoutine(opt.AppName))
   104  		}
   105  
   106  		delete(ignored, opt.AppName)
   107  		delete(idles, opt.AppName)
   108  		delete(routines, opt.AppName)
   109  	}
   110  }
   111  
   112  func configs(appName string) (conf Conf) {
   113  	_ = config.Use(appName).LoadComponentConfig(config.ComponentGoroutinePool, &conf)
   114  	return
   115  }
   116  
   117  func forceSync(appName string) bool {
   118  	return configs(appName).ForceSync
   119  }
   120  
   121  func init() {
   122  	config.AddComponent(config.ComponentGoroutinePool, Construct, config.WithFlag(&flagString))
   123  }