去掉热更

This commit is contained in:
zhx 2026-05-29 15:03:52 +08:00
parent 11e0ec2f75
commit a7a9ed08ff
2 changed files with 17 additions and 178 deletions

View File

@ -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

View File

@ -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 {