From a7a9ed08ff8545d331c36942daca8752247bace8 Mon Sep 17 00:00:00 2001 From: zhx Date: Fri, 29 May 2026 15:03:52 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8E=BB=E6=8E=89=E7=83=AD=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 2 +- cmd/dev-run/main.go | 193 ++++---------------------------------------- 2 files changed, 17 insertions(+), 178 deletions(-) diff --git a/Makefile b/Makefile index 73ceb68b..8091f678 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ build: go build ./... go build ./server/admin/... -# `run` 拉起 MySQL/Redis 后在本机用 go run 启动所有 Go 服务,并在源码或配置变更时热重启。 +# `run` 拉起 MySQL/Redis 后在本机用 go run 启动所有 Go 服务,不做源码监听或热重启。 # 可用 `make run rs`、`make run SERVICE=room-service` 或 `make run DEV_RUN_SERVICES=user-service,gateway-service` 只跑子集。 run: ./scripts/resolve-compose-container-conflicts.sh diff --git a/cmd/dev-run/main.go b/cmd/dev-run/main.go index 7c316c0b..1e874aac 100644 --- a/cmd/dev-run/main.go +++ b/cmd/dev-run/main.go @@ -1,4 +1,4 @@ -// Package main provides the repository-local hot reload runner behind `make run`. +// Package main provides the repository-local go run launcher behind `make run`. package main import ( @@ -20,19 +20,14 @@ import ( "time" ) -const ( - scanInterval = 800 * time.Millisecond - restartDebounce = 350 * time.Millisecond - stopTimeout = 8 * time.Second -) +const stopTimeout = 8 * time.Second type serviceSpec struct { - Name string - Dir string - Args []string - WatchRoot []string - Ports []int - Color string + Name string + Dir string + Args []string + Ports []int + Color string } type serviceRunner struct { @@ -66,7 +61,6 @@ func main() { defer stop() runners := make(map[string]*serviceRunner, len(specs)) - watchers := make([]*watchState, 0, len(specs)) for _, spec := range specs { runner := &serviceRunner{spec: spec} runners[spec.Name] = runner @@ -74,43 +68,13 @@ func main() { if err := runner.start(root); err != nil { logf(os.Stderr, spec, "start failed: %v", err) } - watchers = append(watchers, newWatchState(root, spec)) } - printPlain(os.Stdout, "dev-run watching %d service(s): %s", len(specs), serviceNames(specs)) + printPlain(os.Stdout, "dev-run started %d service(s): %s", len(specs), serviceNames(specs)) printPlain(os.Stdout, "press Ctrl-C to stop all services") - ticker := time.NewTicker(scanInterval) - defer ticker.Stop() - - pending := map[string]time.Time{} - for { - select { - case <-ctx.Done(): - stopAll(runners) - return - case now := <-ticker.C: - for _, watcher := range watchers { - changed, err := watcher.changed() - if err != nil { - logf(os.Stderr, watcher.spec, "watch failed: %v", err) - continue - } - if changed { - pending[watcher.spec.Name] = now - } - } - for name, changedAt := range pending { - if now.Sub(changedAt) < restartDebounce { - continue - } - delete(pending, name) - runner := runners[name] - logf(os.Stdout, runner.spec, "change detected, restarting") - runner.restart(root) - } - } - } + <-ctx.Done() + stopAll(runners) } func allServices() []serviceSpec { @@ -126,13 +90,9 @@ func allServices() []serviceSpec { appService("gateway-service", []int{13000}, "92"), appService("statistics-service", []int{13010, 13110}, "94"), { - Name: "admin", - Dir: "server/admin", - Args: []string{"run", "./cmd/server", "-config", "configs/config.yaml"}, - WatchRoot: []string{ - "server/admin", - "api", - }, + Name: "admin", + Dir: "server/admin", + Args: []string{"run", "./cmd/server", "-config", "configs/config.yaml"}, Ports: []int{13100}, Color: "91", }, @@ -141,14 +101,9 @@ func allServices() []serviceSpec { func appService(name string, ports []int, color string) serviceSpec { return serviceSpec{ - Name: name, - Dir: ".", - Args: []string{"run", "./services/" + name + "/cmd/server", "-config", "services/" + name + "/configs/config.yaml"}, - WatchRoot: []string{ - "services/" + name, - "pkg", - "api", - }, + Name: name, + Dir: ".", + Args: []string{"run", "./services/" + name + "/cmd/server", "-config", "services/" + name + "/configs/config.yaml"}, Ports: ports, Color: color, } @@ -238,14 +193,6 @@ func (r *serviceRunner) start(repoRoot string) error { return nil } -func (r *serviceRunner) restart(repoRoot string) { - r.stop() - killPortOwners(r.spec) - if err := r.start(repoRoot); err != nil { - logf(os.Stderr, r.spec, "restart failed: %v", err) - } -} - func (r *serviceRunner) stop() { r.mu.Lock() cmd := r.cmd @@ -306,114 +253,6 @@ func stopAll(runners map[string]*serviceRunner) { wg.Wait() } -type watchState struct { - root string - spec serviceSpec - snapshot map[string]fileStamp -} - -type fileStamp struct { - modTime time.Time - size int64 -} - -func newWatchState(root string, spec serviceSpec) *watchState { - w := &watchState{root: root, spec: spec} - w.snapshot = w.scan() - return w -} - -func (w *watchState) changed() (bool, error) { - next := w.scan() - changed := !sameSnapshot(w.snapshot, next) - w.snapshot = next - return changed, nil -} - -func (w *watchState) scan() map[string]fileStamp { - out := make(map[string]fileStamp) - for _, rel := range w.spec.WatchRoot { - w.scanPath(out, rel) - } - // 根 module 变更会影响所有 app 服务;admin 还有自己的独立 module 文件。 - w.scanPath(out, "go.mod") - w.scanPath(out, "go.sum") - if w.spec.Name == "admin" { - w.scanPath(out, filepath.Join("server", "admin", "go.mod")) - w.scanPath(out, filepath.Join("server", "admin", "go.sum")) - } - return out -} - -func (w *watchState) scanPath(out map[string]fileStamp, rel string) { - path := filepath.Join(w.root, rel) - info, err := os.Stat(path) - if err != nil { - return - } - if !info.IsDir() { - if watchableFile(path) { - out[rel] = fileStamp{modTime: info.ModTime(), size: info.Size()} - } - return - } - _ = filepath.WalkDir(path, func(path string, d os.DirEntry, err error) error { - if err != nil { - return nil - } - if d.IsDir() { - if ignoredDir(d.Name()) { - return filepath.SkipDir - } - return nil - } - if !watchableFile(path) { - return nil - } - info, err := d.Info() - if err != nil { - return nil - } - relPath, err := filepath.Rel(w.root, path) - if err != nil { - return nil - } - out[relPath] = fileStamp{modTime: info.ModTime(), size: info.Size()} - return nil - }) -} - -func ignoredDir(name string) bool { - switch name { - case ".git", ".idea", ".vscode", "bin", "dist", "node_modules", "storage", "tmp", "vendor": - return true - default: - return false - } -} - -func watchableFile(path string) bool { - switch filepath.Ext(path) { - case ".go", ".yaml", ".yml", ".proto", ".mod", ".sum": - return true - default: - return false - } -} - -func sameSnapshot(a, b map[string]fileStamp) bool { - if len(a) != len(b) { - return false - } - for path, stampA := range a { - stampB, ok := b[path] - if !ok || !stampA.modTime.Equal(stampB.modTime) || stampA.size != stampB.size { - return false - } - } - return true -} - func killPortOwners(spec serviceSpec) { seen := map[int]bool{} for _, port := range spec.Ports {