diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go index 1238de92f..8387168ea 100644 --- a/cmd/cgr-engine/cgr-engine.go +++ b/cmd/cgr-engine/cgr-engine.go @@ -19,6 +19,7 @@ along with this program. If not, see package main import ( + "flag" "fmt" "log" "os" @@ -26,6 +27,8 @@ import ( "path/filepath" "runtime" "runtime/pprof" + "strconv" + "strings" "sync" "syscall" "time" @@ -35,6 +38,7 @@ import ( "github.com/cgrates/cgrates/apis" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/cores" + "github.com/cgrates/cgrates/engine" "github.com/cgrates/cgrates/services" "github.com/cgrates/cgrates/servmanager" "github.com/cgrates/cgrates/utils" @@ -46,30 +50,97 @@ func main() { } } +type flags struct { + *flag.FlagSet + config struct { + path string + check bool + version bool + } + process struct { + pidFile string + singleCPU bool + scheduledShutdown time.Duration + } + profiling struct { + cpu struct { + dir string + } + mem struct { + dir string + interval time.Duration + maxFiles int + useTS bool + } + } + logger struct { + level int + nodeID string + typ string // syslog|stdout|kafkaLog + } + data struct { + preloadIDs []string + setVersions bool + } +} + +func newFlags() *flags { + f := &flags{ + FlagSet: flag.NewFlagSet("cgr-engine", flag.ExitOnError), + } + + f.StringVar(&f.config.path, utils.CfgPathCgr, utils.ConfigPath, "Configuration directory path") + f.BoolVar(&f.config.check, utils.CheckCfgCgr, false, "Verify the config without starting the engine") + f.BoolVar(&f.config.version, utils.VersionCgr, false, "Print application version and exit") + + f.StringVar(&f.process.pidFile, utils.PidCgr, "", "Path to write the PID file") + f.BoolVar(&f.process.singleCPU, utils.SingleCpuCgr, false, "Run on a single CPU core") + f.DurationVar(&f.process.scheduledShutdown, utils.ScheduledShutdownCgr, 0, "Shutdown the engine after the specified duration") + + f.StringVar(&f.profiling.cpu.dir, utils.CpuProfDirCgr, "", "Directory for CPU profiles") + f.StringVar(&f.profiling.mem.dir, utils.MemProfDirCgr, "", "Directory for memory profiles") + f.DurationVar(&f.profiling.mem.interval, utils.MemProfIntervalCgr, 15*time.Second, "Interval between memory profile saves") + f.IntVar(&f.profiling.mem.maxFiles, utils.MemProfMaxFilesCgr, 1, "Number of memory profiles to keep (most recent)") + f.BoolVar(&f.profiling.mem.useTS, utils.MemProfTimestampCgr, false, "Add timestamp to memory profile files") + + f.IntVar(&f.logger.level, utils.LogLevelCfg, -1, "Log level (0=emergency to 7=debug)") + f.StringVar(&f.logger.nodeID, utils.NodeIDCfg, "", "Node ID of the engine") + f.StringVar(&f.logger.typ, utils.LoggerCfg, "", "Logger type <*syslog|*stdout|*kafkaLog>") + + f.Func(utils.PreloadCgr, "Loader IDs used to load data before engine starts", func(val string) error { + f.data.preloadIDs = strings.Split(val, utils.FieldsSep) + return nil + }) + f.BoolVar(&f.data.setVersions, utils.SetVersionsCgr, false, "Overwrite database versions") + + return f +} + // runCGREngine configures the CGREngine object and runs it func runCGREngine(fs []string) (err error) { - flags := services.NewCGREngineFlags() + flags := newFlags() flags.Parse(fs) + var vers string if vers, err = utils.GetCGRVersion(); err != nil { return } - if *flags.Version { + if flags.config.version { fmt.Println(vers) return } - if *flags.PidFile != utils.EmptyString { - if err = services.CgrWritePid(*flags.PidFile); err != nil { + if flags.process.pidFile != utils.EmptyString { + if err = writePIDFile(flags.process.pidFile); err != nil { return } } - if *flags.SingleCPU { + if flags.process.singleCPU { runtime.GOMAXPROCS(1) // Having multiple cpus may slow down computing due to CPU management, to be reviewed in future Go releases } var cfg *config.CGRConfig - if cfg, err = services.InitConfigFromPath(context.TODO(), *flags.CfgPath, *flags.NodeID, - *flags.Logger, *flags.LogLevel); err != nil || *flags.CheckConfig { + if cfg, err = initConfigFromPath(context.TODO(), flags.config.path, flags.logger.nodeID, + flags.logger.typ, flags.logger.level); err != nil || flags.config.check { return } @@ -90,8 +161,8 @@ func runCGREngine(fs []string) (err error) { } var cpuPrfF *os.File - if *flags.CpuPrfDir != utils.EmptyString { - cpuPath := filepath.Join(*flags.CpuPrfDir, utils.CpuPathCgr) + if flags.profiling.cpu.dir != utils.EmptyString { + cpuPath := filepath.Join(flags.profiling.cpu.dir, utils.CpuPathCgr) if cpuPrfF, err = cores.StartCPUProfiling(cpuPath); err != nil { return } @@ -102,15 +173,11 @@ func runCGREngine(fs []string) (err error) { shutdown := utils.NewSyncedChan() go handleSignals(shutdown, cfg, shdWg) - if *flags.ScheduledShutdown != utils.EmptyString { - var shtDwDur time.Duration - if shtDwDur, err = utils.ParseDurationWithNanosecs(*flags.ScheduledShutdown); err != nil { - return - } + if flags.process.scheduledShutdown != 0 { shdWg.Add(1) go func() { // Schedule shutdown defer shdWg.Done() - tm := time.NewTimer(shtDwDur) + tm := time.NewTimer(flags.process.scheduledShutdown) select { case <-tm.C: shutdown.CloseOnce() @@ -132,15 +199,15 @@ func runCGREngine(fs []string) (err error) { services.NewCommonListenerService(cfg), services.NewAnalyzerService(cfg), services.NewConnManagerService(cfg), - services.NewLoggerService(cfg, *flags.Logger), - services.NewDataDBService(cfg, *flags.SetVersions), - services.NewStorDBService(cfg, *flags.SetVersions), + services.NewLoggerService(cfg, flags.logger.typ), + services.NewDataDBService(cfg, flags.data.setVersions), + services.NewStorDBService(cfg, flags.data.setVersions), services.NewConfigService(cfg), services.NewGuardianService(cfg), coreS, services.NewCacheService(cfg), services.NewFilterService(cfg), - services.NewLoaderService(cfg, *flags.Preload), + services.NewLoaderService(cfg, flags.data.preloadIDs), services.NewExportFailoverService(cfg), services.NewAdminSv1Service(cfg), services.NewSessionService(cfg), @@ -182,8 +249,8 @@ func runCGREngine(fs []string) (err error) { utils.Logger.Err(fmt.Sprintf("<%s> failed to shut down all services in the given time", utils.ServiceManager)) } - if *flags.PidFile != utils.EmptyString { - if err := os.Remove(*flags.PidFile); err != nil { + if flags.process.pidFile != utils.EmptyString { + if err := os.Remove(flags.process.pidFile); err != nil { utils.Logger.Warning("Could not remove pid file: " + err.Error()) } } @@ -201,18 +268,18 @@ func runCGREngine(fs []string) (err error) { }() srvManager.StartServices(shutdown) - cgrInitServiceManagerV1(cfg, srvManager, registry) + initServiceManagerV1(cfg, srvManager, registry) // Serve rpc connections - cgrStartRPC(cfg, registry, shutdown) + startRPC(cfg, registry, shutdown) // TODO: find a better location for this if block - if *flags.MemPrfDir != "" { + if flags.profiling.mem.dir != "" { if err := coreS.CoreS().StartMemoryProfiling(cores.MemoryProfilingParams{ - DirPath: *flags.MemPrfDir, - MaxFiles: *flags.MemPrfMaxF, - Interval: *flags.MemPrfInterval, - UseTimestamp: *flags.MemPrfTS, + DirPath: flags.profiling.mem.dir, + MaxFiles: flags.profiling.mem.maxFiles, + Interval: flags.profiling.mem.interval, + UseTimestamp: flags.profiling.mem.useTS, }); err != nil { utils.Logger.Err(fmt.Sprintf("<%s> %v", utils.CoreS, err)) } @@ -222,27 +289,59 @@ func runCGREngine(fs []string) (err error) { return } -func cgrInitServiceManagerV1(cfg *config.CGRConfig, srvMngr *servmanager.ServiceManager, - registry *servmanager.ServiceRegistry) { - srvDeps, err := services.WaitForServicesToReachState(utils.StateServiceUP, - []string{ - utils.CommonListenerS, - utils.ConnManager, - }, - registry, cfg.GeneralCfg().ConnectTimeout) +func writePIDFile(path string) error { + f, err := os.Create(path) if err != nil { - return + return fmt.Errorf("failed to create pid file: %s", err) } - cl := srvDeps[utils.CommonListenerS].(*services.CommonListenerService).CLS() - cms := srvDeps[utils.ConnManager].(*services.ConnManagerService) - srv, _ := birpc.NewService(apis.NewServiceManagerV1(srvMngr), utils.EmptyString, false) - cl.RpcRegister(srv) - cms.AddInternalConn(utils.ServiceManager, srv) + if _, err := f.WriteString(strconv.Itoa(os.Getpid())); err != nil { + f.Close() + return fmt.Errorf("failed to write to pid file: %s", err) + } + if err := f.Close(); err != nil { + return fmt.Errorf("failed to close pid file: %s", err) + } + return nil } -func cgrStartRPC(cfg *config.CGRConfig, registry *servmanager.ServiceRegistry, shutdown *utils.SyncedChan) { - cl := registry.Lookup(utils.CommonListenerS).(*services.CommonListenerService).CLS() - cl.StartServer(cfg, shutdown) +func initConfigFromPath(ctx *context.Context, path, nodeID, logType string, logLevel int) (cfg *config.CGRConfig, err error) { + // Init config + if cfg, err = config.NewCGRConfigFromPath(ctx, path); err != nil { + err = fmt.Errorf("could not parse config: <%s>", err) + return + } + if cfg.ConfigDBCfg().Type != utils.MetaInternal { + var d config.ConfigDB + if d, err = engine.NewDataDBConn(cfg.ConfigDBCfg().Type, + cfg.ConfigDBCfg().Host, cfg.ConfigDBCfg().Port, + cfg.ConfigDBCfg().Name, cfg.ConfigDBCfg().User, + cfg.ConfigDBCfg().Password, cfg.GeneralCfg().DBDataEncoding, + cfg.ConfigDBCfg().Opts, nil); err != nil { // Cannot configure getter database, show stopper + err = fmt.Errorf("could not configure configDB: <%s>", err) + return + } + if err = cfg.LoadFromDB(ctx, d); err != nil { + err = fmt.Errorf("could not parse config from DB: <%s>", err) + return + } + } + if nodeID != utils.EmptyString { + cfg.GeneralCfg().NodeID = nodeID + } + if logLevel != -1 { // Modify the log level if provided by command arguments + cfg.LoggerCfg().Level = logLevel + } + if logType != utils.EmptyString { + cfg.LoggerCfg().Type = logType + } + if utils.ConcurrentReqsLimit != 0 { // used as shared variable + cfg.CoreSCfg().Caps = utils.ConcurrentReqsLimit + } + if len(utils.ConcurrentReqsStrategy) != 0 { + cfg.CoreSCfg().CapsStrategy = utils.ConcurrentReqsStrategy + } + config.SetCgrConfig(cfg) // Share the config object + return } func handleSignals(shutdown *utils.SyncedChan, cfg *config.CGRConfig, shdWg *sync.WaitGroup) { @@ -271,3 +370,26 @@ func handleSignals(shutdown *utils.SyncedChan, cfg *config.CGRConfig, shdWg *syn } } } + +func initServiceManagerV1(cfg *config.CGRConfig, srvMngr *servmanager.ServiceManager, + registry *servmanager.ServiceRegistry) { + srvDeps, err := services.WaitForServicesToReachState(utils.StateServiceUP, + []string{ + utils.CommonListenerS, + utils.ConnManager, + }, + registry, cfg.GeneralCfg().ConnectTimeout) + if err != nil { + return + } + cl := srvDeps[utils.CommonListenerS].(*services.CommonListenerService).CLS() + cms := srvDeps[utils.ConnManager].(*services.ConnManagerService) + srv, _ := birpc.NewService(apis.NewServiceManagerV1(srvMngr), utils.EmptyString, false) + cl.RpcRegister(srv) + cms.AddInternalConn(utils.ServiceManager, srv) +} + +func startRPC(cfg *config.CGRConfig, registry *servmanager.ServiceRegistry, shutdown *utils.SyncedChan) { + cl := registry.Lookup(utils.CommonListenerS).(*services.CommonListenerService).CLS() + cl.StartServer(cfg, shutdown) +} diff --git a/cmd/cgr-engine/flag_test.go b/cmd/cgr-engine/flag_test.go new file mode 100644 index 000000000..9affd0dc2 --- /dev/null +++ b/cmd/cgr-engine/flag_test.go @@ -0,0 +1,172 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package main + +import ( + "path" + "reflect" + "testing" + "time" +) + +// If any flag changes, this test should fail. +// Do not use constants in this test to ensure these changes are detected. +func TestFlags(t *testing.T) { + flags := newFlags() + tests := []struct { + name string + flags []string + flagVar any + defaultVal any + want any + }{ + { + name: "config_path", + flags: []string{"-config_path", path.Join("/usr", "share", "cgrates", "conf", "samples", "tutorial")}, + flagVar: &flags.config.path, + defaultVal: "/etc/cgrates/", + want: "/usr/share/cgrates/conf/samples/tutorial", + }, + { + name: "version", + flags: []string{"-version"}, + flagVar: &flags.config.version, + defaultVal: false, + want: true, + }, + { + name: "pid", + flags: []string{"-pid", "/run/cgrates/cgrates.pid"}, + flagVar: &flags.process.pidFile, + defaultVal: "", + want: "/run/cgrates/cgrates.pid", + }, + { + name: "cpuprof_dir", + flags: []string{"-cpuprof_dir", "/tmp/profiling"}, + flagVar: &flags.profiling.cpu.dir, + defaultVal: "", + want: "/tmp/profiling", + }, + { + name: "memprof_dir", + flags: []string{"-memprof_dir", "/tmp/profiling"}, + flagVar: &flags.profiling.mem.dir, + defaultVal: "", + want: "/tmp/profiling", + }, + { + name: "memprof_interval", + flags: []string{"-memprof_interval", "1s"}, + flagVar: &flags.profiling.mem.interval, + defaultVal: 15 * time.Second, + want: time.Second, + }, + { + name: "memprof_maxfiles", + flags: []string{"-memprof_maxfiles", "3"}, + flagVar: &flags.profiling.mem.maxFiles, + defaultVal: 1, + want: 3, + }, + { + name: "memprof_timestamp", + flags: []string{"-memprof_timestamp"}, + flagVar: &flags.profiling.mem.useTS, + defaultVal: false, + want: true, + }, + { + name: "scheduled_shutdown", + flags: []string{"-scheduled_shutdown", "1h"}, + flagVar: &flags.process.scheduledShutdown, + defaultVal: time.Duration(0), + want: time.Hour, + }, + { + name: "single_cpu", + flags: []string{"-single_cpu"}, + flagVar: &flags.process.singleCPU, + defaultVal: false, + want: true, + }, + { + name: "logger", + flags: []string{"-logger", "*stdout"}, + flagVar: &flags.logger.typ, + defaultVal: "", + want: "*stdout", + }, + { + name: "node_id", + flags: []string{"-node_id", "CGRateS.org"}, + flagVar: &flags.logger.nodeID, + defaultVal: "", + want: "CGRateS.org", + }, + { + name: "log_level", + flags: []string{"-log_level", "7"}, + flagVar: &flags.logger.level, + defaultVal: -1, + want: 7, + }, + { + name: "check_config", + flags: []string{"-check_config", "true"}, + flagVar: &flags.config.check, + defaultVal: false, + want: true, + }, + { + name: "set_versions", + flags: []string{"-set_versions"}, + flagVar: &flags.data.setVersions, + defaultVal: false, + want: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + flagVal := reflect.ValueOf(tt.flagVar).Elem().Interface() + if flagVal != tt.defaultVal { + t.Errorf("%s=%v, want default value %v", tt.name, flagVal, tt.defaultVal) + } + if err := flags.Parse(tt.flags); err != nil { + t.Errorf("flags.Parse(%v) returned unexpected error: %v", tt.flags, err) + } + flagVal = reflect.ValueOf(tt.flagVar).Elem().Interface() + if flagVal != tt.want { + t.Errorf("%s=%v, want %v", tt.name, flagVal, tt.want) + } + }) + } +} + +func TestPreloadFlag(t *testing.T) { + flg := newFlags() + if err := flg.Parse([]string{"-preload", "loader1,loader2"}); err != nil { + t.Fatal(err) + } + want := []string{"loader1", "loader2"} + if !reflect.DeepEqual(flg.data.preloadIDs, want) { + t.Errorf("preload IDs = %v, want %v", flg.data.preloadIDs, want) + } +} diff --git a/services/libcgr-engine.go b/services/libcgr-engine.go deleted file mode 100644 index 5ecf6064c..000000000 --- a/services/libcgr-engine.go +++ /dev/null @@ -1,143 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package services - -import ( - "flag" - "fmt" - "os" - "strconv" - "time" - - "github.com/cgrates/birpc/context" - "github.com/cgrates/cgrates/config" - "github.com/cgrates/cgrates/engine" - "github.com/cgrates/cgrates/utils" -) - -func NewCGREngineFlags() *CGREngineFlags { - fs := flag.NewFlagSet(utils.CgrEngine, flag.ExitOnError) - return &CGREngineFlags{ - FlagSet: fs, - CfgPath: fs.String(utils.CfgPathCgr, utils.ConfigPath, "Configuration directory path"), - Version: fs.Bool(utils.VersionCgr, false, "Print application version and exit"), - PidFile: fs.String(utils.PidCgr, utils.EmptyString, "Path to write the PID file"), - CpuPrfDir: fs.String(utils.CpuProfDirCgr, utils.EmptyString, "Directory for CPU profiles"), - MemPrfDir: fs.String(utils.MemProfDirCgr, utils.EmptyString, "Directory for memory profiles"), - MemPrfInterval: fs.Duration(utils.MemProfIntervalCgr, 15*time.Second, "Interval between memory profile saves"), - MemPrfMaxF: fs.Int(utils.MemProfMaxFilesCgr, 1, "Number of memory profiles to keep (most recent)"), - MemPrfTS: fs.Bool(utils.MemProfTimestampCgr, false, "Add timestamp to memory profile files"), - ScheduledShutdown: fs.String(utils.ScheduledShutdownCgr, utils.EmptyString, "Shutdown the engine after the specified duration"), - SingleCPU: fs.Bool(utils.SingleCpuCgr, false, "Run on a single CPU core"), - Logger: fs.String(utils.LoggerCfg, utils.EmptyString, "Logger type <*syslog|*stdout|*kafkaLog>"), - NodeID: fs.String(utils.NodeIDCfg, utils.EmptyString, "Node ID of the engine"), - LogLevel: fs.Int(utils.LogLevelCfg, -1, "Log level (0=emergency to 7=debug)"), - Preload: fs.String(utils.PreloadCgr, utils.EmptyString, "Loader IDs used to load data before engine starts"), - CheckConfig: fs.Bool(utils.CheckCfgCgr, false, "Verify the config without starting the engine"), - SetVersions: fs.Bool(utils.SetVersionsCgr, false, "Overwrite database versions (equivalent to cgr-migrator -exec=*set_versions)"), - } -} - -type CGREngineFlags struct { - *flag.FlagSet - - CfgPath *string - Version *bool - PidFile *string - CpuPrfDir *string - MemPrfDir *string - MemPrfInterval *time.Duration - MemPrfMaxF *int - MemPrfTS *bool - ScheduledShutdown *string - SingleCPU *bool - Logger *string - NodeID *string - LogLevel *int - Preload *string - CheckConfig *bool - SetVersions *bool -} - -func CgrWritePid(pidFile string) (err error) { - var f *os.File - if f, err = os.Create(pidFile); err != nil { - err = fmt.Errorf("could not create pid file: %s", err) - return - } - if _, err = f.WriteString(strconv.Itoa(os.Getpid())); err != nil { - f.Close() - err = fmt.Errorf("could not write pid file: %s", err) - return - } - if err = f.Close(); err != nil { - err = fmt.Errorf("could not close pid file: %s", err) - } - return -} - -func waitForFilterS(ctx *context.Context, fsCh chan *engine.FilterS) (filterS *engine.FilterS, err error) { - select { - case <-ctx.Done(): - err = ctx.Err() - case filterS = <-fsCh: - fsCh <- filterS - } - return -} - -func InitConfigFromPath(ctx *context.Context, path, nodeID, logType string, logLevel int) (cfg *config.CGRConfig, err error) { - // Init config - if cfg, err = config.NewCGRConfigFromPath(ctx, path); err != nil { - err = fmt.Errorf("could not parse config: <%s>", err) - return - } - if cfg.ConfigDBCfg().Type != utils.MetaInternal { - var d config.ConfigDB - if d, err = engine.NewDataDBConn(cfg.ConfigDBCfg().Type, - cfg.ConfigDBCfg().Host, cfg.ConfigDBCfg().Port, - cfg.ConfigDBCfg().Name, cfg.ConfigDBCfg().User, - cfg.ConfigDBCfg().Password, cfg.GeneralCfg().DBDataEncoding, - cfg.ConfigDBCfg().Opts, nil); err != nil { // Cannot configure getter database, show stopper - err = fmt.Errorf("could not configure configDB: <%s>", err) - return - } - if err = cfg.LoadFromDB(ctx, d); err != nil { - err = fmt.Errorf("could not parse config from DB: <%s>", err) - return - } - } - if nodeID != utils.EmptyString { - cfg.GeneralCfg().NodeID = nodeID - } - if logLevel != -1 { // Modify the log level if provided by command arguments - cfg.LoggerCfg().Level = logLevel - } - if logType != utils.EmptyString { - cfg.LoggerCfg().Type = logType - } - if utils.ConcurrentReqsLimit != 0 { // used as shared variable - cfg.CoreSCfg().Caps = utils.ConcurrentReqsLimit - } - if len(utils.ConcurrentReqsStrategy) != 0 { - cfg.CoreSCfg().CapsStrategy = utils.ConcurrentReqsStrategy - } - config.SetCgrConfig(cfg) // Share the config object - return -} diff --git a/services/libcgr-engine_test.go b/services/libcgr-engine_test.go deleted file mode 100644 index 73d34f777..000000000 --- a/services/libcgr-engine_test.go +++ /dev/null @@ -1,168 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package services - -// import ( -// "path" -// "reflect" -// "testing" -// "time" -// ) -// -// // If any flag changes, this test should fail. -// // Do not use constants in this test to ensure these changes are detected. -// func TestCgrEngineFlags(t *testing.T) { -// ngFlags := NewCGREngineFlags() -// tests := []struct { -// name string -// flags []string -// flagVar any -// defaultVal any -// want any -// }{ -// { -// name: "cfgPath", -// flags: []string{"-config_path", path.Join("/usr", "share", "cgrates", "conf", "samples", "tutorial")}, -// flagVar: ngFlags.CfgPath, -// defaultVal: "/etc/cgrates/", -// want: "/usr/share/cgrates/conf/samples/tutorial", -// }, -// { -// name: "version", -// flags: []string{"-version"}, -// flagVar: ngFlags.Version, -// defaultVal: false, -// want: true, -// }, -// { -// name: "pidFile", -// flags: []string{"-pid", "/run/cgrates/cgrates.pid"}, -// flagVar: ngFlags.PidFile, -// defaultVal: "", -// want: "/run/cgrates/cgrates.pid", -// }, -// { -// name: "cpuProfDir", -// flags: []string{"-cpuprof_dir", "/tmp/profiling"}, -// flagVar: ngFlags.CpuPrfDir, -// defaultVal: "", -// want: "/tmp/profiling", -// }, -// { -// name: "memProfDir", -// flags: []string{"-memprof_dir", "/tmp/profiling"}, -// flagVar: ngFlags.MemPrfDir, -// defaultVal: "", -// want: "/tmp/profiling", -// }, -// { -// name: "memProfInterval", -// flags: []string{"-memprof_interval", "1s"}, -// flagVar: ngFlags.MemPrfInterval, -// defaultVal: 15 * time.Second, -// want: time.Second, -// }, -// { -// name: "memProfMaxFiles", -// flags: []string{"-memprof_maxfiles", "3"}, -// flagVar: ngFlags.MemPrfMaxF, -// defaultVal: 1, -// want: 3, -// }, -// { -// name: "memProfTimestamp", -// flags: []string{"-memprof_timestamp"}, -// flagVar: ngFlags.MemPrfTS, -// defaultVal: false, -// want: true, -// }, -// { -// name: "scheduledShutdown", -// flags: []string{"-scheduled_shutdown", "1h"}, -// flagVar: ngFlags.ScheduledShutdown, -// defaultVal: "", -// want: "1h", -// }, -// { -// name: "singleCPU", -// flags: []string{"-single_cpu"}, -// flagVar: ngFlags.SingleCPU, -// defaultVal: false, -// want: true, -// }, -// { -// name: "syslogger", -// flags: []string{"-logger", "*stdout"}, -// flagVar: ngFlags.Logger, -// defaultVal: "", -// want: "*stdout", -// }, -// { -// name: "nodeID", -// flags: []string{"-node_id", "CGRateS.org"}, -// flagVar: ngFlags.NodeID, -// defaultVal: "", -// want: "CGRateS.org", -// }, -// { -// name: "logLevel", -// flags: []string{"-log_level", "7"}, -// flagVar: ngFlags.LogLevel, -// defaultVal: -1, -// want: 7, -// }, -// { -// name: "preload", -// flags: []string{"-preload", "TestPreloadID"}, -// flagVar: ngFlags.Preload, -// defaultVal: "", -// want: "TestPreloadID", -// }, -// { -// name: "check_config", -// flags: []string{"-check_config", "true"}, -// flagVar: ngFlags.CheckConfig, -// defaultVal: false, -// want: true, -// }, -// { -// name: "setVersions", -// flags: []string{"-set_versions"}, -// flagVar: ngFlags.SetVersions, -// defaultVal: false, -// want: true, -// }, -// } -// -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// flagVal := reflect.ValueOf(tt.flagVar).Elem().Interface() -// if flagVal != tt.defaultVal { -// t.Errorf("%s=%v, want default value %v", tt.name, flagVal, tt.defaultVal) -// } -// if err := ngFlags.Parse(tt.flags); err != nil { -// t.Errorf("cgrEngineFlags.Parse(%v) returned unexpected error: %v", tt.flags, err) -// } -// flagVal = reflect.ValueOf(tt.flagVar).Elem().Interface() -// if flagVal != tt.want { -// t.Errorf("%s=%v, want %v", tt.name, flagVal, tt.want) -// } -// }) -// } -// } diff --git a/services/loaders.go b/services/loaders.go index 8297e6f4e..103539de8 100644 --- a/services/loaders.go +++ b/services/loaders.go @@ -20,7 +20,6 @@ package services import ( "fmt" - "strings" "sync" "github.com/cgrates/birpc/context" @@ -33,11 +32,11 @@ import ( ) // NewLoaderService returns the Loader Service -func NewLoaderService(cfg *config.CGRConfig, preloadIDs string) *LoaderService { +func NewLoaderService(cfg *config.CGRConfig, preloadIDs []string) *LoaderService { return &LoaderService{ cfg: cfg, stopChan: make(chan struct{}), - preloadIDs: strings.Split(preloadIDs, utils.FieldsSep), + preloadIDs: preloadIDs, stateDeps: NewStateDependencies([]string{utils.StateServiceUP, utils.StateServiceDOWN}), } }