From 1ee6a3f42f88c8fe08d7d9aa9b83adfa44b77421 Mon Sep 17 00:00:00 2001 From: Felix Clase Date: Mon, 5 Feb 2024 07:18:39 -0400 Subject: [PATCH] Memory leak fix.. --- .../HangfireSQLiteConnection.cs | 18 ++++++++---------- .../SQLiteDistributedLock.cs | 11 ++--------- .../SQLiteMonitoringApi.cs | 16 +++++++++------- .../Hangfire.Storage.SQLite/SQLiteStorage.cs | 2 +- .../SQLiteWriteOnlyTransaction.cs | 1 - .../SQLiteMonitoringApiFacts.cs | 2 +- 6 files changed, 21 insertions(+), 29 deletions(-) diff --git a/src/main/Hangfire.Storage.SQLite/HangfireSQLiteConnection.cs b/src/main/Hangfire.Storage.SQLite/HangfireSQLiteConnection.cs index a5a0034..0c23d29 100644 --- a/src/main/Hangfire.Storage.SQLite/HangfireSQLiteConnection.cs +++ b/src/main/Hangfire.Storage.SQLite/HangfireSQLiteConnection.cs @@ -38,6 +38,12 @@ public HangfireSQLiteConnection( _queueProviders = queueProviders ?? throw new ArgumentNullException(nameof(queueProviders)); } + public override void Dispose() + { + DbContext.Dispose(); + base.Dispose(); + } + public override IDisposable AcquireDistributedLock(string resource, TimeSpan timeout) { return Retry.Twice((_) => @@ -347,27 +353,19 @@ public override void Heartbeat(string serverId) throw new ArgumentNullException(nameof(serverId)); } - // DANIEL WAS HERE: - // Something fishy is going on here, a BackgroundServerGoneException is unexpectedly thrown - // https://github.com/HangfireIO/Hangfire/blob/master/src/Hangfire.Core/Server/ServerHeartbeatProcess.cs - // Changing to - - // DANIEL WAS HERE: - // var server = DbContext.HangfireServerRepository.FirstOrDefault(_ => _.Id == serverId); var server = Retry.Twice((attempts) => - // Forcing a query (read somewhere that sqlite-net handles FirstOrDefault differently ) DbContext.HangfireServerRepository.Where(_ => _.Id == serverId) .ToArray() .FirstOrDefault() ); + if (server == null) throw new BackgroundServerGoneException(); server.LastHeartbeat = DateTime.UtcNow; - // DANIEL WAS HERE: - // var affected = DbContext.Database.Update(server); var affected = Retry.Twice((_) => DbContext.Database.Update(server)); + if (affected == 0) throw new BackgroundServerGoneException(); } diff --git a/src/main/Hangfire.Storage.SQLite/SQLiteDistributedLock.cs b/src/main/Hangfire.Storage.SQLite/SQLiteDistributedLock.cs index 2d1693b..ef4b534 100644 --- a/src/main/Hangfire.Storage.SQLite/SQLiteDistributedLock.cs +++ b/src/main/Hangfire.Storage.SQLite/SQLiteDistributedLock.cs @@ -176,31 +176,24 @@ private void Acquire(TimeSpan timeout) /// private void Release() { - // DANIEL WAS HERE: Retry.Twice((retry) => { // Remove resource lock (if it's still ours) _dbContext.DistributedLockRepository.Delete(_ => _.Resource == _resource && _.ResourceKey == _resourceKey); lock (EventWaitHandleName) Monitor.Pulse(EventWaitHandleName); - } - - ); + }); } - private void Cleanup() { try { - // DANIEL WAS HERE: Retry.Twice((_) => { - // Delete expired locks (of any owner) _dbContext.DistributedLockRepository. Delete(x => x.Resource == _resource && x.ExpireAt < DateTime.UtcNow); - } - ); + }); } catch (Exception ex) { diff --git a/src/main/Hangfire.Storage.SQLite/SQLiteMonitoringApi.cs b/src/main/Hangfire.Storage.SQLite/SQLiteMonitoringApi.cs index 5128117..72adbce 100644 --- a/src/main/Hangfire.Storage.SQLite/SQLiteMonitoringApi.cs +++ b/src/main/Hangfire.Storage.SQLite/SQLiteMonitoringApi.cs @@ -12,25 +12,28 @@ namespace Hangfire.Storage.SQLite { public class SQLiteMonitoringApi : IMonitoringApi { - private readonly HangfireDbContext _dbContext; + private readonly SQLiteStorage _storage; private readonly PersistentJobQueueProviderCollection _queueProviders; /// /// /// - /// + /// /// - public SQLiteMonitoringApi(HangfireDbContext database, PersistentJobQueueProviderCollection queueProviders) + public SQLiteMonitoringApi(SQLiteStorage storage, PersistentJobQueueProviderCollection queueProviders) { - _dbContext = database; + _storage = storage; _queueProviders = queueProviders; } private T UseConnection(Func action) { - var result = action(_dbContext); - return result; + using (var dbContext = _storage.CreateAndOpenConnection()) + { + var result = action(dbContext); + return result; + } } private JobList GetJobs(HangfireDbContext connection, int from, int count, string stateName, Func, TDto> selector) @@ -414,7 +417,6 @@ public JobList FetchedJobs(string queue, int from, int perPage) /// public StatisticsDto GetStatistics() { - // DANIEL WAS HERE: return Retry.Twice((attempts) => UseConnection(ctx => diff --git a/src/main/Hangfire.Storage.SQLite/SQLiteStorage.cs b/src/main/Hangfire.Storage.SQLite/SQLiteStorage.cs index bde08c6..7fe98ed 100644 --- a/src/main/Hangfire.Storage.SQLite/SQLiteStorage.cs +++ b/src/main/Hangfire.Storage.SQLite/SQLiteStorage.cs @@ -75,7 +75,7 @@ public override IStorageConnection GetConnection() public override IMonitoringApi GetMonitoringApi() { CheckDisposed(); - return new SQLiteMonitoringApi(CreateAndOpenConnection(), QueueProviders); + return new SQLiteMonitoringApi(this, QueueProviders); } /// diff --git a/src/main/Hangfire.Storage.SQLite/SQLiteWriteOnlyTransaction.cs b/src/main/Hangfire.Storage.SQLite/SQLiteWriteOnlyTransaction.cs index 0e796c7..65d3e19 100644 --- a/src/main/Hangfire.Storage.SQLite/SQLiteWriteOnlyTransaction.cs +++ b/src/main/Hangfire.Storage.SQLite/SQLiteWriteOnlyTransaction.cs @@ -113,7 +113,6 @@ public override void AddToSet(string key, string value, double score) public override void Commit() { - // DANIEL WAS HERE Retry.Twice((attempts) => { lock (_lockObject) diff --git a/src/test/Hangfire.Storage.SQLite.Test/SQLiteMonitoringApiFacts.cs b/src/test/Hangfire.Storage.SQLite.Test/SQLiteMonitoringApiFacts.cs index 8e75a77..4bc9e9e 100644 --- a/src/test/Hangfire.Storage.SQLite.Test/SQLiteMonitoringApiFacts.cs +++ b/src/test/Hangfire.Storage.SQLite.Test/SQLiteMonitoringApiFacts.cs @@ -283,7 +283,7 @@ public void ProcessingJobs_ReturnsProcessingJobsOnly_WhenMultipleJobsExistsInPro private void UseMonitoringApi(Action action) { using var storage = ConnectionUtils.CreateStorage(); - var connection = new SQLiteMonitoringApi(storage.CreateAndOpenConnection(), _providers); + var connection = new SQLiteMonitoringApi(storage, _providers); using var dbContext = storage.CreateAndOpenConnection(); action(dbContext, connection); }