1
1
using System ;
2
+ using System . Collections . Generic ;
2
3
using System . Threading ;
3
- using Exceptionless . Logging ;
4
4
using Exceptionless . Models ;
5
- using Exceptionless . Queue ;
6
5
7
6
namespace Exceptionless . Plugins . Default {
8
7
[ Priority ( 110 ) ]
9
8
public class HeartbeatPlugin : IEventPlugin , IDisposable {
10
- private readonly IEventQueue _eventQueue ;
11
- private readonly IExceptionlessLog _log ;
12
- private Timer _timer ;
13
- private Event _lastEvent ;
14
-
15
- public HeartbeatPlugin ( IEventQueue eventQueue , IExceptionlessLog log ) {
16
- _eventQueue = eventQueue ;
17
- _log = log ;
18
- }
9
+ private readonly Dictionary < string , SessionHeartbeat > _sessionHeartbeats = new Dictionary < string , SessionHeartbeat > ( ) ;
10
+ private readonly object _lock = new object ( ) ;
19
11
20
12
public void Run ( EventPluginContext context ) {
21
13
var sessionIdentifier = context . Event . SessionId ?? context . Event . GetUserIdentity ( ) ? . Identity ;
22
- if ( String . IsNullOrEmpty ( sessionIdentifier ) || context . Event . IsSessionEnd ( ) ) {
23
- _lastEvent = null ;
24
- _timer ? . Change ( Timeout . Infinite , Timeout . Infinite ) ;
14
+ if ( String . IsNullOrEmpty ( sessionIdentifier ) || context . Event . Type == Event . KnownTypes . SessionHeartbeat )
25
15
return ;
26
- }
27
16
28
- _lastEvent = context . Event ;
29
- if ( _timer == null )
30
- _timer = new Timer ( OnEnqueueHeartbeat , null , TimeSpan . FromSeconds ( 30 ) , TimeSpan . FromSeconds ( 30 ) ) ;
31
- else
32
- _timer . Change ( TimeSpan . FromSeconds ( 30 ) , TimeSpan . FromSeconds ( 30 ) ) ;
17
+ lock ( _lock ) {
18
+ if ( ! _sessionHeartbeats . ContainsKey ( sessionIdentifier ) )
19
+ _sessionHeartbeats . Add ( sessionIdentifier , new SessionHeartbeat ( sessionIdentifier , context . Client ) ) ;
20
+ else if ( context . Event . IsSessionEnd ( ) ) {
21
+ _sessionHeartbeats [ sessionIdentifier ] . Dispose ( ) ;
22
+ _sessionHeartbeats . Remove ( sessionIdentifier ) ;
23
+ } else
24
+ _sessionHeartbeats [ sessionIdentifier ] . DelayNext ( ) ;
25
+ }
33
26
}
34
27
35
- private void OnEnqueueHeartbeat ( object state ) {
36
- var heartbeatEvent = CreateHeartbeatEvent ( _lastEvent ) ;
37
- if ( heartbeatEvent == null )
38
- return ;
28
+ public void Dispose ( ) {
29
+ lock ( _lock ) {
30
+ foreach ( var kvp in _sessionHeartbeats )
31
+ kvp . Value . Dispose ( ) ;
32
+ }
39
33
40
- _log . Trace ( nameof ( HeartbeatPlugin ) , $ "Enqueuing heartbeat for session: { heartbeatEvent . SessionId } ") ;
41
- _eventQueue . Enqueue ( heartbeatEvent ) ;
34
+ _sessionHeartbeats . Clear ( ) ;
35
+ }
36
+ }
37
+ public class SessionHeartbeat : IDisposable {
38
+ private readonly Timer _timer ;
39
+ private readonly int _interval = 30 * 1000 ;
40
+ private readonly ExceptionlessClient _client ;
41
+
42
+ public SessionHeartbeat ( string sessionId , ExceptionlessClient client ) {
43
+ SessionId = sessionId ;
44
+ _client = client ;
45
+ _timer = new Timer ( SendHeartbeat , null , _interval , _interval ) ;
42
46
}
43
47
44
- private Event CreateHeartbeatEvent ( Event source ) {
45
- if ( source == null )
46
- return null ;
47
-
48
- var heartbeatEvent = new Event {
49
- Date = DateTimeOffset . Now ,
50
- Type = Event . KnownTypes . Heartbeat ,
51
- SessionId = source . SessionId
52
- } ;
48
+ public string SessionId { get ; set ; }
53
49
54
- heartbeatEvent . SetUserIdentity ( source . GetUserIdentity ( ) ) ;
50
+ public void DelayNext ( ) {
51
+ _timer . Change ( _interval , _interval ) ;
52
+ }
55
53
56
- return heartbeatEvent ;
54
+ private void SendHeartbeat ( object state ) {
55
+ _client . SubmitEvent ( new Event { Type = Event . KnownTypes . SessionHeartbeat , SessionId = SessionId } ) ;
57
56
}
58
57
59
58
public void Dispose ( ) {
60
- if ( _timer == null )
61
- return ;
62
-
63
- _timer . Dispose ( ) ;
64
- _timer = null ;
59
+ _timer ? . Dispose ( ) ;
65
60
}
66
61
}
67
62
}
0 commit comments