mirror of
				https://github.com/openimsdk/open-im-server.git
				synced 2025-10-29 23:38:11 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			107 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			107 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package etcd
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"os"
 | |
| 	"os/exec"
 | |
| 	"runtime"
 | |
| 	"sync"
 | |
| 	"syscall"
 | |
| 
 | |
| 	"github.com/openimsdk/tools/errs"
 | |
| 	"github.com/openimsdk/tools/log"
 | |
| 	"github.com/openimsdk/tools/utils/datautil"
 | |
| 	clientv3 "go.etcd.io/etcd/client/v3"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	ShutDowns []func() error
 | |
| )
 | |
| 
 | |
| func RegisterShutDown(shutDown ...func() error) {
 | |
| 	ShutDowns = append(ShutDowns, shutDown...)
 | |
| }
 | |
| 
 | |
| type ConfigManager struct {
 | |
| 	client           *clientv3.Client
 | |
| 	watchConfigNames []string
 | |
| 	lock             sync.Mutex
 | |
| }
 | |
| 
 | |
| func BuildKey(s string) string {
 | |
| 	return ConfigKeyPrefix + s
 | |
| }
 | |
| 
 | |
| func NewConfigManager(client *clientv3.Client, configNames []string) *ConfigManager {
 | |
| 	return &ConfigManager{
 | |
| 		client:           client,
 | |
| 		watchConfigNames: datautil.Batch(func(s string) string { return BuildKey(s) }, append(configNames, RestartKey))}
 | |
| }
 | |
| 
 | |
| func (c *ConfigManager) Watch(ctx context.Context) {
 | |
| 	chans := make([]clientv3.WatchChan, 0, len(c.watchConfigNames))
 | |
| 	for _, name := range c.watchConfigNames {
 | |
| 		chans = append(chans, c.client.Watch(ctx, name, clientv3.WithPrefix()))
 | |
| 	}
 | |
| 
 | |
| 	doWatch := func(watchChan clientv3.WatchChan) {
 | |
| 		for watchResp := range watchChan {
 | |
| 			if watchResp.Err() != nil {
 | |
| 				log.ZError(ctx, "watch err", errs.Wrap(watchResp.Err()))
 | |
| 				continue
 | |
| 			}
 | |
| 			for _, event := range watchResp.Events {
 | |
| 				if event.IsModify() {
 | |
| 					if datautil.Contain(string(event.Kv.Key), c.watchConfigNames...) {
 | |
| 						c.lock.Lock()
 | |
| 						err := restartServer(ctx)
 | |
| 						if err != nil {
 | |
| 							log.ZError(ctx, "restart server err", err)
 | |
| 						}
 | |
| 						c.lock.Unlock()
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	for _, ch := range chans {
 | |
| 		go doWatch(ch)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func restartServer(ctx context.Context) error {
 | |
| 	exePath, err := os.Executable()
 | |
| 	if err != nil {
 | |
| 		return errs.New("get executable path fail").Wrap()
 | |
| 	}
 | |
| 
 | |
| 	args := os.Args
 | |
| 	env := os.Environ()
 | |
| 
 | |
| 	cmd := exec.Command(exePath, args[1:]...)
 | |
| 	cmd.Env = env
 | |
| 	cmd.Stdout = os.Stdout
 | |
| 	cmd.Stderr = os.Stderr
 | |
| 	cmd.Stdin = os.Stdin
 | |
| 
 | |
| 	if runtime.GOOS != "windows" {
 | |
| 		cmd.SysProcAttr = &syscall.SysProcAttr{}
 | |
| 	}
 | |
| 	log.ZInfo(ctx, "shutdown server")
 | |
| 	for _, f := range ShutDowns {
 | |
| 		if err = f(); err != nil {
 | |
| 			log.ZError(ctx, "shutdown fail", err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	log.ZInfo(ctx, "restart server")
 | |
| 	err = cmd.Start()
 | |
| 	if err != nil {
 | |
| 		return errs.New("restart server fail").Wrap()
 | |
| 	}
 | |
| 	log.ZInfo(ctx, "cmd start over")
 | |
| 
 | |
| 	os.Exit(0)
 | |
| 	return nil
 | |
| }
 |