Skip to content

Commit 1d3c9cb

Browse files
committed
refactor(platform): abstract process management for Unix and Windows environments
1 parent c2148e8 commit 1d3c9cb

8 files changed

Lines changed: 88 additions & 36 deletions

File tree

src/client/acontext-cli/cmd/create_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,3 @@ func TestValidateProjectName(t *testing.T) {
9090
})
9191
}
9292
}
93-

src/client/acontext-cli/cmd/server.go

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"os/exec"
88
"os/signal"
99
"path/filepath"
10-
"runtime"
1110
"strings"
1211
"sync"
1312
"syscall"
@@ -17,6 +16,7 @@ import (
1716
"github.com/charmbracelet/lipgloss"
1817
"github.com/memodb-io/Acontext/acontext-cli/internal/docker"
1918
"github.com/memodb-io/Acontext/acontext-cli/internal/pkgmgr"
19+
"github.com/memodb-io/Acontext/acontext-cli/internal/platform"
2020
"github.com/memodb-io/Acontext/acontext-cli/internal/sandbox"
2121
"github.com/spf13/cobra"
2222
)
@@ -516,9 +516,7 @@ func runServerUp(cmd *cobra.Command, args []string) error {
516516
mu.Lock()
517517
sandboxCmd = exec.Command(parts[0], parts[1:]...)
518518
sandboxCmd.Dir = projectDir
519-
if runtime.GOOS != "windows" {
520-
sandboxCmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
521-
}
519+
platform.SetProcessGroup(sandboxCmd)
522520
mu.Unlock()
523521

524522
sandboxStdout, err := sandboxCmd.StdoutPipe()
@@ -689,25 +687,12 @@ func runServerUp(cmd *cobra.Command, args []string) error {
689687
func cleanup(cwd string, mu *sync.Mutex, sandboxCmd, dockerLogsCmd *exec.Cmd, dockerComposeFile string) {
690688
mu.Lock()
691689
if sandboxCmd != nil && sandboxCmd.Process != nil {
692-
if runtime.GOOS != "windows" {
693-
pgid, err := syscall.Getpgid(sandboxCmd.Process.Pid)
694-
if err == nil {
695-
if err := syscall.Kill(-pgid, syscall.SIGTERM); err != nil {
696-
fmt.Printf("⚠️ Warning: failed to send SIGTERM to process group: %v\n", err)
697-
}
698-
time.Sleep(500 * time.Millisecond)
699-
if err := syscall.Kill(-pgid, syscall.SIGKILL); err != nil {
700-
fmt.Printf("⚠️ Warning: failed to send SIGKILL to process group: %v\n", err)
701-
}
702-
} else {
703-
if err := sandboxCmd.Process.Kill(); err != nil {
704-
fmt.Printf("⚠️ Warning: failed to kill sandbox process: %v\n", err)
705-
}
706-
}
707-
} else {
708-
if err := sandboxCmd.Process.Kill(); err != nil {
709-
fmt.Printf("⚠️ Warning: failed to kill sandbox process: %v\n", err)
710-
}
690+
if err := platform.KillProcessGroup(sandboxCmd); err != nil {
691+
fmt.Printf("⚠️ Warning: failed to send SIGTERM to process group: %v\n", err)
692+
}
693+
time.Sleep(500 * time.Millisecond)
694+
if err := platform.KillProcessGroupForce(sandboxCmd); err != nil {
695+
fmt.Printf("⚠️ Warning: failed to send SIGKILL to process group: %v\n", err)
711696
}
712697
if err := sandboxCmd.Wait(); err != nil {
713698
fmt.Printf("⚠️ Warning: sandbox process wait error: %v\n", err)

src/client/acontext-cli/internal/docker/checker.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,3 @@ func CheckDockerInstalled() error {
2929

3030
return nil
3131
}
32-

src/client/acontext-cli/internal/docker/env_test.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func TestGenerateEnvFile(t *testing.T) {
2828
},
2929
}
3030

31-
for _, tt := range tests {
31+
for _, tt := range tests {
3232
t.Run(tt.name, func(t *testing.T) {
3333
// Create directory if needed
3434
dir := filepath.Dir(tt.filePath)
@@ -44,7 +44,7 @@ func TestGenerateEnvFile(t *testing.T) {
4444
},
4545
RootAPIBearerToken: "test-root-token",
4646
}
47-
47+
4848
err = GenerateEnvFile(tt.filePath, envConfig)
4949
if tt.wantErr {
5050
assert.Error(t, err)
@@ -95,4 +95,3 @@ func TestGenerateEnvFile(t *testing.T) {
9595
})
9696
}
9797
}
98-

src/client/acontext-cli/internal/git/init.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,4 +107,3 @@ temp/
107107

108108
return os.WriteFile(gitignorePath, []byte(content), 0644)
109109
}
110-

src/client/acontext-cli/internal/git/init_test.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,19 @@ import (
1111

1212
func TestEnsureGitignore(t *testing.T) {
1313
tests := []struct {
14-
name string
14+
name string
1515
fileExists bool
16-
wantErr bool
16+
wantErr bool
1717
}{
1818
{
19-
name: "create new gitignore",
19+
name: "create new gitignore",
2020
fileExists: false,
21-
wantErr: false,
21+
wantErr: false,
2222
},
2323
{
24-
name: "skip if gitignore exists",
24+
name: "skip if gitignore exists",
2525
fileExists: true,
26-
wantErr: false,
26+
wantErr: false,
2727
},
2828
}
2929

@@ -62,4 +62,3 @@ func TestEnsureGitignore(t *testing.T) {
6262
})
6363
}
6464
}
65-
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//go:build !windows
2+
// +build !windows
3+
4+
package platform
5+
6+
import (
7+
"os/exec"
8+
"syscall"
9+
)
10+
11+
// SetProcessGroup sets the process group for Unix systems
12+
func SetProcessGroup(cmd *exec.Cmd) {
13+
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
14+
}
15+
16+
// KillProcessGroup kills a process group on Unix systems
17+
func KillProcessGroup(cmd *exec.Cmd) error {
18+
if cmd == nil || cmd.Process == nil {
19+
return nil
20+
}
21+
pgid, err := syscall.Getpgid(cmd.Process.Pid)
22+
if err != nil {
23+
// If we can't get the process group, just kill the process
24+
return cmd.Process.Kill()
25+
}
26+
// Send SIGTERM to the process group
27+
if err := syscall.Kill(-pgid, syscall.SIGTERM); err != nil {
28+
return err
29+
}
30+
return nil
31+
}
32+
33+
// KillProcessGroupForce forcefully kills a process group on Unix systems
34+
func KillProcessGroupForce(cmd *exec.Cmd) error {
35+
if cmd == nil || cmd.Process == nil {
36+
return nil
37+
}
38+
pgid, err := syscall.Getpgid(cmd.Process.Pid)
39+
if err != nil {
40+
// If we can't get the process group, just kill the process
41+
return cmd.Process.Kill()
42+
}
43+
// Send SIGKILL to the process group
44+
return syscall.Kill(-pgid, syscall.SIGKILL)
45+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//go:build windows
2+
// +build windows
3+
4+
package platform
5+
6+
import "os/exec"
7+
8+
// SetProcessGroup is a no-op on Windows
9+
func SetProcessGroup(cmd *exec.Cmd) {
10+
// Windows doesn't support process groups in the same way
11+
}
12+
13+
// KillProcessGroup kills a process on Windows (no process groups)
14+
func KillProcessGroup(cmd *exec.Cmd) error {
15+
if cmd == nil || cmd.Process == nil {
16+
return nil
17+
}
18+
return cmd.Process.Kill()
19+
}
20+
21+
// KillProcessGroupForce forcefully kills a process on Windows (no process groups)
22+
func KillProcessGroupForce(cmd *exec.Cmd) error {
23+
if cmd == nil || cmd.Process == nil {
24+
return nil
25+
}
26+
return cmd.Process.Kill()
27+
}

0 commit comments

Comments
 (0)