1+ using System . Text . Json ;
2+ using StackExchange . Redis ;
3+ using TickAPI . Common . Redis . Abstractions ;
4+
5+ namespace TickAPI . Common . Redis . Services ;
6+
7+ public class RedisService : IRedisService
8+ {
9+ private readonly IDatabase _database ;
10+ private static readonly JsonSerializerOptions JsonOptions = new ( JsonSerializerDefaults . Web ) ;
11+
12+ public RedisService ( IConnectionMultiplexer connectionMultiplexer )
13+ {
14+ _database = connectionMultiplexer . GetDatabase ( ) ;
15+ }
16+
17+ public async Task < string ? > GetStringAsync ( string key )
18+ {
19+ return await RetryAsync ( async ( ) =>
20+ {
21+ var value = await _database . StringGetAsync ( key ) ;
22+ return value . HasValue ? value . ToString ( ) : null ;
23+ } ) ;
24+ }
25+
26+ public async Task < bool > SetStringAsync ( string key , string value , TimeSpan ? expiry = null )
27+ {
28+ return await RetryAsync ( async ( ) => await _database . StringSetAsync ( key , value , expiry ) ) ;
29+ }
30+
31+ public async Task < bool > DeleteKeyAsync ( string key )
32+ {
33+ return await RetryAsync ( async ( ) => await _database . KeyDeleteAsync ( key ) ) ;
34+ }
35+
36+ public async Task < T ? > GetObjectAsync < T > ( string key )
37+ {
38+ var json = await GetStringAsync ( key ) ;
39+ if ( string . IsNullOrEmpty ( json ) )
40+ {
41+ return default ;
42+ }
43+ return JsonSerializer . Deserialize < T > ( json , JsonOptions ) ;
44+ }
45+
46+ public async Task < bool > SetObjectAsync < T > ( string key , T value , TimeSpan ? expiry = null )
47+ {
48+ var json = JsonSerializer . Serialize ( value , JsonOptions ) ;
49+
50+ return await SetStringAsync ( key , json , expiry ) ;
51+ }
52+
53+ public async Task < bool > KeyExistsAsync ( string key )
54+ {
55+ return await RetryAsync ( async ( ) => await _database . KeyExistsAsync ( key ) ) ;
56+ }
57+
58+ public async Task < bool > KeyExpireAsync ( string key , TimeSpan expiry )
59+ {
60+ return await RetryAsync ( async ( ) => await _database . KeyExpireAsync ( key , expiry ) ) ;
61+ }
62+
63+ public async Task < long > IncrementValueAsync ( string key , long value = 1 )
64+ {
65+ return await RetryAsync ( async ( ) => await _database . StringIncrementAsync ( key , value ) ) ;
66+ }
67+
68+ public async Task < long > DecrementValueAsync ( string key , long value = 1 )
69+ {
70+ return await RetryAsync ( async ( ) => await _database . StringDecrementAsync ( key , value ) ) ;
71+ }
72+
73+ public async Task < long ? > GetLongValueAsync ( string key )
74+ {
75+ var value = await RetryAsync ( ( ) => _database . StringGetAsync ( key ) ) ;
76+ if ( value . HasValue && long . TryParse ( value , out var result ) )
77+ {
78+ return result ;
79+ }
80+ return null ;
81+ }
82+
83+ public async Task < bool > SetLongValueAsync ( string key , long value , TimeSpan ? expiry = null )
84+ {
85+ return await RetryAsync ( async ( ) => await _database . StringSetAsync ( key , value . ToString ( ) , expiry ) ) ;
86+ }
87+
88+ private static async Task < T > RetryAsync < T > ( Func < Task < T > > action , int retryCount = 3 , int millisecondsDelay = 100 )
89+ {
90+ var attempt = 0 ;
91+ while ( true )
92+ {
93+ try
94+ {
95+ return await action ( ) ;
96+ }
97+ catch ( Exception ex ) when ( ex is RedisConnectionException or RedisTimeoutException && attempt < retryCount )
98+ {
99+ attempt ++ ;
100+ await Task . Delay ( millisecondsDelay ) ;
101+ }
102+ }
103+ }
104+ }
0 commit comments