From c1920bb1d130ef07c8eab04774ca68a7f33ad2bf Mon Sep 17 00:00:00 2001 From: daved Date: Wed, 17 May 2023 22:03:44 -0700 Subject: [PATCH 1/4] Improve svcctl start/stop wait logic --- internal/svcctl/svcctl.go | 76 +++++++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 26 deletions(-) diff --git a/internal/svcctl/svcctl.go b/internal/svcctl/svcctl.go index e3b11ace73..1ae2103b5b 100644 --- a/internal/svcctl/svcctl.go +++ b/internal/svcctl/svcctl.go @@ -25,12 +25,18 @@ import ( ) var ( - pingRetryIterations = 32 - commonTimeout = func() time.Duration { + pingRetryIterations = 26 + baseStart = 8 + modifierNumerator = 9 + modifierDenominator = 10 + + ipCommTimeout = time.Second * 4 + upDownWaitTimeout = func() time.Duration { var acc int // alg to set max timeout matches ping backoff alg - for i := 1; i <= pingRetryIterations; i++ { - acc += i * i + // last iter does not count towards total, so -1 the iters + for base := baseStart; base < pingRetryIterations+baseStart-1; base++ { + acc += ((base * base) * modifierNumerator) / modifierDenominator } return time.Millisecond * time.Duration(acc) }() @@ -71,10 +77,7 @@ func EnsureExecStartedAndLocateHTTP(ipComm IPCommunicator, exec, argText string) return "", errs.Wrap(err, "Cannot locate HTTP port of service") } - ctx, cancel := context.WithTimeout(context.Background(), commonTimeout) - defer cancel() - - if err := startAndWait(ctx, ipComm, exec, argText); err != nil { + if err := startAndWait(ipComm, exec, argText); err != nil { return "", errs.Wrap(err, "Cannot start service at %q", exec) } @@ -100,7 +103,7 @@ func LocateHTTP(ipComm IPCommunicator) (addr string, err error) { comm := NewComm(ipComm) - ctx, cancel := context.WithTimeout(context.Background(), commonTimeout) + ctx, cancel := context.WithTimeout(context.Background(), ipCommTimeout) defer cancel() addr, err = comm.GetHTTPAddr(ctx) @@ -116,7 +119,7 @@ func LocateHTTP(ipComm IPCommunicator) (addr string, err error) { func LogFileName(ipComm IPCommunicator) (string, error) { comm := NewComm(ipComm) - ctx, cancel := context.WithTimeout(context.Background(), commonTimeout) + ctx, cancel := context.WithTimeout(context.Background(), ipCommTimeout) defer cancel() logfile, err := comm.GetLogFileName(ctx) @@ -130,10 +133,7 @@ func LogFileName(ipComm IPCommunicator) (string, error) { } func StopServer(ipComm IPCommunicator) error { - ctx, cancel := context.WithTimeout(context.Background(), commonTimeout) - defer cancel() - - err := stopAndWait(ctx, ipComm) + err := stopAndWait(ipComm) if err != nil && !errs.Matches(err, &ipc.ServerDownError{}) { return errs.Wrap(err, "Cannot stop service") } @@ -141,7 +141,7 @@ func StopServer(ipComm IPCommunicator) error { return nil } -func startAndWait(ctx context.Context, ipComm IPCommunicator, exec, argText string) error { +func startAndWait(ipComm IPCommunicator, exec, argText string) error { defer profile.Measure("svcmanager:Start", time.Now()) if !fileutils.FileExists(exec) { @@ -157,6 +157,9 @@ func startAndWait(ctx context.Context, ipComm IPCommunicator, exec, argText stri return locale.WrapError(err, "svcctl_cannot_exec_and_forget", "Cannot execute service in background: {{.V0}}", err.Error()) } + ctx, cancel := context.WithTimeout(context.Background(), upDownWaitTimeout) + defer cancel() + logging.Debug("Waiting for service") if err := waitUp(ctx, ipComm); err != nil { return locale.WrapError(err, "svcctl_wait_startup_failed", "Waiting for service startup confirmation failed") @@ -172,6 +175,7 @@ var ( func waitUp(ctx context.Context, ipComm IPCommunicator) error { start := time.Now() for try := 1; try <= pingRetryIterations; try++ { + base := try - 1 + baseStart select { case <-ctx.Done(): return locale.WrapError(ctx.Err(), waitTimeoutL10nKey, "", time.Since(start).String(), "1", constants.ForumsURL) @@ -179,9 +183,12 @@ func waitUp(ctx context.Context, ipComm IPCommunicator) error { } tryStart := time.Now() - timeout := time.Millisecond * time.Duration(try*try) + timeout := time.Millisecond * time.Duration( + ((base*base)*modifierNumerator)/modifierDenominator, + ) + + logging.Debug("Attempt %02d at %12s with timeout %v", try, time.Since(start), timeout) - logging.Debug("Attempt: %d, timeout: %v, total: %v", try, timeout, time.Since(start)) if err := ping(ctx, ipComm, timeout); err != nil { // Timeout does not reveal enough info, try again. // We don't need to sleep for this type of error because, @@ -192,8 +199,12 @@ func waitUp(ctx context.Context, ipComm IPCommunicator) error { if !errors.Is(err, ctlErrNotUp) { return locale.WrapError(err, "svcctl_ping_failed", "Ping encountered unexpected failure: {{.V0}}", err.Error()) } - elapsed := time.Since(tryStart) - time.Sleep(timeout - elapsed) + + if try < pingRetryIterations { + elapsed := time.Since(tryStart) + time.Sleep(timeout - elapsed) + } + continue } return nil @@ -202,13 +213,19 @@ func waitUp(ctx context.Context, ipComm IPCommunicator) error { return locale.NewError(waitTimeoutL10nKey, "", time.Since(start).Round(time.Millisecond).String(), "2", constants.ForumsURL) } -func stopAndWait(ctx context.Context, ipComm IPCommunicator) error { - if err := ipComm.StopServer(ctx); err != nil { +func stopAndWait(ipComm IPCommunicator) error { + stopCtx, stopCancel := context.WithTimeout(context.Background(), ipCommTimeout) + defer stopCancel() + + if err := ipComm.StopServer(stopCtx); err != nil { return locale.WrapError(err, "svcctl_stop_req_failed", "Service stop request failed") } + waitCtx, waitCancel := context.WithTimeout(context.Background(), upDownWaitTimeout) + defer waitCancel() + logging.Debug("Waiting for service to die") - if err := waitDown(ctx, ipComm); err != nil { + if err := waitDown(waitCtx, ipComm); err != nil { return locale.WrapError(err, "svcctl_wait_shutdown_failed", "Waiting for service shutdown confirmation failed") } @@ -218,6 +235,7 @@ func stopAndWait(ctx context.Context, ipComm IPCommunicator) error { func waitDown(ctx context.Context, ipComm IPCommunicator) error { start := time.Now() for try := 1; try <= pingRetryIterations; try++ { + base := try - 1 + baseStart select { case <-ctx.Done(): return locale.WrapError(ctx.Err(), waitTimeoutL10nKey, "", time.Since(start).String(), "3", constants.ForumsURL) @@ -225,9 +243,12 @@ func waitDown(ctx context.Context, ipComm IPCommunicator) error { } tryStart := time.Now() - timeout := time.Millisecond * time.Duration(try*try) + timeout := time.Millisecond * time.Duration( + ((base*base)*modifierNumerator)/modifierDenominator, + ) + + logging.Debug("Attempt %02d at %12s w/timeout %v", try, time.Since(start), timeout) - logging.Debug("Attempt: %d, timeout: %v, total: %v", try, timeout, time.Since(start)) if err := ping(ctx, ipComm, timeout); err != nil { // Timeout does not reveal enough info, try again. // We don't need to sleep for this type of error because, @@ -245,8 +266,11 @@ func waitDown(ctx context.Context, ipComm IPCommunicator) error { return locale.WrapError(err, "svcctl_ping_failed", "Ping encountered unexpected failure: {{.V0}}", err.Error()) } } - elapsed := time.Since(tryStart) - time.Sleep(timeout - elapsed) + + if try < pingRetryIterations { + elapsed := time.Since(tryStart) + time.Sleep(timeout - elapsed) + } } return locale.NewError(waitTimeoutL10nKey, "", time.Since(start).Round(time.Millisecond).String(), "4", constants.ForumsURL) From b06ce58417f9042b8cc249c30de8ea140bf4af63 Mon Sep 17 00:00:00 2001 From: daved Date: Fri, 19 May 2023 14:44:35 -0700 Subject: [PATCH 2/4] Add debug data error to svcctl waitup/waitdown --- internal/locale/locales/en-us.yaml | 4 +- internal/svcctl/debugdata.go | 104 +++++++++++++++++++++++++++++ internal/svcctl/svcctl.go | 82 +++++++++++++++++------ 3 files changed, 169 insertions(+), 21 deletions(-) create mode 100644 internal/svcctl/debugdata.go diff --git a/internal/locale/locales/en-us.yaml b/internal/locale/locales/en-us.yaml index 9ec38a97a4..7b4ae569c8 100644 --- a/internal/locale/locales/en-us.yaml +++ b/internal/locale/locales/en-us.yaml @@ -1966,13 +1966,13 @@ use_reset_notice: other: Note you may need to run '[ACTIONABLE]hash -r[/RESET]' or start a new shell to fully update your environment. svcctl_wait_timeout: other: | - Timed out waiting for service to respond ({{.V0}} - code {{.V1}}). + Timed out waiting for service to respond. (code {{.V0}}) Are you running software that could prevent State Tool from running local processes/servers? Please try running your command again. - If this problem persists please report it on our forums: [ACTIONABLE]{{.V2}}[/RESET] + If this problem persists please report it on our forums: [ACTIONABLE]{{.V1}}[/RESET] svcctl_file_not_found: other: | Could not find the State Tool service executable. diff --git a/internal/svcctl/debugdata.go b/internal/svcctl/debugdata.go new file mode 100644 index 0000000000..9bb0d62714 --- /dev/null +++ b/internal/svcctl/debugdata.go @@ -0,0 +1,104 @@ +package svcctl + +import ( + "fmt" + "strings" + "time" +) + +type execKind string + +const ( + execSvc execKind = "Exec" + stopSvc execKind = "Stop" +) + +type waitAttempt struct { + waitStart time.Time + start time.Time + iter int + timeout time.Duration +} + +func newWaitAttempt(waitStart, start time.Time, iter int, timeout time.Duration) *waitAttempt { + return &waitAttempt{ + waitStart: waitStart, + start: start, + iter: iter, + timeout: timeout, + } +} + +func (a *waitAttempt) String() string { + return fmt.Sprintf( + "Attempt %02d at %12s with timeout %v", + a.iter, a.start.Sub(a.waitStart), a.timeout, + ) +} + +func (a *waitAttempt) LogString() string { + return fmt.Sprintf( + "%02d at %12s, wait %v", + a.iter, a.start.Sub(a.waitStart), a.timeout, + ) +} + +type waitDebugData struct { + execStart time.Time + execDur time.Duration + execKind execKind + waitStart time.Time + waitAttempts []*waitAttempt + waitDur time.Duration +} + +func newWaitDebugData(kind execKind) *waitDebugData { + return &waitDebugData{ + execStart: time.Now(), + execKind: kind, + } +} + +func (d *waitDebugData) Error() string { + var attemptsMsg string + sep := " " + for _, wa := range d.waitAttempts { + attemptsMsg += sep + wa.LogString() + sep = "\n " + } + return fmt.Sprintf(strings.TrimSpace(` +%s Start : %s +%s Duration : %s +Wait Start : %s +Wait Duration : %s +Wait Log: +%s +`), + d.execKind, d.execStart, + d.execKind, d.execDur, + d.waitStart, + d.waitDur, + attemptsMsg) +} + +func (d *waitDebugData) stampExec() { + if d.execStart.IsZero() { + return + } + d.execDur = time.Since(d.execStart) +} + +func (d *waitDebugData) startWait() { + d.waitStart = time.Now() +} + +func (d *waitDebugData) addAttempts(as ...*waitAttempt) { + d.waitAttempts = append(d.waitAttempts, as...) +} + +func (d *waitDebugData) stampWait() { + if d.waitStart.IsZero() { + return + } + d.waitDur = time.Since(d.waitStart) +} diff --git a/internal/svcctl/svcctl.go b/internal/svcctl/svcctl.go index 1ae2103b5b..0765bed60f 100644 --- a/internal/svcctl/svcctl.go +++ b/internal/svcctl/svcctl.go @@ -33,12 +33,12 @@ var ( ipCommTimeout = time.Second * 4 upDownWaitTimeout = func() time.Duration { var acc int - // alg to set max timeout matches ping backoff alg + // alg to set backstop timeout (matches ping backoff alg) // last iter does not count towards total, so -1 the iters for base := baseStart; base < pingRetryIterations+baseStart-1; base++ { acc += ((base * base) * modifierNumerator) / modifierDenominator } - return time.Millisecond * time.Duration(acc) + return time.Millisecond*time.Duration(acc) + time.Second // add buffer }() ) @@ -153,16 +153,31 @@ func startAndWait(ipComm IPCommunicator, exec, argText string) error { args = args[:len(args)-1] } + wdd := newWaitDebugData(execSvc) if _, err := exeutils.ExecuteAndForget(exec, args); err != nil { - return locale.WrapError(err, "svcctl_cannot_exec_and_forget", "Cannot execute service in background: {{.V0}}", err.Error()) + return locale.WrapError( + err, "svcctl_cannot_exec_and_forget", + "Cannot execute service in background: {{.V0}}", err.Error(), + ) } + wdd.stampExec() + + logging.Debug("ExecuteAndForget took %v", wdd.execDur) ctx, cancel := context.WithTimeout(context.Background(), upDownWaitTimeout) defer cancel() logging.Debug("Waiting for service") - if err := waitUp(ctx, ipComm); err != nil { - return locale.WrapError(err, "svcctl_wait_startup_failed", "Waiting for service startup confirmation failed") + wdd.startWait() + err := waitUp(ctx, ipComm, wdd) + wdd.stampWait() + logging.Debug("Wait duration: %s", wdd.waitDur) + if err != nil { + return locale.WrapError( + err, "svcctl_wait_startup_failed", + "Waiting for service startup confirmation failed after {{.V0}}", + time.Since(wdd.waitStart).String(), + ) } return nil @@ -172,13 +187,13 @@ var ( waitTimeoutL10nKey = "svcctl_wait_timeout" ) -func waitUp(ctx context.Context, ipComm IPCommunicator) error { - start := time.Now() +func waitUp(ctx context.Context, ipComm IPCommunicator, wdd *waitDebugData) error { for try := 1; try <= pingRetryIterations; try++ { base := try - 1 + baseStart select { case <-ctx.Done(): - return locale.WrapError(ctx.Err(), waitTimeoutL10nKey, "", time.Since(start).String(), "1", constants.ForumsURL) + err := locale.WrapError(ctx.Err(), waitTimeoutL10nKey, "", "1", constants.ForumsURL) + return errs.Pack(err, wdd) default: } @@ -187,7 +202,10 @@ func waitUp(ctx context.Context, ipComm IPCommunicator) error { ((base*base)*modifierNumerator)/modifierDenominator, ) - logging.Debug("Attempt %02d at %12s with timeout %v", try, time.Since(start), timeout) + wa := newWaitAttempt(wdd.waitStart, tryStart, try, timeout) + wdd.addAttempts(wa) + + logging.Debug("%s", wa) if err := ping(ctx, ipComm, timeout); err != nil { // Timeout does not reveal enough info, try again. @@ -197,7 +215,12 @@ func waitUp(ctx context.Context, ipComm IPCommunicator) error { continue } if !errors.Is(err, ctlErrNotUp) { - return locale.WrapError(err, "svcctl_ping_failed", "Ping encountered unexpected failure: {{.V0}}", err.Error()) + err := locale.WrapError( + err, "svcctl_ping_failed", + "Ping encountered unexpected failure: {{.V0}}", + err.Error(), + ) + errs.Pack(err, wdd) } if try < pingRetryIterations { @@ -207,38 +230,50 @@ func waitUp(ctx context.Context, ipComm IPCommunicator) error { continue } + return nil } - return locale.NewError(waitTimeoutL10nKey, "", time.Since(start).Round(time.Millisecond).String(), "2", constants.ForumsURL) + err := locale.NewError(waitTimeoutL10nKey, "", "2", constants.ForumsURL) + return errs.Pack(err, wdd) } func stopAndWait(ipComm IPCommunicator) error { stopCtx, stopCancel := context.WithTimeout(context.Background(), ipCommTimeout) defer stopCancel() + wdd := newWaitDebugData(stopSvc) if err := ipComm.StopServer(stopCtx); err != nil { return locale.WrapError(err, "svcctl_stop_req_failed", "Service stop request failed") } + wdd.stampExec() waitCtx, waitCancel := context.WithTimeout(context.Background(), upDownWaitTimeout) defer waitCancel() logging.Debug("Waiting for service to die") - if err := waitDown(waitCtx, ipComm); err != nil { - return locale.WrapError(err, "svcctl_wait_shutdown_failed", "Waiting for service shutdown confirmation failed") + wdd.startWait() + err := waitDown(waitCtx, ipComm, wdd) + wdd.stampWait() + logging.Debug("Wait duration: %s", wdd.waitDur) + if err != nil { + return locale.WrapError( + err, "svcctl_wait_shutdown_failed", + "Waiting for service shutdown confirmation failed after {{.V0}}", + time.Since(wdd.waitStart).String(), + ) } return nil } -func waitDown(ctx context.Context, ipComm IPCommunicator) error { - start := time.Now() +func waitDown(ctx context.Context, ipComm IPCommunicator, wdd *waitDebugData) error { for try := 1; try <= pingRetryIterations; try++ { base := try - 1 + baseStart select { case <-ctx.Done(): - return locale.WrapError(ctx.Err(), waitTimeoutL10nKey, "", time.Since(start).String(), "3", constants.ForumsURL) + err := locale.WrapError(ctx.Err(), waitTimeoutL10nKey, "", "3", constants.ForumsURL) + return errs.Pack(err, wdd) default: } @@ -247,7 +282,10 @@ func waitDown(ctx context.Context, ipComm IPCommunicator) error { ((base*base)*modifierNumerator)/modifierDenominator, ) - logging.Debug("Attempt %02d at %12s w/timeout %v", try, time.Since(start), timeout) + wa := newWaitAttempt(wdd.waitStart, tryStart, try, timeout) + wdd.addAttempts(wa) + + logging.Debug("%s", wa) if err := ping(ctx, ipComm, timeout); err != nil { // Timeout does not reveal enough info, try again. @@ -263,7 +301,12 @@ func waitDown(ctx context.Context, ipComm IPCommunicator) error { return nil } if !errors.Is(err, ctlErrTempNotUp) { - return locale.WrapError(err, "svcctl_ping_failed", "Ping encountered unexpected failure: {{.V0}}", err.Error()) + err := locale.WrapError( + err, "svcctl_ping_failed", + "Ping encountered unexpected failure: {{.V0}}", + err.Error(), + ) + errs.Pack(err, wdd) } } @@ -273,7 +316,8 @@ func waitDown(ctx context.Context, ipComm IPCommunicator) error { } } - return locale.NewError(waitTimeoutL10nKey, "", time.Since(start).Round(time.Millisecond).String(), "4", constants.ForumsURL) + err := locale.NewError(waitTimeoutL10nKey, "", "4", constants.ForumsURL) + return errs.Pack(err, wdd) } func ping(ctx context.Context, ipComm IPCommunicator, timeout time.Duration) error { From 5065458141281af0e43c0e27358ed1f82054f55f Mon Sep 17 00:00:00 2001 From: daved Date: Fri, 19 May 2023 14:46:33 -0700 Subject: [PATCH 3/4] Ensure errors are returned in waitup/waitdown --- internal/svcctl/svcctl.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/svcctl/svcctl.go b/internal/svcctl/svcctl.go index 0765bed60f..ab495e2fdb 100644 --- a/internal/svcctl/svcctl.go +++ b/internal/svcctl/svcctl.go @@ -220,7 +220,7 @@ func waitUp(ctx context.Context, ipComm IPCommunicator, wdd *waitDebugData) erro "Ping encountered unexpected failure: {{.V0}}", err.Error(), ) - errs.Pack(err, wdd) + return errs.Pack(err, wdd) } if try < pingRetryIterations { @@ -306,7 +306,7 @@ func waitDown(ctx context.Context, ipComm IPCommunicator, wdd *waitDebugData) er "Ping encountered unexpected failure: {{.V0}}", err.Error(), ) - errs.Pack(err, wdd) + return errs.Pack(err, wdd) } } From c2022addccc567e5847672275a092edb1e5c4d89 Mon Sep 17 00:00:00 2001 From: daved Date: Fri, 19 May 2023 17:45:09 -0700 Subject: [PATCH 4/4] Add file info to wait debug output --- internal/ipc/client.go | 4 ++ internal/svcctl/debugdata.go | 91 +++++++++++++++++++++++++++++++----- internal/svcctl/svcctl.go | 5 +- 3 files changed, 86 insertions(+), 14 deletions(-) diff --git a/internal/ipc/client.go b/internal/ipc/client.go index dc6da797bf..d60e593ff1 100644 --- a/internal/ipc/client.go +++ b/internal/ipc/client.go @@ -23,6 +23,10 @@ func NewClient(n *SockPath) *Client { } } +func (c *Client) SockPath() *SockPath { + return c.sockpath +} + func (c *Client) Request(ctx context.Context, key string) (string, error) { spath := c.sockpath.String() conn, err := c.dialer.DialContext(ctx, network, spath) diff --git a/internal/svcctl/debugdata.go b/internal/svcctl/debugdata.go index 9bb0d62714..66d418fba5 100644 --- a/internal/svcctl/debugdata.go +++ b/internal/svcctl/debugdata.go @@ -2,8 +2,14 @@ package svcctl import ( "fmt" + "io/fs" + "os" + "path/filepath" "strings" "time" + + "github.com/ActiveState/cli/internal/fileutils" + "github.com/ActiveState/cli/internal/ipc" ) type execKind string @@ -31,42 +37,67 @@ func newWaitAttempt(waitStart, start time.Time, iter int, timeout time.Duration) func (a *waitAttempt) String() string { return fmt.Sprintf( - "Attempt %02d at %12s with timeout %v", - a.iter, a.start.Sub(a.waitStart), a.timeout, + "Attempt %2d at %10s with timeout %v", + a.iter, a.start.Sub(a.waitStart).Round(time.Microsecond), a.timeout, ) } func (a *waitAttempt) LogString() string { return fmt.Sprintf( - "%02d at %12s, wait %v", - a.iter, a.start.Sub(a.waitStart), a.timeout, + "%2d: %10s/%v", + a.iter, a.start.Sub(a.waitStart).Round(time.Microsecond), a.timeout, ) } type waitDebugData struct { - execStart time.Time - execDur time.Duration - execKind execKind + sockInfo *fileInfo + sockDirInfo *fileInfo + sockDirList []string + + execStart time.Time + execDur time.Duration + execKind execKind + waitStart time.Time waitAttempts []*waitAttempt waitDur time.Duration } -func newWaitDebugData(kind execKind) *waitDebugData { +func newWaitDebugData(sp *ipc.SockPath, kind execKind) *waitDebugData { + sock := sp.String() + sockDir := filepath.Dir(sock) + return &waitDebugData{ - execStart: time.Now(), - execKind: kind, + sockInfo: newFileInfo(sock), + sockDirInfo: newFileInfo(sockDir), + sockDirList: fileutils.ListDirSimple(sockDir, false), + execStart: time.Now(), + execKind: kind, } } func (d *waitDebugData) Error() string { + var sockDirList string + sep := " " + for _, entry := range d.sockDirList { + sockDirList += sep + entry + sep = "\n" + } + if sockDirList == "" { + sockDirList = "No entries found" + } + var attemptsMsg string - sep := " " + sep = " " for _, wa := range d.waitAttempts { attemptsMsg += sep + wa.LogString() sep = "\n " } + return fmt.Sprintf(strings.TrimSpace(` +Sock Info : %s +Sock Dir Info : %s +Sock Dir List : %s %s Start : %s %s Duration : %s Wait Start : %s @@ -74,11 +105,15 @@ Wait Duration : %s Wait Log: %s `), + strings.ReplaceAll(d.sockInfo.LogString(), "\n", "\n "), + strings.ReplaceAll(d.sockDirInfo.LogString(), "\n", "\n "), + sockDirList, d.execKind, d.execStart, d.execKind, d.execDur, d.waitStart, d.waitDur, - attemptsMsg) + attemptsMsg, + ) } func (d *waitDebugData) stampExec() { @@ -102,3 +137,35 @@ func (d *waitDebugData) stampWait() { } d.waitDur = time.Since(d.waitStart) } + +type fileInfo struct { + path string + fs.FileInfo + osFIErr error +} + +func newFileInfo(path string) *fileInfo { + fi := &fileInfo{ + path: path, + } + + fi.FileInfo, fi.osFIErr = os.Stat(path) + + return fi +} + +func (f *fileInfo) LogString() string { + if f.osFIErr != nil { + return fmt.Sprintf("%s, error: %s", f.path, f.osFIErr) + } + + // name + // size, mode, mod time + return fmt.Sprintf(strings.TrimSpace(` +%s +%d, %s, %s +`), + f.path, + f.Size(), f.Mode(), f.ModTime(), + ) +} diff --git a/internal/svcctl/svcctl.go b/internal/svcctl/svcctl.go index ab495e2fdb..75181ff56e 100644 --- a/internal/svcctl/svcctl.go +++ b/internal/svcctl/svcctl.go @@ -46,6 +46,7 @@ type IPCommunicator interface { Requester PingServer(context.Context) (time.Duration, error) StopServer(context.Context) error + SockPath() *ipc.SockPath } func NewIPCSockPathFromGlobals() *ipc.SockPath { @@ -153,7 +154,7 @@ func startAndWait(ipComm IPCommunicator, exec, argText string) error { args = args[:len(args)-1] } - wdd := newWaitDebugData(execSvc) + wdd := newWaitDebugData(ipComm.SockPath(), execSvc) if _, err := exeutils.ExecuteAndForget(exec, args); err != nil { return locale.WrapError( err, "svcctl_cannot_exec_and_forget", @@ -242,7 +243,7 @@ func stopAndWait(ipComm IPCommunicator) error { stopCtx, stopCancel := context.WithTimeout(context.Background(), ipCommTimeout) defer stopCancel() - wdd := newWaitDebugData(stopSvc) + wdd := newWaitDebugData(ipComm.SockPath(), stopSvc) if err := ipComm.StopServer(stopCtx); err != nil { return locale.WrapError(err, "svcctl_stop_req_failed", "Service stop request failed") }