fix: clean shutdown without connection errors
- Use read deadline + context check instead of forcibly closing connections - ReadBypassPending now takes context and exits cleanly on cancellation - Remove forced conn.Close() loop from Kill() - context cancellation suffices
This commit is contained in:
parent
9057d36f05
commit
85435447bf
|
|
@ -135,7 +135,7 @@ func (s *Session) runBypassLoop(notifyFn BypassNotifyFunc) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := conn.ReadBypassPending()
|
req, err := conn.ReadBypassPending(s.Ctx)
|
||||||
conn.Close()
|
conn.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
select {
|
select {
|
||||||
|
|
|
||||||
|
|
@ -198,8 +198,18 @@ func (s *Server) Start(conn net.Conn) {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
// Set read deadline so we can check for shutdown periodically
|
||||||
|
conn.SetReadDeadline(time.Now().Add(1 * time.Second))
|
||||||
fc, err := plan9.ReadFcall(conn)
|
fc, err := plan9.ReadFcall(conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// Check if shutdown was requested
|
||||||
|
if connCtx.Err() != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Timeout - loop and check context again
|
||||||
|
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if err != io.EOF {
|
if err != io.EOF {
|
||||||
s.log.Error("read: %v", err)
|
s.log.Error("read: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -704,11 +714,6 @@ func remove(root *fs.Tree, cs *connState, fc *plan9.Fcall) *plan9.Fcall {
|
||||||
|
|
||||||
func (s *Server) Kill() {
|
func (s *Server) Kill() {
|
||||||
s.shutdownCancel()
|
s.shutdownCancel()
|
||||||
s.connMu.Lock()
|
|
||||||
for conn := range s.activeConns {
|
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
s.connMu.Unlock()
|
|
||||||
session.Shutdown()
|
session.Shutdown()
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
|
|
|
||||||
|
|
@ -551,14 +551,25 @@ type BypassRequest struct {
|
||||||
|
|
||||||
// ReadBypassPending blocks until a bypass request is available.
|
// ReadBypassPending blocks until a bypass request is available.
|
||||||
// This should be called in a loop by the approval handler.
|
// This should be called in a loop by the approval handler.
|
||||||
func (c *Conn) ReadBypassPending() (*BypassRequest, error) {
|
// Returns nil, ctx.Err() if context is cancelled.
|
||||||
|
func (c *Conn) ReadBypassPending(ctx context.Context) (*BypassRequest, error) {
|
||||||
fid, err := c.fsys.Open("bypass/pending", plan9.OREAD)
|
fid, err := c.fsys.Open("bypass/pending", plan9.OREAD)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("open bypass/pending: %w", err)
|
return nil, fmt.Errorf("open bypass/pending: %w", err)
|
||||||
}
|
}
|
||||||
defer fid.Close()
|
|
||||||
|
|
||||||
// Blocking read - will return when a request is available
|
// Watch for context cancellation to unblock the read
|
||||||
|
done := make(chan struct{})
|
||||||
|
defer close(done)
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
fid.Close()
|
||||||
|
case <-done:
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Blocking read - will return when a request is available or fid is closed
|
||||||
var result []byte
|
var result []byte
|
||||||
buf := make([]byte, 8192)
|
buf := make([]byte, 8192)
|
||||||
for {
|
for {
|
||||||
|
|
@ -570,9 +581,14 @@ func (c *Conn) ReadBypassPending() (*BypassRequest, error) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fid.Close()
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
return nil, ctx.Err()
|
||||||
|
}
|
||||||
return nil, fmt.Errorf("read bypass/pending: %w", err)
|
return nil, fmt.Errorf("read bypass/pending: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fid.Close()
|
||||||
|
|
||||||
var req BypassRequest
|
var req BypassRequest
|
||||||
if err := json.Unmarshal(result, &req); err != nil {
|
if err := json.Unmarshal(result, &req); err != nil {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue