Skip to content

Commit d5984b7

Browse files
iamayushmkishan789dev
authored and
kishan789dev
committed
fix: terminal stuck in connecting state (#4989)
* closing channel after write operation * removing close * using buffered channel * wip: making done channel bufferred * terminal racecondition and deadlock fix * wire run * removing done send call * updating bound channel send function
1 parent c4b3d16 commit d5984b7

File tree

2 files changed

+38
-17
lines changed

2 files changed

+38
-17
lines changed

pkg/terminal/terminalSesion.go

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import (
4848

4949
const END_OF_TRANSMISSION = "\u0004"
5050
const ProcessExitedMsg = "Process exited"
51+
const ProcessTimedOut = "Process timedOut"
5152

5253
// PtyHandler is what remotecommand expects from a pty
5354
type PtyHandler interface {
@@ -185,23 +186,53 @@ func (sm *SessionMap) SetTerminalSessionStartTime(sessionId string) {
185186
}
186187
}
187188

189+
func (sm *SessionMap) setAndSendSignal(sessionId string, session sockjs.Session) {
190+
sm.Lock.Lock()
191+
defer sm.Lock.Unlock()
192+
terminalSession, ok := sm.Sessions[sessionId]
193+
if ok && terminalSession.id == "" {
194+
log.Printf("handleTerminalSession: can't find session '%s'", sessionId)
195+
session.Close(http.StatusGone, fmt.Sprintf("handleTerminalSession: can't find session '%s'", sessionId))
196+
return
197+
} else if ok {
198+
terminalSession.sockJSSession = session
199+
sm.Sessions[sessionId] = terminalSession
200+
201+
select {
202+
case terminalSession.bound <- nil:
203+
log.Printf("message sent on bound channel for sessionId : %s", sessionId)
204+
default:
205+
// if a request from the front end is not received within a particular time frame, and no one is reading from the bound channel, we will ignore sending on the bound channel.
206+
log.Printf("skipping send on bound, channel receiver possibly timed out. sessionId: %s", sessionId)
207+
}
208+
209+
}
210+
}
211+
188212
// Close shuts down the SockJS connection and sends the status code and reason to the client
189213
// Can happen if the process exits or if there is an error starting up the process
190214
// For now the status code is unused and reason is shown to the user (unless "")
191215
func (sm *SessionMap) Close(sessionId string, status uint32, reason string) {
216+
192217
sm.Lock.Lock()
193218
defer sm.Lock.Unlock()
219+
194220
terminalSession := sm.Sessions[sessionId]
221+
195222
if terminalSession.sockJSSession != nil {
223+
196224
err := terminalSession.sockJSSession.Close(status, reason)
197225
if err != nil {
198226
log.Println(err)
199227
}
228+
229+
close(terminalSession.doneChan)
230+
200231
isErroredConnectionTermination := isConnectionClosedByError(status)
201232
middleware.IncTerminalSessionRequestCounter(SessionTerminated, strconv.FormatBool(isErroredConnectionTermination))
202233
middleware.RecordTerminalSessionDurationMetrics(terminalSession.podName, terminalSession.namespace, terminalSession.clusterId, time.Since(terminalSession.startedOn).Seconds())
203-
close(terminalSession.doneChan)
204234
terminalSession.contextCancelFunc()
235+
close(terminalSession.bound)
205236
delete(sm.Sessions, sessionId)
206237
}
207238

@@ -219,10 +250,9 @@ var terminalSessions = SessionMap{Sessions: make(map[string]TerminalSession)}
219250
// handleTerminalSession is Called by net/http for any new /api/sockjs connections
220251
func handleTerminalSession(session sockjs.Session) {
221252
var (
222-
buf string
223-
err error
224-
msg TerminalMessage
225-
terminalSession TerminalSession
253+
buf string
254+
err error
255+
msg TerminalMessage
226256
)
227257

228258
if buf, err = session.Recv(); err != nil {
@@ -241,15 +271,8 @@ func handleTerminalSession(session sockjs.Session) {
241271
return
242272
}
243273

244-
if terminalSession = terminalSessions.Get(msg.SessionID); terminalSession.id == "" {
245-
log.Printf("handleTerminalSession: can't find session '%s'", msg.SessionID)
246-
session.Close(http.StatusGone, fmt.Sprintf("handleTerminalSession: can't find session '%s'", msg.SessionID))
247-
return
248-
}
274+
terminalSessions.setAndSendSignal(msg.SessionID, session)
249275

250-
terminalSession.sockJSSession = session
251-
terminalSessions.Set(msg.SessionID, terminalSession)
252-
terminalSession.bound <- nil
253276
}
254277

255278
type SocketConfig struct {
@@ -381,7 +404,6 @@ func WaitForTerminal(k8sClient kubernetes.Interface, cfg *rest.Config, request *
381404
timedCtx, _ := context.WithTimeout(sessionCtx, 60*time.Second)
382405
select {
383406
case <-session.bound:
384-
close(session.bound)
385407

386408
var err error
387409
if isValidShell(validShells, request.Shell) {
@@ -407,8 +429,7 @@ func WaitForTerminal(k8sClient kubernetes.Interface, cfg *rest.Config, request *
407429
terminalSessions.Close(request.SessionId, 1, ProcessExitedMsg)
408430
case <-timedCtx.Done():
409431
// handle case when connection has not been initiated from FE side within particular time
410-
close(session.bound)
411-
terminalSessions.Close(request.SessionId, 1, ProcessExitedMsg)
432+
terminalSessions.Close(request.SessionId, 1, ProcessTimedOut)
412433
}
413434
}
414435

wire_gen.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)