Ignore "no such process" error (#1686)

* Cleanup how status is updated for service. Ignore "no such process" error as it could be that the pid died

* add nice error log to record process error exit
This commit is contained in:
Dominic Wong 2020-06-08 10:47:25 +01:00
parent d613804b0a
commit 86dfcb819b
4 changed files with 35 additions and 26 deletions

View File

@ -373,7 +373,6 @@ func (r *runtime) Create(s *Service, opts ...CreateOption) error {
if err := service.Start(); err != nil { if err := service.Start(); err != nil {
return err return err
} }
// save service // save service
r.namespaces[options.Namespace][serviceKey(s)] = service r.namespaces[options.Namespace][serviceKey(s)] = service
@ -536,7 +535,7 @@ func (r *runtime) Read(opts ...ReadOption) ([]*Service, error) {
return services, nil return services, nil
} }
// Update attemps to update the service // Update attempts to update the service
func (r *runtime) Update(s *Service, opts ...UpdateOption) error { func (r *runtime) Update(s *Service, opts ...UpdateOption) error {
var options UpdateOptions var options UpdateOptions
for _, o := range opts { for _, o := range opts {
@ -565,7 +564,8 @@ func (r *runtime) Update(s *Service, opts ...UpdateOption) error {
return errors.New("Service not found") return errors.New("Service not found")
} }
if err := service.Stop(); err != nil { if err := service.Stop(); err != nil && err.Error() != "no such process" {
logger.Errorf("Error stopping service %s: %s", service.Name, err)
return err return err
} }

View File

@ -167,11 +167,10 @@ func (k *kubernetes) getService(labels map[string]string, opts ...client.GetOpti
// parse out deployment status and inject into service metadata // parse out deployment status and inject into service metadata
if len(kdep.Status.Conditions) > 0 { if len(kdep.Status.Conditions) > 0 {
svc.Metadata["status"] = kdep.Status.Conditions[0].Type svc.Status(kdep.Status.Conditions[0].Type, nil)
svc.Metadata["started"] = kdep.Status.Conditions[0].LastUpdateTime svc.Metadata["started"] = kdep.Status.Conditions[0].LastUpdateTime
delete(svc.Metadata, "error")
} else { } else {
svc.Metadata["status"] = "n/a" svc.Status("n/a", nil)
} }
// get the real status // get the real status
@ -214,8 +213,7 @@ func (k *kubernetes) getService(labels map[string]string, opts ...client.GetOpti
} }
} }
// TODO: set from terminated // TODO: set from terminated
svc.Status(status, nil)
svc.Metadata["status"] = status
} }
// save deployment // save deployment

View File

@ -3,6 +3,7 @@ package kubernetes
import ( import (
"encoding/json" "encoding/json"
"strings" "strings"
"time"
"github.com/micro/go-micro/v2/logger" "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/runtime" "github.com/micro/go-micro/v2/runtime"
@ -185,8 +186,10 @@ func (s *service) Update(k client.Client, opts ...client.UpdateOption) error {
} }
func (s *service) Status(status string, err error) { func (s *service) Status(status string, err error) {
s.Metadata["lastStatusUpdate"] = time.Now().Format(time.RFC3339)
if err == nil { if err == nil {
s.Metadata["status"] = status s.Metadata["status"] = status
delete(s.Metadata, "error")
return return
} }
s.Metadata["status"] = "error" s.Metadata["status"] = "error"

View File

@ -93,7 +93,7 @@ func (s *service) Running() bool {
return s.running return s.running
} }
// Start stars the service // Start starts the service
func (s *service) Start() error { func (s *service) Start() error {
s.Lock() s.Lock()
defer s.Unlock() defer s.Unlock()
@ -110,10 +110,7 @@ func (s *service) Start() error {
if s.Metadata == nil { if s.Metadata == nil {
s.Metadata = make(map[string]string) s.Metadata = make(map[string]string)
} }
s.Status("starting", nil)
s.Metadata["status"] = "starting"
// delete any existing error
delete(s.Metadata, "error")
// TODO: pull source & build binary // TODO: pull source & build binary
if logger.V(logger.DebugLevel, logger.DefaultLogger) { if logger.V(logger.DebugLevel, logger.DefaultLogger) {
@ -122,17 +119,15 @@ func (s *service) Start() error {
p, err := s.Process.Fork(s.Exec) p, err := s.Process.Fork(s.Exec)
if err != nil { if err != nil {
s.Metadata["status"] = "error" s.Status("error", err)
s.Metadata["error"] = err.Error()
return err return err
} }
// set the pid // set the pid
s.PID = p s.PID = p
// set to running // set to running
s.running = true s.running = true
// set status // set status
s.Metadata["status"] = "running" s.Status("running", nil)
// set started // set started
s.Metadata["started"] = time.Now().Format(time.RFC3339) s.Metadata["started"] = time.Now().Format(time.RFC3339)
@ -146,6 +141,18 @@ func (s *service) Start() error {
return nil return nil
} }
// Status updates the status of the service. Assumes it's called under a lock as it mutates state
func (s *service) Status(status string, err error) {
s.Metadata["lastStatusUpdate"] = time.Now().Format(time.RFC3339)
s.Metadata["status"] = status
if err == nil {
delete(s.Metadata, "error")
return
}
s.Metadata["error"] = err.Error()
}
// Stop stops the service // Stop stops the service
func (s *service) Stop() error { func (s *service) Stop() error {
s.Lock() s.Lock()
@ -163,18 +170,17 @@ func (s *service) Stop() error {
} }
// set status // set status
s.Metadata["status"] = "stopping" s.Status("stopping", nil)
// kill the process // kill the process
err := s.Process.Kill(s.PID) err := s.Process.Kill(s.PID)
if err != nil { if err == nil {
return err
}
// wait for it to exit // wait for it to exit
s.Process.Wait(s.PID) s.Process.Wait(s.PID)
}
// set status // set status
s.Metadata["status"] = "stopped" s.Status("stopped", err)
// return the kill error // return the kill error
return err return err
@ -198,14 +204,16 @@ func (s *service) Wait() {
// save the error // save the error
if err != nil { if err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
logger.Errorf("Service %s terminated with error %s", s.Name, err)
}
s.retries++ s.retries++
s.Metadata["status"] = "error" s.Status("error", err)
s.Metadata["error"] = err.Error()
s.Metadata["retries"] = strconv.Itoa(s.retries) s.Metadata["retries"] = strconv.Itoa(s.retries)
s.err = err s.err = err
} else { } else {
s.Metadata["status"] = "done" s.Status("done", nil)
} }
// no longer running // no longer running