Skip to content

Commit 38c7dcd

Browse files
authored
fix: avoid vscodessh exit when server restarts (#13970)
Mitigates an issue where vscodessh would restart when the control plane restarts, causing the entire SSH session to be reestablished.
1 parent d2b0353 commit 38c7dcd

File tree

1 file changed

+42
-9
lines changed

1 file changed

+42
-9
lines changed

cli/vscodessh.go

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,11 @@ func (r *RootCmd) vscodeSSH() *serpent.Command {
151151
// command via the ProxyCommand SSH option.
152152
pid := os.Getppid()
153153

154-
logger := inv.Logger
154+
// Use a stripped down writer that doesn't sync, otherwise you get
155+
// "failed to sync sloghuman: sync /dev/stderr: The handle is
156+
// invalid" on Windows. Syncing isn't required for stdout/stderr
157+
// anyways.
158+
logger := inv.Logger.AppendSinks(sloghuman.Sink(slogWriter{w: inv.Stderr})).Leveled(slog.LevelDebug)
155159
if logDir != "" {
156160
logFilePath := filepath.Join(logDir, fmt.Sprintf("%d.log", pid))
157161
logFile, err := fs.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY, 0o600)
@@ -160,7 +164,7 @@ func (r *RootCmd) vscodeSSH() *serpent.Command {
160164
}
161165
dc := cliutil.DiscardAfterClose(logFile)
162166
defer dc.Close()
163-
logger = logger.AppendSinks(sloghuman.Sink(dc)).Leveled(slog.LevelDebug)
167+
logger = logger.AppendSinks(sloghuman.Sink(dc))
164168
}
165169
if r.disableDirect {
166170
logger.Info(ctx, "direct connections disabled")
@@ -204,31 +208,48 @@ func (r *RootCmd) vscodeSSH() *serpent.Command {
204208
// command via the ProxyCommand SSH option.
205209
networkInfoFilePath := filepath.Join(networkInfoDir, fmt.Sprintf("%d.json", pid))
206210

207-
statsErrChan := make(chan error, 1)
211+
var (
212+
firstErrTime time.Time
213+
errCh = make(chan error, 1)
214+
)
208215
cb := func(start, end time.Time, virtual, _ map[netlogtype.Connection]netlogtype.Counts) {
209-
sendErr := func(err error) {
216+
sendErr := func(tolerate bool, err error) {
217+
logger.Error(ctx, "collect network stats", slog.Error(err))
218+
// Tolerate up to 1 minute of errors.
219+
if tolerate {
220+
if firstErrTime.IsZero() {
221+
logger.Info(ctx, "tolerating network stats errors for up to 1 minute")
222+
firstErrTime = time.Now()
223+
}
224+
if time.Since(firstErrTime) < time.Minute {
225+
return
226+
}
227+
}
228+
210229
select {
211-
case statsErrChan <- err:
230+
case errCh <- err:
212231
default:
213232
}
214233
}
215234

216235
stats, err := collectNetworkStats(ctx, agentConn, start, end, virtual)
217236
if err != nil {
218-
sendErr(err)
237+
sendErr(true, err)
219238
return
220239
}
221240

222241
rawStats, err := json.Marshal(stats)
223242
if err != nil {
224-
sendErr(err)
243+
sendErr(false, err)
225244
return
226245
}
227246
err = afero.WriteFile(fs, networkInfoFilePath, rawStats, 0o600)
228247
if err != nil {
229-
sendErr(err)
248+
sendErr(false, err)
230249
return
231250
}
251+
252+
firstErrTime = time.Time{}
232253
}
233254

234255
now := time.Now()
@@ -238,7 +259,7 @@ func (r *RootCmd) vscodeSSH() *serpent.Command {
238259
select {
239260
case <-ctx.Done():
240261
return nil
241-
case err := <-statsErrChan:
262+
case err := <-errCh:
242263
return err
243264
}
244265
},
@@ -280,6 +301,18 @@ func (r *RootCmd) vscodeSSH() *serpent.Command {
280301
return cmd
281302
}
282303

304+
// slogWriter wraps an io.Writer and removes all other methods (such as Sync),
305+
// which may cause undesired/broken behavior.
306+
type slogWriter struct {
307+
w io.Writer
308+
}
309+
310+
var _ io.Writer = slogWriter{}
311+
312+
func (s slogWriter) Write(p []byte) (n int, err error) {
313+
return s.w.Write(p)
314+
}
315+
283316
type sshNetworkStats struct {
284317
P2P bool `json:"p2p"`
285318
Latency float64 `json:"latency"`

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy