< Summary

Information
Class: Elsa.AI.Host.Streaming.AIStreamSessionManager
Assembly: Elsa.AI.Host
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.AI.Host/Streaming/AIStreamSessionManager.cs
Line coverage
82%
Covered lines: 28
Uncovered lines: 6
Coverable lines: 34
Total lines: 79
Line coverage: 82.3%
Branch coverage
80%
Covered branches: 16
Total branches: 20
Branch coverage: 80%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor()100%11100%
MarkDisconnected(...)100%11100%
CanReconnect(...)87.5%8881.81%
MarkConnected(...)100%11100%
ReleaseReconnect(...)62.5%11863.63%
PruneExpired(...)100%44100%
get_Deadline()100%11100%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.AI.Host/Streaming/AIStreamSessionManager.cs

#LineLine coverage
 1using System.Collections.Concurrent;
 2
 3namespace Elsa.AI.Host.Streaming;
 4
 5public class AIStreamSessionManager
 6{
 137    private readonly ConcurrentDictionary<string, ReconnectState> _reconnectStates = new(StringComparer.OrdinalIgnoreCas
 8
 9    public void MarkDisconnected(string conversationId, TimeSpan graceWindow)
 10    {
 811        var now = DateTimeOffset.UtcNow;
 812        _reconnectStates[conversationId] = new ReconnectState(now.Add(graceWindow), false);
 813        PruneExpired(now);
 814    }
 15
 16    public bool CanReconnect(string conversationId)
 17    {
 18        while (true)
 19        {
 2020            var now = DateTimeOffset.UtcNow;
 2021            PruneExpired(now);
 22
 2023            if (!_reconnectStates.TryGetValue(conversationId, out var state))
 1024                return false;
 25
 1026            if (state.Deadline < now)
 27            {
 028                _reconnectStates.TryRemove(conversationId, out _);
 029                return false;
 30            }
 31
 1032            if (state.IsReserved)
 133                return false;
 34
 935            if (_reconnectStates.TryUpdate(conversationId, state with { IsReserved = true }, state))
 936                return true;
 37        }
 38    }
 39
 40    public void MarkConnected(string conversationId)
 41    {
 242        _reconnectStates.TryRemove(conversationId, out _);
 243    }
 44
 45    public void ReleaseReconnect(string conversationId)
 46    {
 47        while (true)
 48        {
 349            var now = DateTimeOffset.UtcNow;
 350            PruneExpired(now);
 51
 352            if (!_reconnectStates.TryGetValue(conversationId, out var state))
 053                return;
 54
 355            if (state.Deadline < now)
 56            {
 057                _reconnectStates.TryRemove(conversationId, out _);
 058                return;
 59            }
 60
 361            if (!state.IsReserved)
 062                return;
 63
 364            if (_reconnectStates.TryUpdate(conversationId, state with { IsReserved = false }, state))
 365                return;
 66        }
 67    }
 68
 69    private void PruneExpired(DateTimeOffset now)
 70    {
 11271        foreach (var (conversationId, state) in _reconnectStates)
 72        {
 2573            if (state.Deadline < now)
 174                _reconnectStates.TryRemove(conversationId, out _);
 75        }
 3176    }
 77
 6378    private readonly record struct ReconnectState(DateTimeOffset Deadline, bool IsReserved);
 79}