2
2
using System . Collections . Generic ;
3
3
using System . Threading . Tasks ;
4
4
using Cleipnir . ResilientFunctions . Domain ;
5
- using Cleipnir . ResilientFunctions . Domain . Exceptions ;
6
5
using Cleipnir . ResilientFunctions . Messaging ;
7
6
using Cleipnir . ResilientFunctions . Storage ;
8
7
using Microsoft . Data . SqlClient ;
9
8
10
9
namespace Cleipnir . ResilientFunctions . SqlServer ;
11
10
12
- public class SqlServerMessageStore : IMessageStore
11
+ public class SqlServerMessageStore ( string connectionString , string tablePrefix = "" ) : IMessageStore
13
12
{
14
- private readonly string _connectionString ;
15
- private readonly string _tablePrefix ;
16
-
17
- public SqlServerMessageStore ( string connectionString , string tablePrefix = "" )
18
- {
19
- _connectionString = connectionString ;
20
- _tablePrefix = tablePrefix ;
21
- }
22
-
23
13
private string ? _initializeSql ;
24
14
public async Task Initialize ( )
25
15
{
26
16
await using var conn = await CreateConnection ( ) ;
27
17
28
18
_initializeSql ??= @$ "
29
- CREATE TABLE { _tablePrefix } _Messages (
19
+ CREATE TABLE { tablePrefix } _Messages (
30
20
FlowType INT,
31
21
FlowInstance UNIQUEIDENTIFIER,
32
22
Position INT NOT NULL,
@@ -46,23 +36,26 @@ PRIMARY KEY (FlowType, FlowInstance, Position)
46
36
public async Task TruncateTable ( )
47
37
{
48
38
await using var conn = await CreateConnection ( ) ;
49
- _truncateTableSql ??= $ "TRUNCATE TABLE { _tablePrefix } _Messages;";
39
+ _truncateTableSql ??= $ "TRUNCATE TABLE { tablePrefix } _Messages;";
50
40
var command = new SqlCommand ( _truncateTableSql , conn ) ;
51
41
await command . ExecuteNonQueryAsync ( ) ;
52
42
}
53
43
54
- private string ? _appendMessageSql ;
55
44
public async Task < FunctionStatus ? > AppendMessage ( StoredId storedId , StoredMessage storedMessage )
45
+ => await AppendMessage ( storedId , storedMessage , depth : 0 ) ;
46
+
47
+ private string ? _appendMessageSql ;
48
+ private async Task < FunctionStatus ? > AppendMessage ( StoredId storedId , StoredMessage storedMessage , int depth )
56
49
{
57
50
await using var conn = await CreateConnection ( ) ;
58
51
59
52
_appendMessageSql ??= @$ "
60
- INSERT INTO { _tablePrefix } _Messages
53
+ INSERT INTO { tablePrefix } _Messages
61
54
(FlowType, FlowInstance, Position, MessageJson, MessageType, IdempotencyKey)
62
55
VALUES (
63
56
@FlowType,
64
57
@FlowInstance,
65
- (SELECT COALESCE(MAX(position), -1) + 1 FROM { _tablePrefix } _Messages WHERE FlowType = @FlowType AND FlowInstance = @FlowInstance),
58
+ (SELECT COALESCE(MAX(position), -1) + 1 FROM { tablePrefix } _Messages WHERE FlowType = @FlowType AND FlowInstance = @FlowInstance),
66
59
@MessageJson, @MessageType, @IdempotencyKey
67
60
);" ;
68
61
@@ -78,14 +71,13 @@ INSERT INTO {_tablePrefix}_Messages
78
71
}
79
72
catch ( SqlException e )
80
73
{
81
- if ( e . Number == SqlError . UNIQUENESS_INDEX_VIOLATION ) //idempotency key already exists
82
- return await GetSuspensionStatus ( storedId , conn ) ;
83
- if ( e . Number != SqlError . DEADLOCK_VICTIM && e . Number != SqlError . UNIQUENESS_VIOLATION )
74
+ if ( depth == 10 || e . Number != SqlError . DEADLOCK_VICTIM )
84
75
throw ;
85
76
77
+ // ReSharper disable once DisposeOnUsingVariable
86
78
await conn . DisposeAsync ( ) ;
87
79
await Task . Delay ( Random . Shared . Next ( 50 , 250 ) ) ;
88
- return await AppendMessage ( storedId , storedMessage ) ;
80
+ return await AppendMessage ( storedId , storedMessage , depth + 1 ) ;
89
81
}
90
82
91
83
return await GetSuspensionStatus ( storedId , conn ) ;
@@ -97,7 +89,7 @@ public async Task<bool> ReplaceMessage(StoredId storedId, int position, StoredMe
97
89
await using var conn = await CreateConnection ( ) ;
98
90
99
91
_replaceMessageSql ??= @$ "
100
- UPDATE { _tablePrefix } _Messages
92
+ UPDATE { tablePrefix } _Messages
101
93
SET MessageJson = @MessageJson, MessageType = @MessageType, IdempotencyKey = @IdempotencyKey
102
94
WHERE FlowType = @FlowType AND FlowInstance = @FlowInstance AND Position = @Position" ;
103
95
@@ -118,7 +110,7 @@ public async Task Truncate(StoredId storedId)
118
110
{
119
111
await using var conn = await CreateConnection ( ) ;
120
112
_truncateSql ??= @$ "
121
- DELETE FROM { _tablePrefix } _Messages
113
+ DELETE FROM { tablePrefix } _Messages
122
114
WHERE FlowType = @FlowType AND FlowInstance = @FlowInstance" ;
123
115
124
116
await using var command = new SqlCommand ( _truncateSql , conn ) ;
@@ -134,7 +126,7 @@ public async Task<IReadOnlyList<StoredMessage>> GetMessages(StoredId storedId, i
134
126
await using var conn = await CreateConnection ( ) ;
135
127
_getMessagesSql ??= @$ "
136
128
SELECT MessageJson, MessageType, IdempotencyKey
137
- FROM { _tablePrefix } _Messages
129
+ FROM { tablePrefix } _Messages
138
130
WHERE FlowType = @FlowType AND FlowInstance = @FlowInstance AND Position >= @Position
139
131
ORDER BY Position ASC;" ;
140
132
@@ -168,7 +160,7 @@ public async Task<IReadOnlyList<StoredMessage>> GetMessages(StoredId storedId, i
168
160
169
161
private async Task < SqlConnection > CreateConnection ( )
170
162
{
171
- var conn = new SqlConnection ( _connectionString ) ;
163
+ var conn = new SqlConnection ( connectionString ) ;
172
164
await conn . OpenAsync ( ) ;
173
165
return conn ;
174
166
}
@@ -178,7 +170,7 @@ private async Task<SqlConnection> CreateConnection()
178
170
{
179
171
_getSuspensionStatusSql ??= @$ "
180
172
SELECT Epoch, Status
181
- FROM { _tablePrefix }
173
+ FROM { tablePrefix }
182
174
WHERE FlowType = @FlowType AND FlowInstance = @FlowInstance" ;
183
175
await using var command = new SqlCommand ( _getSuspensionStatusSql , connection ) ;
184
176
command . Parameters . AddWithValue ( "@FlowType" , storedId . Type . Value ) ;
0 commit comments