Dashboard: admin-only Close session / Kill worker
Add IDashboardSessionAdminService (Admin-role gate, friendly errors, audit logging) wrapping a new ISessionManager.KillWorkerAsync that skips graceful shutdown and cleans up registry/metrics. Sessions, Workers, and SessionDetails pages render Close / Kill buttons only when CanManage; the service re-checks the role on every call so forged clicks return Unauthenticated. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -203,6 +203,56 @@ public sealed class SessionManager : ISessionManager
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forcefully terminates a session's worker without attempting graceful shutdown.
|
||||
/// Mirrors the registry/metrics cleanup that <see cref="CloseSessionCoreAsync"/>
|
||||
/// performs after a successful close, but skips the <c>WorkerClient.ShutdownAsync</c>
|
||||
/// step that <see cref="GatewaySession.CloseAsync"/> would otherwise attempt.
|
||||
/// </summary>
|
||||
/// <param name="sessionId">Session identifier.</param>
|
||||
/// <param name="reason">Reason recorded for the kill.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Session close result.</returns>
|
||||
public async Task<SessionCloseResult> KillWorkerAsync(
|
||||
string sessionId,
|
||||
string reason,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(reason);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
GatewaySession session = GetRequiredSession(sessionId);
|
||||
bool wasClosed = session.State == SessionState.Closed;
|
||||
|
||||
try
|
||||
{
|
||||
session.KillWorker(reason);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
session.MarkFaulted(exception.Message);
|
||||
_metrics.Fault(SessionManagerErrorCode.CloseFailed.ToString());
|
||||
await RemoveSessionAsync(session).ConfigureAwait(false);
|
||||
throw new SessionManagerException(
|
||||
SessionManagerErrorCode.CloseFailed,
|
||||
$"Failed to kill worker for session {sessionId}.",
|
||||
exception);
|
||||
}
|
||||
|
||||
if (!wasClosed)
|
||||
{
|
||||
_metrics.SessionClosed();
|
||||
}
|
||||
|
||||
await RemoveSessionAsync(session).ConfigureAwait(false);
|
||||
_logger.LogInformation(
|
||||
"Worker for session {SessionId} killed; reason={Reason}.",
|
||||
sessionId,
|
||||
reason);
|
||||
|
||||
return new SessionCloseResult(sessionId, SessionState.Closed, AlreadyClosed: wasClosed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes all sessions with expired leases asynchronously.
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user