lifecycle manages the lifecycle of the reconnecting pty. If the context ends or the reconnecting pty closes the pty will be shut down.
(ctx context.Context, logger slog.Logger)
| 125 | // lifecycle manages the lifecycle of the reconnecting pty. If the context ends |
| 126 | // or the reconnecting pty closes the pty will be shut down. |
| 127 | func (rpty *bufferedReconnectingPTY) lifecycle(ctx context.Context, logger slog.Logger) { |
| 128 | rpty.timer = time.AfterFunc(attachTimeout, func() { |
| 129 | rpty.Close(xerrors.New("reconnecting pty timeout")) |
| 130 | }) |
| 131 | |
| 132 | logger.Debug(ctx, "reconnecting pty ready") |
| 133 | rpty.state.setState(StateReady, nil) |
| 134 | |
| 135 | state, reasonErr := rpty.state.waitForStateOrContext(ctx, StateClosing) |
| 136 | if state < StateClosing { |
| 137 | // If we have not closed yet then the context is what unblocked us (which |
| 138 | // means the agent is shutting down) so move into the closing phase. |
| 139 | rpty.Close(reasonErr) |
| 140 | } |
| 141 | rpty.timer.Stop() |
| 142 | |
| 143 | rpty.state.cond.L.Lock() |
| 144 | // Log these closes only for debugging since the connections or processes |
| 145 | // might have already closed on their own. |
| 146 | for _, conn := range rpty.activeConns { |
| 147 | err := conn.Close() |
| 148 | if err != nil { |
| 149 | logger.Debug(ctx, "closed conn with error", slog.Error(err)) |
| 150 | } |
| 151 | } |
| 152 | // Connections get removed once they close but it is possible there is still |
| 153 | // some data that will be written before that happens so clear the map now to |
| 154 | // avoid writing to closed connections. |
| 155 | rpty.activeConns = map[string]net.Conn{} |
| 156 | rpty.state.cond.L.Unlock() |
| 157 | |
| 158 | // Log close/kill only for debugging since the process might have already |
| 159 | // closed on its own. |
| 160 | err := rpty.ptty.Close() |
| 161 | if err != nil { |
| 162 | logger.Debug(ctx, "closed ptty with error", slog.Error(err)) |
| 163 | } |
| 164 | |
| 165 | err = rpty.process.Kill() |
| 166 | if err != nil { |
| 167 | logger.Debug(ctx, "killed process with error", slog.Error(err)) |
| 168 | } |
| 169 | |
| 170 | logger.Info(ctx, "closed reconnecting pty") |
| 171 | rpty.state.setState(StateDone, reasonErr) |
| 172 | } |
| 173 | |
| 174 | func (rpty *bufferedReconnectingPTY) Attach(ctx context.Context, connID string, conn net.Conn, height, width uint16, logger slog.Logger) error { |
| 175 | logger.Info(ctx, "attach to reconnecting pty") |