refactor(route): ensure validation and start only starts once, and lock error before finishing

This commit is contained in:
yusing
2025-10-31 18:10:09 +08:00
parent 3ccaba3163
commit 77e486f4fe

View File

@@ -82,19 +82,39 @@ type (
impl types.Route impl types.Route
task *task.Task task *task.Task
isValidated bool // ensure err is read after validation or start
lastError gperr.Error valErr lockedError
provider types.RouteProvider startErr lockedError
provider types.RouteProvider
agent *agent.AgentConfig agent *agent.AgentConfig
started chan struct{} started chan struct{}
once sync.Once onceStart sync.Once
onceValidate sync.Once
} }
Routes map[string]*Route Routes map[string]*Route
Port = route.Port Port = route.Port
) )
type lockedError struct {
err gperr.Error
lock sync.Mutex
}
func (le *lockedError) Get() gperr.Error {
le.lock.Lock()
defer le.lock.Unlock()
return le.err
}
func (le *lockedError) Set(err gperr.Error) {
le.lock.Lock()
defer le.lock.Unlock()
le.err = err
}
const DefaultHost = "localhost" const DefaultHost = "localhost"
func (r Routes) Contains(alias string) bool { func (r Routes) Contains(alias string) bool {
@@ -103,11 +123,13 @@ func (r Routes) Contains(alias string) bool {
} }
func (r *Route) Validate() gperr.Error { func (r *Route) Validate() gperr.Error {
if r.isValidated { r.onceValidate.Do(func() {
return r.lastError r.valErr.Set(r.validate())
} })
r.isValidated = true return r.valErr.Get()
}
func (r *Route) validate() gperr.Error {
if r.Agent != "" { if r.Agent != "" {
if r.Container != nil { if r.Container != nil {
return gperr.Errorf("specifying agent is not allowed for docker container routes") return gperr.Errorf("specifying agent is not allowed for docker container routes")
@@ -250,7 +272,6 @@ func (r *Route) Validate() gperr.Error {
} }
if errs.HasError() { if errs.HasError() {
r.lastError = errs.Error()
return errs.Error() return errs.Error()
} }
@@ -266,7 +287,6 @@ func (r *Route) Validate() gperr.Error {
} }
if err != nil { if err != nil {
r.lastError = err
return err return err
} }
@@ -320,13 +340,10 @@ func (r *Route) Task() *task.Task {
} }
func (r *Route) Start(parent task.Parent) gperr.Error { func (r *Route) Start(parent task.Parent) gperr.Error {
if r.lastError != nil { r.onceStart.Do(func() {
return r.lastError r.startErr.Set(r.start(parent))
}
r.once.Do(func() {
r.lastError = r.start(parent)
}) })
return r.lastError return r.startErr.Get()
} }
func (r *Route) start(parent task.Parent) gperr.Error { func (r *Route) start(parent task.Parent) gperr.Error {
@@ -496,7 +513,7 @@ func (r *Route) IsZeroPort() bool {
} }
func (r *Route) ShouldExclude() bool { func (r *Route) ShouldExclude() bool {
if r.lastError != nil { if r.valErr.Get() != nil {
return true return true
} }
if r.Excluded { if r.Excluded {
@@ -565,7 +582,7 @@ func (re ExcludedReason) MarshalJSON() ([]byte, error) {
// no need to unmarshal json because we don't store this // no need to unmarshal json because we don't store this
func (r *Route) findExcludedReason() ExcludedReason { func (r *Route) findExcludedReason() ExcludedReason {
if r.lastError != nil { if r.valErr.Get() != nil {
return ExcludedReasonError return ExcludedReasonError
} }
if r.ExcludedReason != ExcludedReasonNone { if r.ExcludedReason != ExcludedReasonNone {