mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 11:03:34 +00:00
fix(exec): Handle context cancellation server-side
This commit is contained in:
@@ -1049,6 +1049,13 @@ func (s *Server) handleServerExecInput(
|
|||||||
|
|
||||||
defer attachConn.CloseWrite()
|
defer attachConn.CloseWrite()
|
||||||
for {
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
slog.Debug("Input goroutine context canceled via context", "exec_id", execID)
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
req, err := stream.Recv()
|
req, err := stream.Recv()
|
||||||
switch {
|
switch {
|
||||||
case errors.Is(err, io.EOF):
|
case errors.Is(err, io.EOF):
|
||||||
@@ -1209,9 +1216,9 @@ func (s *Server) ExecContainer(stream pb.Docker_ExecContainerServer) error {
|
|||||||
}
|
}
|
||||||
defer attachConn.Close()
|
defer attachConn.Close()
|
||||||
|
|
||||||
// Create a cancelable context for the handlers
|
// Create a cancelable context for the input handler
|
||||||
handlerCtx, cancel := context.WithCancel(ctx)
|
handlerCtx, cancelInput := context.WithCancel(ctx)
|
||||||
defer cancel() // Ensure handlers are canceled when we return
|
defer cancelInput()
|
||||||
|
|
||||||
// Create a channel to wait for output completion
|
// Create a channel to wait for output completion
|
||||||
outputDone := make(chan error, 1)
|
outputDone := make(chan error, 1)
|
||||||
@@ -1236,13 +1243,14 @@ func (s *Server) ExecContainer(stream pb.Docker_ExecContainerServer) error {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// Wait for the output goroutine to complete (it signals when done)
|
// Wait for the output goroutine to complete (it signals when done)
|
||||||
// We only wait for output, not for stdin goroutine.
|
// We only wait for the output handler goroutine, not for the stdin one.
|
||||||
if err := <-outputDone; err != nil {
|
if err := <-outputDone; err != nil {
|
||||||
slog.Warn("Error in exec output handler", "err", err, "exec_id", execResp.ID)
|
slog.Warn("Error in exec output handler", "err", err, "exec_id", execResp.ID)
|
||||||
}
|
}
|
||||||
// The stdin goroutine may still be blocked in stream.Recv() waiting for client data,
|
// Do a best-effort cancellation of the stdin handler.
|
||||||
// so cancel it explicitly.
|
// We can't guarantee immediate exit because it may be blocked on stream.Recv(), but at
|
||||||
cancel()
|
// least we want to send a cancel signal explicitly.
|
||||||
|
cancelInput()
|
||||||
|
|
||||||
inspectResp, err := s.client.ContainerExecInspect(ctx, execResp.ID)
|
inspectResp, err := s.client.ContainerExecInspect(ctx, execResp.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user