Sort of run node app
This commit is contained in:
124
master/runexpress.go
Normal file
124
master/runexpress.go
Normal file
@@ -0,0 +1,124 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func runExpress(changes <-chan FileChange) {
|
||||
var currentProcess *exec.Cmd
|
||||
var mu sync.Mutex
|
||||
|
||||
// Helper to start the express process
|
||||
startExpress := func() *exec.Cmd {
|
||||
cmd := exec.Command("node", "../express/dist/index.js")
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
log.Printf("[express] Failed to start: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("[express] Started (pid %d)", cmd.Process.Pid)
|
||||
|
||||
// Monitor the process in background
|
||||
go func() {
|
||||
err := cmd.Wait()
|
||||
if err != nil {
|
||||
log.Printf("[express] Process exited: %v", err)
|
||||
} else {
|
||||
log.Printf("[express] Process exited normally")
|
||||
}
|
||||
}()
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// Helper to stop the express process
|
||||
stopExpress := func(cmd *exec.Cmd) {
|
||||
if cmd == nil || cmd.Process == nil {
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("[express] Stopping (pid %d)", cmd.Process.Pid)
|
||||
cmd.Process.Signal(syscall.SIGTERM)
|
||||
|
||||
// Wait briefly for graceful shutdown
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
cmd.Wait()
|
||||
close(done)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
log.Printf("[express] Stopped gracefully")
|
||||
case <-time.After(5 * time.Second):
|
||||
log.Printf("[express] Force killing")
|
||||
cmd.Process.Kill()
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to run the build
|
||||
runBuild := func() bool {
|
||||
log.Printf("[build] Starting ncc build...")
|
||||
|
||||
cmd := exec.Command("sh", "-c", "cd ../express && ../cmd pnpm ncc build ./app.ts")
|
||||
|
||||
stdout, _ := cmd.StdoutPipe()
|
||||
stderr, _ := cmd.StderrPipe()
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
log.Printf("[build] Failed to start: %v", err)
|
||||
return false
|
||||
}
|
||||
|
||||
// Copy output
|
||||
go io.Copy(os.Stdout, stdout)
|
||||
go io.Copy(os.Stderr, stderr)
|
||||
|
||||
err := cmd.Wait()
|
||||
if err != nil {
|
||||
log.Printf("[build] Failed: %v", err)
|
||||
return false
|
||||
}
|
||||
|
||||
log.Printf("[build] Success")
|
||||
return true
|
||||
}
|
||||
|
||||
// Debounce timer
|
||||
var debounceTimer *time.Timer
|
||||
const debounceDelay = 100 * time.Millisecond
|
||||
|
||||
for change := range changes {
|
||||
log.Printf("[watch] %s: %s", change.Operation, change.Path)
|
||||
|
||||
// Reset debounce timer
|
||||
if debounceTimer != nil {
|
||||
debounceTimer.Stop()
|
||||
}
|
||||
|
||||
debounceTimer = time.AfterFunc(debounceDelay, func() {
|
||||
if !runBuild() {
|
||||
log.Printf("[master] Build failed, keeping current process")
|
||||
return
|
||||
}
|
||||
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
// Stop old process
|
||||
stopExpress(currentProcess)
|
||||
|
||||
// Start new process
|
||||
currentProcess = startExpress()
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user