Skip to content

Commit e256565

Browse files
authored
⭐ feat: restart server after binary recompile (#256)
- Added version and build ID headers for client verification. - Enhanced health checks to validate server version and build ID. - Updated server versioning to reflect current version and commit ID. - Improved error handling for robust server communication.
1 parent 6934c18 commit e256565

File tree

3 files changed

+76
-5
lines changed

3 files changed

+76
-5
lines changed

packages/cli/internal/daemon/manager.go

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,18 @@ import (
1313
"strconv"
1414
"syscall"
1515
"time"
16+
17+
"github.com/babelcloud/gbox/packages/cli/internal/server"
18+
"github.com/babelcloud/gbox/packages/cli/internal/version"
1619
)
1720

1821
const (
1922
DefaultPort = 29888 // New port for unified gbox server
2023
ServerURL = "http://localhost:29888"
24+
25+
// Version headers returned by server
26+
serverHeaderVersion = "X-GBOX-Version"
27+
serverHeaderBuildID = "X-GBOX-Build-ID"
2128
)
2229

2330
// Manager handles the gbox server daemon lifecycle
@@ -72,13 +79,25 @@ func (m *Manager) IsServerRunning() bool {
7279

7380
// checkHTTPHealth checks if server is responding to HTTP requests
7481
func (m *Manager) checkHTTPHealth() bool {
75-
client := &http.Client{Timeout: 500 * time.Millisecond}
82+
client := &http.Client{Timeout: 150 * time.Millisecond}
7683
resp, err := client.Get(fmt.Sprintf("%s/api/server/info", m.url))
7784
if err != nil {
7885
return false
7986
}
8087
defer resp.Body.Close()
81-
return resp.StatusCode == http.StatusOK
88+
89+
if resp.StatusCode != http.StatusOK {
90+
return false
91+
}
92+
serverVersion := resp.Header.Get(serverHeaderVersion)
93+
serverBuildID := resp.Header.Get(serverHeaderBuildID)
94+
clientVersion := version.Version
95+
clientBuildID := server.GetBuildID()
96+
if (serverVersion != "" && clientVersion != "" && serverVersion != clientVersion) ||
97+
(serverBuildID != "" && clientBuildID != "" && serverBuildID != clientBuildID) {
98+
return false
99+
}
100+
return true
82101
}
83102

84103
// StartServer starts the gbox server daemon
@@ -228,12 +247,58 @@ func (m *Manager) CallAPI(method, endpoint string, body interface{}, result inte
228247
}
229248

230249
client := &http.Client{Timeout: 10 * time.Second}
231-
resp, err := client.Do(req)
250+
251+
// perform is a small helper to execute the request
252+
perform := func() (*http.Response, error) {
253+
return client.Do(req)
254+
}
255+
256+
resp, err := perform()
232257
if err != nil {
233258
return fmt.Errorf("API call failed: %v", err)
234259
}
235260
defer resp.Body.Close()
236261

262+
// Version/build-id check: compare headers with client values.
263+
serverVersion := resp.Header.Get(serverHeaderVersion)
264+
serverBuildID := resp.Header.Get(serverHeaderBuildID)
265+
clientVersion := version.Version
266+
clientBuildID := server.GetBuildID()
267+
268+
mismatch := false
269+
if serverVersion != "" && clientVersion != "" && serverVersion != clientVersion {
270+
mismatch = true
271+
}
272+
if serverBuildID != "" && clientBuildID != "" && serverBuildID != clientBuildID {
273+
mismatch = true
274+
}
275+
276+
if mismatch {
277+
_ = m.StopServer()
278+
if err := m.StartServer(); err != nil {
279+
return fmt.Errorf("server mismatch (ver:%s!=%s or build:%s!=%s) and restart failed: %v", serverVersion, clientVersion, serverBuildID, clientBuildID, err)
280+
}
281+
// Retry once with a fresh request object (req body may have been consumed)
282+
if body != nil {
283+
jsonData, _ := json.Marshal(body)
284+
req, err = http.NewRequest(method, url, bytes.NewReader(jsonData))
285+
if err != nil {
286+
return fmt.Errorf("failed to create retry request: %v", err)
287+
}
288+
req.Header.Set("Content-Type", "application/json")
289+
} else {
290+
req, err = http.NewRequest(method, url, nil)
291+
if err != nil {
292+
return fmt.Errorf("failed to create retry request: %v", err)
293+
}
294+
}
295+
resp, err = perform()
296+
if err != nil {
297+
return fmt.Errorf("API call after restart failed: %v", err)
298+
}
299+
defer resp.Body.Close()
300+
}
301+
237302
if resp.StatusCode >= 400 {
238303
body, _ := io.ReadAll(resp.Body)
239304
return fmt.Errorf("API error (status %d): %s", resp.StatusCode, string(body))

packages/cli/internal/server/handlers/api.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,5 +105,9 @@ func (h *APIHandlers) HandleServerInfo(w http.ResponseWriter, req *http.Request)
105105
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
106106
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
107107

108+
// Set version headers for client verification
109+
w.Header().Set("X-GBOX-Version", h.serverService.GetVersion())
110+
w.Header().Set("X-GBOX-Build-ID", h.serverService.GetBuildID())
111+
108112
RespondJSON(w, http.StatusOK, info)
109113
}

packages/cli/internal/server/version.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"os"
66
"runtime"
77
"time"
8+
9+
"github.com/babelcloud/gbox/packages/cli/internal/version"
810
)
911

1012
// BuildInfo contains build-time information
@@ -14,9 +16,9 @@ var BuildInfo = struct {
1416
GitCommit string
1517
GoVersion string
1618
}{
17-
Version: "dev",
19+
Version: version.Version,
1820
BuildTime: time.Now().Format(time.RFC3339),
19-
GitCommit: "unknown",
21+
GitCommit: version.CommitID,
2022
GoVersion: runtime.Version(),
2123
}
2224

0 commit comments

Comments
 (0)