Skip to content

Commit c08a97e

Browse files
committed
Prevents deadlocks during disposal in indexes.
Introduces a cancellation token to prevent potential deadlocks when disposing of indexes. The change ensures that locks are released when the index is disposed, preventing tasks from waiting indefinitely.
1 parent 8da782e commit c08a97e

File tree

2 files changed

+24
-10
lines changed

2 files changed

+24
-10
lines changed

src/Foundatio.Repositories.Elasticsearch/Configuration/Index.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Collections.Generic;
44
using System.Linq;
55
using System.Linq.Expressions;
6+
using System.Threading;
67
using System.Threading.Tasks;
78
using Foundatio.AsyncEx;
89
using Foundatio.Parsers.ElasticQueries;
@@ -30,6 +31,7 @@ public class Index : IIndex
3031
private readonly Lazy<QueryFieldResolver> _fieldResolver;
3132
private readonly ConcurrentDictionary<string, ICustomFieldType> _customFieldTypes = new();
3233
private readonly AsyncLock _lock = new();
34+
private readonly CancellationTokenSource _disposedCancellationTokenSource = new();
3335
protected readonly ILogger _logger;
3436

3537
public Index(IElasticConfiguration configuration, string name = null)
@@ -152,7 +154,7 @@ public virtual async Task EnsureIndexAsync(object target)
152154
if (_isEnsured)
153155
return;
154156

155-
using (await _lock.LockAsync().AnyContext())
157+
using (await _lock.LockAsync(_disposedCancellationTokenSource.Token).AnyContext())
156158
{
157159
if (_isEnsured)
158160
return;
@@ -181,7 +183,7 @@ public virtual IPromise<IAliases> ConfigureIndexAliases(AliasesDescriptor aliase
181183

182184
public virtual async Task DeleteAsync()
183185
{
184-
using (await _lock.LockAsync().AnyContext())
186+
using (await _lock.LockAsync(_disposedCancellationTokenSource.Token).AnyContext())
185187
{
186188
await DeleteIndexAsync(Name).AnyContext();
187189
_isEnsured = false;
@@ -363,7 +365,11 @@ public virtual CreateIndexDescriptor ConfigureIndex(CreateIndexDescriptor idx)
363365

364366
public virtual void ConfigureSettings(ConnectionSettings settings) { }
365367

366-
public virtual void Dispose() { }
368+
public virtual void Dispose()
369+
{
370+
_disposedCancellationTokenSource.Cancel();
371+
_disposedCancellationTokenSource.Dispose();
372+
}
367373
}
368374

369375
public class Index<T> : Index, IIndex<T> where T : class

tests/Foundatio.Repositories.Elasticsearch.Tests/Repositories/Configuration/Indexes/CalculatedIntegerFieldType.cs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Concurrent;
33
using System.Security.Cryptography;
44
using System.Text;
5+
using System.Threading;
56
using System.Threading.Tasks;
67
using Foundatio.AsyncEx;
78
using Foundatio.Serializer;
@@ -39,12 +40,13 @@ public override async Task<ProcessFieldValueResult> ProcessValueAsync<T>(T docum
3940
}
4041
}
4142

42-
public class ScriptService
43+
public class ScriptService : IDisposable
4344
{
4445
private readonly ITextSerializer _serializer;
4546
private readonly ILogger<ScriptService> _logger;
4647
private readonly ConcurrentDictionary<string, string> _registeredExpressions = new();
4748
private readonly AsyncLock _lock = new();
49+
private readonly CancellationTokenSource _disposedCancellationTokenSource = new();
4850

4951
public ScriptService(ITextSerializer jsonSerializer, ILogger<ScriptService> logger)
5052
{
@@ -61,7 +63,7 @@ public ScriptService(ITextSerializer jsonSerializer, ILogger<ScriptService> logg
6163
/// </summary>
6264
public async Task<ScriptValueResult> EvaluateForSourceAsync<T>(T source, string expression) where T : class
6365
{
64-
using (await _lock.LockAsync().ConfigureAwait(false))
66+
using (await _lock.LockAsync(_disposedCancellationTokenSource.Token).ConfigureAwait(false))
6567
{
6668
string functionName = EnsureExpressionFunctionInternal(expression);
6769
SetSourceInternal(source);
@@ -71,7 +73,7 @@ public async Task<ScriptValueResult> EvaluateForSourceAsync<T>(T source, string
7173

7274
public string EnsureExpressionFunction(string expression)
7375
{
74-
using (_lock.Lock())
76+
using (_lock.Lock(_disposedCancellationTokenSource.Token))
7577
{
7678
return EnsureExpressionFunctionInternal(expression);
7779
}
@@ -92,7 +94,7 @@ private string EnsureExpressionFunctionInternal(string expression)
9294

9395
public void RegisterFunction(string name, string body)
9496
{
95-
using (_lock.Lock())
97+
using (_lock.Lock(_disposedCancellationTokenSource.Token))
9698
{
9799
RegisterFunctionInternal(name, body);
98100
}
@@ -129,7 +131,7 @@ private void RegisterFunctionInternal(string name, string body)
129131

130132
public void SetSource(object source)
131133
{
132-
using (_lock.Lock())
134+
using (_lock.Lock(_disposedCancellationTokenSource.Token))
133135
{
134136
SetSourceInternal(source);
135137
}
@@ -147,7 +149,7 @@ private void SetSourceInternal(object source)
147149

148150
public ScriptValueResult GetValue(string functionName)
149151
{
150-
using (_lock.Lock())
152+
using (_lock.Lock(_disposedCancellationTokenSource.Token))
151153
{
152154
return GetValueInternal(functionName);
153155
}
@@ -172,7 +174,7 @@ private ScriptValueResult GetValueInternal(string functionName)
172174

173175
public object ExecuteExpression(string expression)
174176
{
175-
using (_lock.Lock())
177+
using (_lock.Lock(_disposedCancellationTokenSource.Token))
176178
{
177179
return ExecuteExpressionInternal(expression);
178180
}
@@ -193,6 +195,12 @@ private object ExecuteExpressionInternal(string expression)
193195
}
194196
}
195197

198+
public void Dispose()
199+
{
200+
_disposedCancellationTokenSource.Cancel();
201+
_disposedCancellationTokenSource.Dispose();
202+
}
203+
196204
private static bool IsValidJavaScriptIdentifier(string identifier)
197205
{
198206
if (String.IsNullOrEmpty(identifier))

0 commit comments

Comments
 (0)