Skip to content

Commit c36128d

Browse files
committed
refactor(ErrorHandling): streamline error handling in API responses and improve SSE performance data transmission
1 parent 422c3ce commit c36128d

File tree

7 files changed

+56
-106
lines changed

7 files changed

+56
-106
lines changed

api/nginx/status.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func GetDetailStatus(c *gin.Context) {
3838
func StreamDetailStatus(c *gin.Context) {
3939
// Set SSE response headers
4040
api.SetSSEHeaders(c)
41-
41+
4242
// Create context that cancels when client disconnects
4343
ctx := c.Request.Context()
4444

@@ -54,10 +54,7 @@ func StreamDetailStatus(c *gin.Context) {
5454
select {
5555
case <-ticker.C:
5656
// Send performance data
57-
if err := sendPerformanceData(c); err != nil {
58-
logger.Warn("Error sending SSE data:", err)
59-
return
60-
}
57+
sendPerformanceData(c)
6158
case <-ctx.Done():
6259
// Client closed connection or request canceled
6360
logger.Debug("Client closed connection")
@@ -67,15 +64,14 @@ func StreamDetailStatus(c *gin.Context) {
6764
}
6865

6966
// sendPerformanceData sends performance data once
70-
func sendPerformanceData(c *gin.Context) error {
67+
func sendPerformanceData(c *gin.Context) {
7168
response := performance.GetPerformanceData()
7269

7370
// Send SSE event
7471
c.SSEvent("message", response)
7572

7673
// Flush buffer to ensure data is sent immediately
7774
c.Writer.Flush()
78-
return nil
7975
}
8076

8177
// CheckStubStatus gets Nginx stub_status module status

app/src/lib/http/error.ts

Lines changed: 28 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -26,36 +26,8 @@ export function useMessageDedupe(interval = 5000): MessageDedupe {
2626
}
2727
}
2828

29-
export function handleApiError(err: CosyError, dedupe: MessageDedupe) {
30-
if (err?.scope) {
31-
// check if already register
32-
if (!errors[err.scope]) {
33-
try {
34-
// Dynamic import error files
35-
import(`@/constants/errors/${err.scope}.ts`)
36-
.then(error => {
37-
registerError(err.scope!, error.default)
38-
displayErrorMessage(err, dedupe)
39-
})
40-
.catch(err => {
41-
console.error(err)
42-
dedupe.error($gettext(err?.message ?? 'Server error'))
43-
})
44-
}
45-
catch {
46-
dedupe.error($gettext(err?.message ?? 'Server error'))
47-
}
48-
}
49-
else {
50-
displayErrorMessage(err, dedupe)
51-
}
52-
}
53-
else {
54-
dedupe.error($gettext(err?.message ?? 'Server error'))
55-
}
56-
}
57-
58-
function displayErrorMessage(err: CosyError, dedupe: MessageDedupe) {
29+
// Synchronous version for already registered errors
30+
function translateErrorSync(err: CosyError): string {
5931
const msg = errors?.[err.scope ?? '']?.[err.code ?? '']
6032

6133
if (msg) {
@@ -67,13 +39,36 @@ function displayErrorMessage(err: CosyError, dedupe: MessageDedupe) {
6739
res = res.replaceAll(`{${index}}`, param)
6840
})
6941

70-
dedupe.error(res)
42+
return res
7143
}
7244
else {
73-
dedupe.error(msg())
45+
return msg()
7446
}
7547
}
7648
else {
77-
dedupe.error($gettext(err?.message ?? 'Server error'))
49+
return $gettext(err?.message ?? 'Server error')
7850
}
7951
}
52+
53+
// Asynchronous version that handles dynamic loading
54+
export async function translateError(err: CosyError): Promise<string> {
55+
// If scope exists, use sync version
56+
if (!err?.scope || errors[err.scope]) {
57+
return translateErrorSync(err)
58+
}
59+
60+
// Need to dynamically load error definitions
61+
try {
62+
const errorModule = await import(`@/constants/errors/${err.scope}.ts`)
63+
registerError(err.scope, errorModule.default)
64+
return translateErrorSync(err)
65+
}
66+
catch (error) {
67+
console.error(error)
68+
return $gettext(err?.message ?? 'Server error')
69+
}
70+
}
71+
72+
export async function handleApiError(err: CosyError, dedupe: MessageDedupe) {
73+
dedupe.error(await translateError(err))
74+
}

app/src/lib/http/interceptors.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ export function setupResponseInterceptor() {
153153
}
154154

155155
const err = error.response?.data as CosyError
156-
handleApiError(err, dedupe)
156+
await handleApiError(err, dedupe)
157157

158158
return Promise.reject(error.response?.data)
159159
},

app/src/views/dashboard/NginxDashBoard.vue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ function connectSSE() {
7676
else {
7777
error.value = data.message || $gettext('Nginx is not running')
7878
}
79+
80+
if (data.error) {
81+
error.value = data.error
82+
}
83+
7984
stubStatusEnabled.value = data.stub_status_enabled
8085
},
8186
onError: () => {

internal/nginx/modules.go

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package nginx
22

33
import (
4-
"fmt"
54
"os"
65
"regexp"
76
"strings"
@@ -218,36 +217,6 @@ func getExpectedLoadModuleName(configureModuleName string) string {
218217
return "ngx_" + normalized + "_module"
219218
}
220219

221-
// GetModuleMapping returns a map showing the relationship between different module name formats.
222-
// This is useful for debugging and understanding how module names are processed.
223-
// Returns a map with normalized names as keys and mapping info as values.
224-
func GetModuleMapping() map[string]map[string]string {
225-
modules := GetModules()
226-
mapping := make(map[string]map[string]string)
227-
228-
modulesCacheLock.RLock()
229-
defer modulesCacheLock.RUnlock()
230-
231-
// Use AllFromFront() to iterate through the ordered map
232-
for normalizedName, module := range modules.AllFromFront() {
233-
if module == nil {
234-
continue
235-
}
236-
237-
expectedLoadName := getExpectedLoadModuleName(normalizedName)
238-
239-
mapping[normalizedName] = map[string]string{
240-
"normalized": normalizedName,
241-
"expected_load_module": expectedLoadName,
242-
"dynamic": fmt.Sprintf("%t", module.Dynamic),
243-
"loaded": fmt.Sprintf("%t", module.Loaded),
244-
"params": module.Params,
245-
}
246-
}
247-
248-
return mapping
249-
}
250-
251220
// normalizeAddModuleName converts a module name from --add-module arguments
252221
// to a consistent format for internal use.
253222
// Examples:

internal/nginx/modules_test.go

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -376,40 +376,6 @@ func TestExternalModuleDiscovery(t *testing.T) {
376376
}
377377
}
378378

379-
func TestGetModuleMapping(t *testing.T) {
380-
// This test verifies that GetModuleMapping function works without errors
381-
// Since it depends on nginx being available, we'll just test that it doesn't panic
382-
defer func() {
383-
if r := recover(); r != nil {
384-
t.Errorf("GetModuleMapping panicked: %v", r)
385-
}
386-
}()
387-
388-
mapping := GetModuleMapping()
389-
390-
// The mapping should be a valid map (could be empty if nginx is not available)
391-
if mapping == nil {
392-
t.Error("GetModuleMapping returned nil")
393-
}
394-
395-
t.Logf("GetModuleMapping returned %d entries", len(mapping))
396-
397-
// If there are entries, verify they have the expected structure
398-
for moduleName, moduleInfo := range mapping {
399-
if moduleInfo == nil {
400-
t.Errorf("Module %s has nil info", moduleName)
401-
continue
402-
}
403-
404-
requiredFields := []string{"normalized", "expected_load_module", "dynamic", "loaded", "params"}
405-
for _, field := range requiredFields {
406-
if _, exists := moduleInfo[field]; !exists {
407-
t.Errorf("Module %s missing field %s", moduleName, field)
408-
}
409-
}
410-
}
411-
}
412-
413379
func TestOpenRestyModuleParsing(t *testing.T) {
414380
// Test case based on real OpenResty nginx -V output
415381
openRestyOutput := `nginx version: openresty/1.25.3.1

internal/performance/performance.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ type NginxPerformanceResponse struct {
1515
StubStatusEnabled bool `json:"stub_status_enabled"`
1616
Running bool `json:"running"`
1717
Info NginxPerformanceInfo `json:"info"`
18+
Error string `json:"error"`
1819
}
1920

2021
func GetPerformanceData() NginxPerformanceResponse {
@@ -32,18 +33,36 @@ func GetPerformanceData() NginxPerformanceResponse {
3233
stubStatusEnabled, statusInfo, err := GetStubStatusData()
3334
if err != nil {
3435
logger.Warn("Failed to get Nginx status:", err)
36+
return NginxPerformanceResponse{
37+
StubStatusEnabled: false,
38+
Running: running,
39+
Info: NginxPerformanceInfo{},
40+
Error: err.Error(),
41+
}
3542
}
3643

3744
// Get Nginx process information
3845
processInfo, err := GetNginxProcessInfo()
3946
if err != nil {
4047
logger.Warn("Failed to get Nginx process info:", err)
48+
return NginxPerformanceResponse{
49+
StubStatusEnabled: stubStatusEnabled,
50+
Running: running,
51+
Info: NginxPerformanceInfo{},
52+
Error: err.Error(),
53+
}
4154
}
4255

4356
// Get Nginx config information
4457
configInfo, err := GetNginxWorkerConfigInfo()
4558
if err != nil {
4659
logger.Warn("Failed to get Nginx config info:", err)
60+
return NginxPerformanceResponse{
61+
StubStatusEnabled: stubStatusEnabled,
62+
Running: running,
63+
Info: NginxPerformanceInfo{},
64+
Error: err.Error(),
65+
}
4766
}
4867

4968
// Ensure ProcessMode field is correctly passed

0 commit comments

Comments
 (0)