mirror of
https://github.com/browseros-ai/BrowserOS.git
synced 2026-05-13 23:53:25 +00:00
Compare commits
1 Commits
dev
...
fix/dev-wa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7f835ca93 |
@@ -2,6 +2,7 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"browseros-dev/proc"
|
||||
|
||||
@@ -33,7 +34,9 @@ func runCleanup(cmd *cobra.Command, args []string) error {
|
||||
if doPorts {
|
||||
ports := proc.DefaultLocalPorts()
|
||||
proc.LogMsgf(proc.TagInfo, "Killing processes on ports %d, %d, %d...", ports.CDP, ports.Server, ports.Extension)
|
||||
proc.KillPorts(ports)
|
||||
if err := proc.KillPortsAndWait(ports, 3*time.Second); err != nil {
|
||||
return err
|
||||
}
|
||||
proc.LogMsg(proc.TagInfo, "Ports cleared")
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"browseros-dev/browser"
|
||||
"browseros-dev/proc"
|
||||
@@ -62,7 +63,9 @@ func runWatch(cmd *cobra.Command, args []string) error {
|
||||
return fmt.Errorf("creating user-data dir: %w", err)
|
||||
}
|
||||
proc.LogMsg(proc.TagInfo, "Killing processes on preferred ports...")
|
||||
proc.KillPorts(defaultPorts)
|
||||
if err := proc.KillPortsAndWait(defaultPorts, 3*time.Second); err != nil {
|
||||
return err
|
||||
}
|
||||
proc.LogMsg(proc.TagInfo, "Ports cleared")
|
||||
|
||||
p, reservations, err = proc.ResolveWatchPorts(false)
|
||||
@@ -159,6 +162,9 @@ func runWatch(cmd *cobra.Command, args []string) error {
|
||||
Env: env,
|
||||
Restart: true,
|
||||
Cmd: []string{"bun", "--watch", "--env-file=.env.development", "src/index.ts"},
|
||||
BeforeStart: func() error {
|
||||
return proc.KillPortAndWait(p.Server, 3*time.Second)
|
||||
},
|
||||
}))
|
||||
|
||||
<-sigCh
|
||||
|
||||
@@ -11,11 +11,12 @@ import (
|
||||
)
|
||||
|
||||
type ProcConfig struct {
|
||||
Tag Tag
|
||||
Dir string
|
||||
Env []string
|
||||
Restart bool
|
||||
Cmd []string
|
||||
Tag Tag
|
||||
Dir string
|
||||
Env []string
|
||||
Restart bool
|
||||
Cmd []string
|
||||
BeforeStart func() error
|
||||
}
|
||||
|
||||
type ManagedProc struct {
|
||||
@@ -49,6 +50,17 @@ func (mp *ManagedProc) run(ctx context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if mp.Cfg.BeforeStart != nil {
|
||||
if err := mp.Cfg.BeforeStart(); err != nil {
|
||||
LogMsg(mp.Cfg.Tag, ErrorColor.Sprintf("Pre-start failed: %v", err))
|
||||
if !mp.Cfg.Restart || ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
LogMsgf(mp.Cfg.Tag, "Starting: %s", DimColor.Sprint(strings.Join(mp.Cfg.Cmd, " ")))
|
||||
|
||||
cmd := exec.Command(mp.Cfg.Cmd[0], mp.Cfg.Cmd[1:]...)
|
||||
|
||||
60
packages/browseros-agent/tools/dev/proc/managed_test.go
Normal file
60
packages/browseros-agent/tools/dev/proc/managed_test.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package proc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestStartManagedRunsBeforeStartOnEachRetry(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2200*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
var count atomic.Int32
|
||||
var wg sync.WaitGroup
|
||||
|
||||
StartManaged(ctx, &wg, ProcConfig{
|
||||
Tag: TagInfo,
|
||||
Dir: t.TempDir(),
|
||||
Restart: true,
|
||||
Cmd: []string{"sh", "-c", "exit 1"},
|
||||
BeforeStart: func() error {
|
||||
count.Add(1)
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
wg.Wait()
|
||||
|
||||
if count.Load() < 2 {
|
||||
t.Fatalf("expected BeforeStart to run on retries, got %d calls", count.Load())
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartManagedSkipsLaunchWhenBeforeStartFails(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
sentinel := filepath.Join(t.TempDir(), "started")
|
||||
var wg sync.WaitGroup
|
||||
|
||||
StartManaged(ctx, &wg, ProcConfig{
|
||||
Tag: TagInfo,
|
||||
Dir: t.TempDir(),
|
||||
Restart: false,
|
||||
Cmd: []string{"sh", "-c", "touch " + sentinel},
|
||||
BeforeStart: func() error {
|
||||
return context.DeadlineExceeded
|
||||
},
|
||||
})
|
||||
|
||||
wg.Wait()
|
||||
|
||||
if _, err := os.Stat(sentinel); !os.IsNotExist(err) {
|
||||
t.Fatalf("expected process launch to be skipped, stat err=%v", err)
|
||||
}
|
||||
}
|
||||
@@ -133,6 +133,29 @@ func KillPort(port int) {
|
||||
exec.Command("sh", "-c", fmt.Sprintf("lsof -ti:%d | xargs kill -9 2>/dev/null || true", port)).Run()
|
||||
}
|
||||
|
||||
func KillPortAndWait(port int, timeout time.Duration) error {
|
||||
deadline := time.Now().Add(timeout)
|
||||
for {
|
||||
KillPort(port)
|
||||
if IsPortAvailable(port) {
|
||||
return nil
|
||||
}
|
||||
if time.Now().After(deadline) {
|
||||
return fmt.Errorf("port %d is still in use after kill -9 cleanup", port)
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
func KillPortsAndWait(p Ports, timeout time.Duration) error {
|
||||
for _, port := range []int{p.CDP, p.Server, p.Extension} {
|
||||
if err := KillPortAndWait(port, timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func BuildEnv(p Ports, nodeEnv string) []string {
|
||||
env := os.Environ()
|
||||
env = append(env,
|
||||
|
||||
Reference in New Issue
Block a user