⚡ Optimized last active flush handler
This commit is contained in:
		@@ -12,11 +12,14 @@ public class LastActiveInfo
 | 
			
		||||
    public Instant SeenAt { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public class LastActiveFlushHandler(IServiceProvider serviceProvider) : IFlushHandler<LastActiveInfo>
 | 
			
		||||
public class LastActiveFlushHandler(IServiceProvider srp, ILogger<LastActiveFlushHandler> logger)
 | 
			
		||||
    : IFlushHandler<LastActiveInfo>
 | 
			
		||||
{
 | 
			
		||||
    public async Task FlushAsync(IReadOnlyList<LastActiveInfo> items)
 | 
			
		||||
    {
 | 
			
		||||
        using var scope = serviceProvider.CreateScope();
 | 
			
		||||
        logger.LogInformation("Flushing {Count} LastActiveInfo items...", items.Count);
 | 
			
		||||
        
 | 
			
		||||
        using var scope = srp.CreateScope();
 | 
			
		||||
        var db = scope.ServiceProvider.GetRequiredService<AppDatabase>();
 | 
			
		||||
 | 
			
		||||
        // Remove duplicates by grouping on (sessionId, accountId), taking the most recent SeenAt
 | 
			
		||||
@@ -26,29 +29,27 @@ public class LastActiveFlushHandler(IServiceProvider serviceProvider) : IFlushHa
 | 
			
		||||
            .ToList();
 | 
			
		||||
 | 
			
		||||
        // Build dictionaries so we can match session/account IDs to their new "last seen" timestamps
 | 
			
		||||
        var sessionIdMap = distinctItems
 | 
			
		||||
        var sessionMap = distinctItems
 | 
			
		||||
            .GroupBy(x => x.Session.Id)
 | 
			
		||||
            .ToDictionary(g => g.Key, g => g.Last().SeenAt);
 | 
			
		||||
 | 
			
		||||
        var accountIdMap = distinctItems
 | 
			
		||||
        var accountMap = distinctItems
 | 
			
		||||
            .GroupBy(x => x.Account.Id)
 | 
			
		||||
            .ToDictionary(g => g.Key, g => g.Last().SeenAt);
 | 
			
		||||
 | 
			
		||||
        // Update sessions using native EF Core ExecuteUpdateAsync
 | 
			
		||||
        foreach (var kvp in sessionIdMap)
 | 
			
		||||
        {
 | 
			
		||||
            await db.AuthSessions
 | 
			
		||||
                .Where(s => s.Id == kvp.Key)
 | 
			
		||||
                .ExecuteUpdateAsync(s => s.SetProperty(x => x.LastGrantedAt, kvp.Value));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Update account profiles using native EF Core ExecuteUpdateAsync
 | 
			
		||||
        foreach (var kvp in accountIdMap)
 | 
			
		||||
        {
 | 
			
		||||
            await db.AccountProfiles
 | 
			
		||||
                .Where(a => a.AccountId == kvp.Key)
 | 
			
		||||
                .ExecuteUpdateAsync(a => a.SetProperty(x => x.LastSeenAt, kvp.Value));
 | 
			
		||||
        }
 | 
			
		||||
        var now = SystemClock.Instance.GetCurrentInstant();
 | 
			
		||||
        
 | 
			
		||||
        var updatingSessions = sessionMap.Select(x => x.Key).ToList();
 | 
			
		||||
        var sessionUpdates = await db.AuthSessions
 | 
			
		||||
            .Where(s => updatingSessions.Contains(s.Id))
 | 
			
		||||
            .ExecuteUpdateAsync(s => s.SetProperty(x => x.LastGrantedAt, now));
 | 
			
		||||
        logger.LogInformation("Updated {Count} auth sessions according to LastActiveInfo", sessionUpdates);
 | 
			
		||||
        
 | 
			
		||||
        var updatingAccounts = accountMap.Select(x => x.Key).ToList();
 | 
			
		||||
        var profileUpdates = await db.AccountProfiles
 | 
			
		||||
            .Where(a => updatingAccounts.Contains(a.AccountId))
 | 
			
		||||
            .ExecuteUpdateAsync(a => a.SetProperty(x => x.LastSeenAt, now));
 | 
			
		||||
        logger.LogInformation("Updated {Count} account profiles according to LastActiveInfo", profileUpdates);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user