Skip to content

Commit 1e15f15

Browse files
committed
fix: make timer array instance based to avoid memory leaks
1 parent 645aad4 commit 1e15f15

File tree

1 file changed

+15
-15
lines changed

1 file changed

+15
-15
lines changed

src/Paramore.Brighter/InMemoryScheduler.cs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public class InMemoryScheduler(
5353
OnSchedulerConflict onConflict)
5454
: IAmAMessageSchedulerSync, IAmAMessageSchedulerAsync, IAmARequestSchedulerSync, IAmARequestSchedulerAsync
5555
{
56-
private static readonly ConcurrentDictionary<string, ITimer> s_timers = new();
56+
private readonly ConcurrentDictionary<string, ITimer> _timers = new();
5757
private static readonly ILogger Logger = ApplicationLogging.CreateLogger<InMemoryScheduler>();
5858

5959
/// <inheritdoc />
@@ -66,13 +66,13 @@ public string Schedule(Message message, TimeSpan delay)
6666
var id = getOrCreateMessageSchedulerId(message);
6767

6868
// Check for conflict before attempting atomic update
69-
if (onConflict == OnSchedulerConflict.Throw && s_timers.ContainsKey(id))
69+
if (onConflict == OnSchedulerConflict.Throw && _timers.ContainsKey(id))
7070
{
7171
throw new InvalidOperationException($"scheduler with '{id}' id already exists");
7272
}
7373

7474
// Use AddOrUpdate to atomically replace the timer, disposing the old one
75-
s_timers.AddOrUpdate(
75+
_timers.AddOrUpdate(
7676
id,
7777
_ => timeProvider.CreateTimer(Execute,
7878
(processor, new FireSchedulerMessage { Id = id, Async = false, Message = message }), delay, TimeSpan.Zero),
@@ -110,13 +110,13 @@ public string Schedule<TRequest>(TRequest request, RequestSchedulerType type, Ti
110110
var id = getOrCreateRequestSchedulerId(request);
111111

112112
// Check for conflict before attempting atomic update
113-
if (onConflict == OnSchedulerConflict.Throw && s_timers.ContainsKey(id))
113+
if (onConflict == OnSchedulerConflict.Throw && _timers.ContainsKey(id))
114114
{
115115
throw new InvalidOperationException($"scheduler with '{id}' id already exists");
116116
}
117117

118118
// Use AddOrUpdate to atomically replace the timer, disposing the old one
119-
s_timers.AddOrUpdate(
119+
_timers.AddOrUpdate(
120120
id,
121121
_ => timeProvider.CreateTimer(Execute,
122122
(processor,
@@ -165,7 +165,7 @@ public bool ReScheduler(string schedulerId, TimeSpan delay)
165165
throw new ArgumentOutOfRangeException(nameof(delay), delay, "Invalid delay, it can't be negative");
166166
}
167167

168-
if (s_timers.TryGetValue(schedulerId, out var timer))
168+
if (_timers.TryGetValue(schedulerId, out var timer))
169169
{
170170
timer.Change(delay, TimeSpan.Zero);
171171
return true;
@@ -177,7 +177,7 @@ public bool ReScheduler(string schedulerId, TimeSpan delay)
177177
/// <inheritdoc cref="IAmAMessageSchedulerSync.Cancel" />
178178
public void Cancel(string id)
179179
{
180-
if (s_timers.TryRemove(id, out var timer))
180+
if (_timers.TryRemove(id, out var timer))
181181
{
182182
timer.Dispose();
183183
}
@@ -207,15 +207,15 @@ public Task<string> ScheduleAsync(Message message, TimeSpan delay,
207207
var id = getOrCreateMessageSchedulerId(message);
208208

209209
// Check for conflict before attempting atomic update
210-
if (onConflict == OnSchedulerConflict.Throw && s_timers.ContainsKey(id))
210+
if (onConflict == OnSchedulerConflict.Throw && _timers.ContainsKey(id))
211211
{
212212
throw new InvalidOperationException($"scheduler with '{id}' id already exists");
213213
}
214214

215215
// Use AddOrUpdate to atomically replace the timer, disposing the old one
216216
// Note: Timer disposal is synchronous here as AddOrUpdate doesn't support async callbacks,
217217
// but ITimer.Dispose() is safe to call synchronously
218-
s_timers.AddOrUpdate(
218+
_timers.AddOrUpdate(
219219
id,
220220
_ => timeProvider.CreateTimer(Execute,
221221
(processor, new FireSchedulerMessage { Id = id, Async = true, Message = message }), delay, TimeSpan.Zero),
@@ -254,15 +254,15 @@ public Task<string> ScheduleAsync<TRequest>(TRequest request, RequestSchedulerTy
254254
var id = getOrCreateRequestSchedulerId(request);
255255

256256
// Check for conflict before attempting atomic update
257-
if (onConflict == OnSchedulerConflict.Throw && s_timers.ContainsKey(id))
257+
if (onConflict == OnSchedulerConflict.Throw && _timers.ContainsKey(id))
258258
{
259259
throw new InvalidOperationException($"scheduler with '{id}' id already exists");
260260
}
261261

262262
// Use AddOrUpdate to atomically replace the timer, disposing the old one
263263
// Note: Timer disposal is synchronous here as AddOrUpdate doesn't support async callbacks,
264264
// but ITimer.Dispose() is safe to call synchronously
265-
s_timers.AddOrUpdate(
265+
_timers.AddOrUpdate(
266266
id,
267267
_ => timeProvider.CreateTimer(Execute,
268268
(processor,
@@ -305,13 +305,13 @@ public Task<bool> ReSchedulerAsync(string schedulerId, TimeSpan delay,
305305
/// <inheritdoc cref="IAmAMessageSchedulerAsync.CancelAsync" />
306306
public async Task CancelAsync(string id, CancellationToken cancellationToken = default)
307307
{
308-
if (s_timers.TryRemove(id, out var timer))
308+
if (_timers.TryRemove(id, out var timer))
309309
{
310310
await timer.DisposeAsync();
311311
}
312312
}
313313

314-
private static void Execute(object? state)
314+
private void Execute(object? state)
315315
{
316316
// .NET Standard doesn't support if(state is (IAmACommandProcessor, FireSchedulerMessage))
317317
var fireMessage = state as (IAmACommandProcessor, FireSchedulerMessage)?;
@@ -320,7 +320,7 @@ private static void Execute(object? state)
320320
var (processor, message) = (fireMessage.Value.Item1, fireMessage.Value.Item2);
321321
BrighterAsyncContext.Run(() => processor.SendAsync(message));
322322

323-
if (s_timers.TryRemove(message.Id, out var timer))
323+
if (_timers.TryRemove(message.Id, out var timer))
324324
{
325325
timer.Dispose();
326326
}
@@ -334,7 +334,7 @@ private static void Execute(object? state)
334334
var (processor, request) = (fireRequest.Value.Item1, fireRequest.Value.Item2);
335335
BrighterAsyncContext.Run(() => processor.SendAsync(request));
336336

337-
if (s_timers.TryRemove(request.Id, out var timer))
337+
if (_timers.TryRemove(request.Id, out var timer))
338338
{
339339
timer.Dispose();
340340
}

0 commit comments

Comments
 (0)