1
- using EventStore . Client . PersistentSubscriptions ;
2
- using Grpc . Core ;
3
1
using Microsoft . Extensions . Logging ;
4
2
5
3
namespace EventStore . Client {
6
4
/// <summary>
7
5
/// Represents a persistent subscription connection.
8
6
/// </summary>
9
7
public class PersistentSubscription : IDisposable {
10
- private readonly EventStorePersistentSubscriptionsClient . PersistentSubscriptionResult _persistentSubscriptionResult ;
8
+ private readonly EventStorePersistentSubscriptionsClient . PersistentSubscriptionResult
9
+ _persistentSubscriptionResult ;
10
+
11
11
private readonly IAsyncEnumerator < PersistentSubscriptionMessage > _enumerator ;
12
12
private readonly Func < PersistentSubscription , ResolvedEvent , int ? , CancellationToken , Task > _eventAppeared ;
13
13
private readonly Action < PersistentSubscription , SubscriptionDroppedReason , Exception ? > _subscriptionDropped ;
@@ -25,7 +25,8 @@ internal static async Task<PersistentSubscription> Confirm(
25
25
EventStorePersistentSubscriptionsClient . PersistentSubscriptionResult persistentSubscriptionResult ,
26
26
Func < PersistentSubscription , ResolvedEvent , int ? , CancellationToken , Task > eventAppeared ,
27
27
Action < PersistentSubscription , SubscriptionDroppedReason , Exception ? > subscriptionDropped ,
28
- ILogger log , UserCredentials ? userCredentials , CancellationToken cancellationToken = default ) {
28
+ ILogger log , UserCredentials ? userCredentials , CancellationToken cancellationToken = default
29
+ ) {
29
30
var enumerator = persistentSubscriptionResult
30
31
. Messages
31
32
. GetAsyncEnumerator ( cancellationToken ) ;
@@ -34,11 +35,20 @@ internal static async Task<PersistentSubscription> Confirm(
34
35
35
36
return ( result , enumerator . Current ) switch {
36
37
( true , PersistentSubscriptionMessage . SubscriptionConfirmation ( var subscriptionId ) ) =>
37
- new PersistentSubscription ( persistentSubscriptionResult , enumerator , subscriptionId , eventAppeared ,
38
- subscriptionDropped , log , cancellationToken ) ,
38
+ new PersistentSubscription (
39
+ persistentSubscriptionResult ,
40
+ enumerator ,
41
+ subscriptionId ,
42
+ eventAppeared ,
43
+ subscriptionDropped ,
44
+ log ,
45
+ cancellationToken
46
+ ) ,
39
47
( true , PersistentSubscriptionMessage . NotFound ) =>
40
- throw new PersistentSubscriptionNotFoundException ( persistentSubscriptionResult . StreamName ,
41
- persistentSubscriptionResult . GroupName ) ,
48
+ throw new PersistentSubscriptionNotFoundException (
49
+ persistentSubscriptionResult . StreamName ,
50
+ persistentSubscriptionResult . GroupName
51
+ ) ,
42
52
_ => throw new InvalidOperationException ( "Subscription could not be confirmed." )
43
53
} ;
44
54
}
@@ -49,14 +59,15 @@ private PersistentSubscription(
49
59
IAsyncEnumerator < PersistentSubscriptionMessage > enumerator , string subscriptionId ,
50
60
Func < PersistentSubscription , ResolvedEvent , int ? , CancellationToken , Task > eventAppeared ,
51
61
Action < PersistentSubscription , SubscriptionDroppedReason , Exception ? > subscriptionDropped , ILogger log ,
52
- CancellationToken cancellationToken ) {
62
+ CancellationToken cancellationToken
63
+ ) {
53
64
_persistentSubscriptionResult = persistentSubscriptionResult ;
54
- _enumerator = enumerator ;
55
- SubscriptionId = subscriptionId ;
56
- _eventAppeared = eventAppeared ;
57
- _subscriptionDropped = subscriptionDropped ;
58
- _log = log ;
59
- _cts = CancellationTokenSource . CreateLinkedTokenSource ( cancellationToken ) ;
65
+ _enumerator = enumerator ;
66
+ SubscriptionId = subscriptionId ;
67
+ _eventAppeared = eventAppeared ;
68
+ _subscriptionDropped = subscriptionDropped ;
69
+ _log = log ;
70
+ _cts = CancellationTokenSource . CreateLinkedTokenSource ( cancellationToken ) ;
60
71
61
72
Task . Run ( Subscribe , _cts . Token ) ;
62
73
}
@@ -91,15 +102,15 @@ public Task Ack(params ResolvedEvent[] resolvedEvents) =>
91
102
public Task Ack ( IEnumerable < ResolvedEvent > resolvedEvents ) =>
92
103
Ack ( resolvedEvents . Select ( resolvedEvent => resolvedEvent . OriginalEvent . EventId ) ) ;
93
104
94
-
95
105
/// <summary>
96
106
/// Acknowledge that a message has failed processing (this will tell the server it has not been processed).
97
107
/// </summary>
98
108
/// <param name="action">The <see cref="PersistentSubscriptionNakEventAction"/> to take.</param>
99
109
/// <param name="reason">A reason given.</param>
100
110
/// <param name="eventIds">The <see cref="Uuid"/> of the <see cref="ResolvedEvent" />s to nak. There should not be more than 2000 to nak at a time.</param>
101
111
/// <exception cref="ArgumentException">The number of eventIds exceeded the limit of 2000.</exception>
102
- public Task Nack ( PersistentSubscriptionNakEventAction action , string reason , params Uuid [ ] eventIds ) => NackInternal ( eventIds , action , reason ) ;
112
+ public Task Nack ( PersistentSubscriptionNakEventAction action , string reason , params Uuid [ ] eventIds ) =>
113
+ NackInternal ( eventIds , action , reason ) ;
103
114
104
115
/// <summary>
105
116
/// Acknowledge that a message has failed processing (this will tell the server it has not been processed).
@@ -108,10 +119,15 @@ public Task Ack(IEnumerable<ResolvedEvent> resolvedEvents) =>
108
119
/// <param name="reason">A reason given.</param>
109
120
/// <param name="resolvedEvents">The <see cref="ResolvedEvent" />s to nak. There should not be more than 2000 to nak at a time.</param>
110
121
/// <exception cref="ArgumentException">The number of resolvedEvents exceeded the limit of 2000.</exception>
111
- public Task Nack ( PersistentSubscriptionNakEventAction action , string reason ,
112
- params ResolvedEvent [ ] resolvedEvents ) =>
113
- Nack ( action , reason ,
114
- Array . ConvertAll ( resolvedEvents , resolvedEvent => resolvedEvent . OriginalEvent . EventId ) ) ;
122
+ public Task Nack (
123
+ PersistentSubscriptionNakEventAction action , string reason ,
124
+ params ResolvedEvent [ ] resolvedEvents
125
+ ) =>
126
+ Nack (
127
+ action ,
128
+ reason ,
129
+ Array . ConvertAll ( resolvedEvents , resolvedEvent => resolvedEvent . OriginalEvent . EventId )
130
+ ) ;
115
131
116
132
/// <inheritdoc />
117
133
public void Dispose ( ) => SubscriptionDropped ( SubscriptionDroppedReason . Disposed ) ;
@@ -121,64 +137,94 @@ private async Task Subscribe() {
121
137
122
138
try {
123
139
while ( await _enumerator . MoveNextAsync ( _cts . Token ) . ConfigureAwait ( false ) ) {
124
- if ( _enumerator . Current is not PersistentSubscriptionMessage . Event ( var resolvedEvent , var retryCount ) ) {
140
+ if ( _enumerator . Current is not
141
+ PersistentSubscriptionMessage . Event ( var resolvedEvent , var retryCount ) ) {
125
142
continue ;
126
143
}
127
144
128
145
if ( _enumerator . Current is PersistentSubscriptionMessage . NotFound ) {
129
146
if ( _subscriptionDroppedInvoked != 0 ) {
130
147
return ;
131
148
}
132
- SubscriptionDropped ( SubscriptionDroppedReason . ServerError ,
149
+
150
+ SubscriptionDropped (
151
+ SubscriptionDroppedReason . ServerError ,
133
152
new PersistentSubscriptionNotFoundException (
134
- _persistentSubscriptionResult . StreamName , _persistentSubscriptionResult . GroupName ) ) ;
153
+ _persistentSubscriptionResult . StreamName ,
154
+ _persistentSubscriptionResult . GroupName
155
+ )
156
+ ) ;
157
+
135
158
return ;
136
159
}
137
-
160
+
138
161
_log . LogTrace (
139
162
"Persistent Subscription {subscriptionId} received event {streamName}@{streamRevision} {position}" ,
140
- SubscriptionId , resolvedEvent . OriginalEvent . EventStreamId ,
141
- resolvedEvent . OriginalEvent . EventNumber , resolvedEvent . OriginalEvent . Position ) ;
163
+ SubscriptionId ,
164
+ resolvedEvent . OriginalEvent . EventStreamId ,
165
+ resolvedEvent . OriginalEvent . EventNumber ,
166
+ resolvedEvent . OriginalEvent . Position
167
+ ) ;
142
168
143
169
try {
144
170
await _eventAppeared (
145
171
this ,
146
172
resolvedEvent ,
147
173
retryCount ,
148
- _cts . Token ) . ConfigureAwait ( false ) ;
174
+ _cts . Token
175
+ ) . ConfigureAwait ( false ) ;
149
176
} catch ( Exception ex ) when ( ex is ObjectDisposedException or OperationCanceledException ) {
150
177
if ( _subscriptionDroppedInvoked != 0 ) {
151
178
return ;
152
179
}
153
180
154
- _log . LogWarning ( ex ,
181
+ _log . LogWarning (
182
+ ex ,
155
183
"Persistent Subscription {subscriptionId} was dropped because cancellation was requested by another caller." ,
156
- SubscriptionId ) ;
184
+ SubscriptionId
185
+ ) ;
157
186
158
187
SubscriptionDropped ( SubscriptionDroppedReason . Disposed ) ;
159
188
160
189
return ;
161
190
} catch ( Exception ex ) {
162
- _log . LogError ( ex ,
191
+ _log . LogError (
192
+ ex ,
163
193
"Persistent Subscription {subscriptionId} was dropped because the subscriber made an error." ,
164
- SubscriptionId ) ;
194
+ SubscriptionId
195
+ ) ;
196
+
165
197
SubscriptionDropped ( SubscriptionDroppedReason . SubscriberError , ex ) ;
166
198
167
199
return ;
168
200
}
169
201
}
170
202
} catch ( Exception ex ) {
171
203
if ( _subscriptionDroppedInvoked == 0 ) {
172
- _log . LogError ( ex ,
173
- "Persistent Subscription {subscriptionId} was dropped because an error occurred on the server." ,
174
- SubscriptionId ) ;
175
- SubscriptionDropped ( SubscriptionDroppedReason . ServerError , ex ) ;
204
+ if ( _cts . Token . IsCancellationRequested ) {
205
+ _log . LogInformation (
206
+ "Subscription {subscriptionId} was dropped because cancellation was requested." ,
207
+ SubscriptionId
208
+ ) ;
209
+
210
+ SubscriptionDropped ( SubscriptionDroppedReason . Disposed , ex ) ;
211
+ } else {
212
+ _log . LogError (
213
+ ex ,
214
+ "Persistent Subscription {subscriptionId} was dropped because an error occurred on the server." ,
215
+ SubscriptionId
216
+ ) ;
217
+
218
+ SubscriptionDropped ( SubscriptionDroppedReason . ServerError , ex ) ;
219
+ }
176
220
}
177
221
} finally {
178
222
if ( _subscriptionDroppedInvoked == 0 ) {
179
223
_log . LogError (
180
224
"Persistent Subscription {subscriptionId} was unexpectedly terminated." ,
181
- SubscriptionId ) ;
225
+ SubscriptionId
226
+ ) ;
227
+
182
228
SubscriptionDropped ( SubscriptionDroppedReason . ServerError ) ;
183
229
}
184
230
}
0 commit comments