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

     1  package cron
     2  
     3  import (
     4  	"context"
     5  	"log"
     6  	"sync"
     7  	"syscall"
     8  
     9  	"github.com/pkg/errors"
    10  
    11  	"github.com/wfusion/gofusion/common/di"
    12  	"github.com/wfusion/gofusion/common/utils"
    13  	"github.com/wfusion/gofusion/config"
    14  
    15  	_ "github.com/wfusion/gofusion/log/customlogger"
    16  )
    17  
    18  var (
    19  	locker  sync.RWMutex
    20  	routers map[string]map[string]IRouter
    21  )
    22  
    23  func Construct(ctx context.Context, confs map[string]*Conf, opts ...utils.OptionExtender) func() {
    24  	opt := utils.ApplyOptions[config.InitOption](opts...)
    25  	optU := utils.ApplyOptions[useOption](opts...)
    26  	if opt.AppName == "" {
    27  		opt.AppName = optU.appName
    28  	}
    29  
    30  	for name, conf := range confs {
    31  		addInstance(ctx, name, conf, opt)
    32  	}
    33  	return func() {
    34  		locker.Lock()
    35  		defer locker.Unlock()
    36  
    37  		pid := syscall.Getpid()
    38  		app := config.Use(opt.AppName).AppName()
    39  		if routers != nil {
    40  			for name, router := range routers[opt.AppName] {
    41  				log.Printf("%v [Gofusion] %s %s %s exiting...", pid, app, config.ComponentCron, name)
    42  				if err := router.shutdown(); err == nil {
    43  					log.Printf("%v [Gofusion] %s %s %s exited", pid, app, config.ComponentCron, name)
    44  				} else {
    45  					log.Printf("%v [Gofusion] %s %s %s exit failed: %s", pid, app, config.ComponentCron, name, err)
    46  				}
    47  			}
    48  			delete(routers, opt.AppName)
    49  		}
    50  	}
    51  }
    52  
    53  func addInstance(ctx context.Context, name string, conf *Conf, opt *config.InitOption) {
    54  	var r IRouter
    55  	switch conf.Type {
    56  	case schedulerTypeAsynq:
    57  		r = newAsynq(ctx, opt.AppName, name, conf)
    58  	default:
    59  		panic(ErrUnsupportedSchedulerType)
    60  	}
    61  
    62  	locker.Lock()
    63  	defer locker.Unlock()
    64  	if routers == nil {
    65  		routers = make(map[string]map[string]IRouter)
    66  	}
    67  	if routers[opt.AppName] == nil {
    68  		routers[opt.AppName] = make(map[string]IRouter)
    69  	}
    70  	if _, ok := routers[opt.AppName][name]; ok {
    71  		panic(errors.Errorf("duplicated cron name: %s", name))
    72  	}
    73  	routers[opt.AppName][name] = r
    74  
    75  	// ioc
    76  	if opt.DI != nil {
    77  		opt.DI.MustProvide(
    78  			func() IRouter { return Use(name, AppName(opt.AppName)) },
    79  			di.Name(name),
    80  		)
    81  	}
    82  }
    83  
    84  type useOption struct {
    85  	appName string
    86  }
    87  
    88  func AppName(name string) utils.OptionFunc[useOption] {
    89  	return func(o *useOption) {
    90  		o.appName = name
    91  	}
    92  }
    93  
    94  func Use(name string, opts ...utils.OptionExtender) IRouter {
    95  	opt := utils.ApplyOptions[useOption](opts...)
    96  
    97  	locker.RLock()
    98  	defer locker.RUnlock()
    99  	routers, ok := routers[opt.appName]
   100  	if !ok {
   101  		panic(errors.Errorf("cron router instance not found for app: %s", opt.appName))
   102  	}
   103  
   104  	router, ok := routers[name]
   105  	if !ok {
   106  		panic(errors.Errorf("cron router instance not found for name: %s", name))
   107  	}
   108  	return router
   109  }
   110  
   111  func init() {
   112  	config.AddComponent(config.ComponentCron, Construct, config.WithFlag(&flagString))
   113  }