Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,12 @@ private void SearchSessions()
/// </summary>
private async Task ReadUserSessionLogs(Guid userSessionId)
{
var logs = await hubConnection.InvokeAsync<DiagnosticLogDto[]>("GetUserSessionLogs", userSessionId);

DiagnosticLogger.Store.Clear();
foreach (var log in logs)

await foreach (var log in hubConnection.StreamAsync<DiagnosticLogDto>(
"GetUserSessionLogs",
userSessionId,
cancellationToken: CurrentCancellationToken))
{
DiagnosticLogger.Store.Enqueue(log);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//+:cnd:noEmit
using System.Runtime.CompilerServices;
using Boilerplate.Server.Api.Controllers.Identity;
using Boilerplate.Server.Api.Models.Identity;
using Boilerplate.Shared.Dtos.Diagnostic;
Expand Down Expand Up @@ -66,17 +67,30 @@ public Task ChangeAuthenticationState(string? accessToken)
/// <inheritdoc cref="SignalRMethods.UPLOAD_DIAGNOSTIC_LOGGER_STORE"/>
/// </summary>
[Authorize(Policy = AppFeatures.System.ManageLogs)]
public async Task<DiagnosticLogDto[]> GetUserSessionLogs(Guid userSessionId, [FromServices] AppDbContext dbContext)
public async IAsyncEnumerable<DiagnosticLogDto> GetUserSessionLogs(
Guid userSessionId,
[EnumeratorCancellation] CancellationToken cancellationToken,
[FromServices] AppDbContext dbContext)
{
var userSessionSignalRConnectionId = await dbContext.UserSessions
.Where(us => us.Id == userSessionId)
.Select(us => us.SignalRConnectionId)
.FirstOrDefaultAsync(Context.ConnectionAborted);
.FirstOrDefaultAsync(cancellationToken);

if (string.IsNullOrEmpty(userSessionSignalRConnectionId))
return [];
yield break;

return await Clients.Client(userSessionSignalRConnectionId).InvokeAsync<DiagnosticLogDto[]>(SignalRMethods.UPLOAD_DIAGNOSTIC_LOGGER_STORE, Context.ConnectionAborted);
var logs = await Clients.Client(userSessionSignalRConnectionId)
.InvokeAsync<DiagnosticLogDto[]>(SignalRMethods.UPLOAD_DIAGNOSTIC_LOGGER_STORE, cancellationToken);

if (logs is null || logs.Length is 0)
yield break;

foreach (var log in logs)
{
cancellationToken.ThrowIfCancellationRequested();
yield return log;
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

This implementation doesn't solve the root cause of the SignalR message size error.

The PR aims to fix the "maximum message size of 32768B was exceeded" error when reading user session logs. However, this implementation only streams logs from the hub to the admin client, but the error occurs when the target user's client returns all logs at once to the hub via InvokeAsync<DiagnosticLogDto[]>.

Architecture flow:

  1. Admin client → GetUserSessionLogs → Hub
  2. Hub → InvokeAsync<DiagnosticLogDto[]> → Target client ⚠️ 32KB error occurs here
  3. Target client → returns all logs at once → Hub
  4. Hub → yields logs one by one → Admin client ✅ (streaming works here, but too late)

Impact: Users will still encounter the same SignalR message size error for sessions with large log volumes.

To properly fix this issue, the target client (the one whose logs are being read) must also stream its logs or batch them into smaller chunks. Consider:

  • Implementing a streaming method on the client side that yields logs incrementally
  • Having the client batch logs into smaller arrays (e.g., 100 logs per batch)
  • Implementing a different retrieval mechanism that doesn't rely on a single InvokeAsync call with a potentially large payload


private async Task ChangeAuthenticationStateImplementation(ClaimsPrincipal? user)
Expand Down