diff --git a/go-backend/internal/http/handler/control_plane.go b/go-backend/internal/http/handler/control_plane.go index 47bfe8a..13ae9d6 100644 --- a/go-backend/internal/http/handler/control_plane.go +++ b/go-backend/internal/http/handler/control_plane.go @@ -245,6 +245,12 @@ func (h *Handler) syncForwardServicesWithWarnings(forward *forwardRecord, method } warnings := make([]string, 0) + // Resolve user tunnel first so runtime service name can carry the real user_tunnel id. + userTunnelID, utLimiterID, utSpeed, err := h.resolveUserTunnelAndLimiter(forward.UserID, forward.TunnelID) + if err != nil { + return nil, err + } + // Determine limiter from forward's SpeedID first, fallback to UserTunnel's limiter var limiterID *int64 var speed *int @@ -260,17 +266,11 @@ func (h *Handler) syncForwardServicesWithWarnings(forward *forwardRecord, method if limiterID == nil { // Fall back to UserTunnel speed limit - var utLimiterID *int64 - var utSpeed *int - _, utLimiterID, utSpeed, err = h.resolveUserTunnelAndLimiter(forward.UserID, forward.TunnelID) - if err != nil { - return nil, err - } limiterID = utLimiterID speed = utSpeed } - serviceBase := buildForwardServiceBase(forward.ID, forward.UserID, 0) + serviceBase := buildForwardServiceBaseWithResolvedUserTunnel(forward.ID, forward.UserID, userTunnelID) tunnelTLSProtocol, err := h.isTunnelSelectedTLSProtocol(forward.TunnelID) if err != nil { return nil, err @@ -1362,6 +1362,13 @@ func buildForwardServiceBase(forwardID, userID, userTunnelID int64) string { return fmt.Sprintf("%d_%d_%d", forwardID, userID, userTunnelID) } +func buildForwardServiceBaseWithResolvedUserTunnel(forwardID, userID, resolvedUserTunnelID int64) string { + if resolvedUserTunnelID <= 0 { + return buildForwardServiceBase(forwardID, userID, 0) + } + return buildForwardServiceBase(forwardID, userID, resolvedUserTunnelID) +} + func buildForwardServiceBaseCandidates(forwardID, userID, preferredUserTunnelID int64, userTunnelIDs []int64) []string { orderedIDs := make([]int64, 0, len(userTunnelIDs)+2) seen := make(map[int64]struct{}, len(userTunnelIDs)+2) diff --git a/go-backend/internal/http/handler/control_plane_test.go b/go-backend/internal/http/handler/control_plane_test.go index 40bef60..47a414a 100644 --- a/go-backend/internal/http/handler/control_plane_test.go +++ b/go-backend/internal/http/handler/control_plane_test.go @@ -43,6 +43,20 @@ func TestBuildForwardServiceBaseCandidatesWithZeroPreferred(t *testing.T) { } } +func TestBuildForwardServiceBaseWithResolvedUserTunnel(t *testing.T) { + got := buildForwardServiceBaseWithResolvedUserTunnel(12, 34, 56) + if got != "12_34_56" { + t.Fatalf("expected 12_34_56, got %s", got) + } +} + +func TestBuildForwardServiceBaseWithResolvedUserTunnelFallbackToZero(t *testing.T) { + got := buildForwardServiceBaseWithResolvedUserTunnel(12, 34, 0) + if got != "12_34_0" { + t.Fatalf("expected 12_34_0, got %s", got) + } +} + func TestShouldTryLegacySingleService(t *testing.T) { if !shouldTryLegacySingleService("PauseService") { t.Fatalf("PauseService should require legacy fallback")