Skip to content

Commit

Permalink
Database retry mechanism (#369)
Browse files Browse the repository at this point in the history
Fixes #346
  • Loading branch information
Edwin Kortman committed Oct 26, 2022
2 parents cba97c0 + b8fcdd7 commit 6f06cdf
Show file tree
Hide file tree
Showing 12 changed files with 59 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ namespace Corgibytes.Freshli.Cli.Test.Functionality.Analysis;
[UnitTest]
public class PrepareCacheForAnalysisActivityTest
{
private readonly Mock<IApplicationEventEngine> _eventClient;
private readonly PrepareCacheForAnalysisActivity _activity;
private readonly Mock<ICacheManager> _cacheManager;
private readonly Mock<IApplicationEventEngine> _eventClient;
private readonly string _historyInterval;
private readonly string _repositoryBranch;
private readonly string _repositoryUrl;
private readonly PrepareCacheForAnalysisActivity _activity;

public PrepareCacheForAnalysisActivityTest()
{
Expand Down Expand Up @@ -76,5 +76,4 @@ public void VerifyItFiresCachePreparedEventWhenPrepareThrowsAnException()
_eventClient.Verify(mock => mock.Fire(It.Is<CachePrepareFailedForAnalysisEvent>(value =>
value.ErrorMessage == "failure message")));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ namespace Corgibytes.Freshli.Cli.Test.Functionality.Cache;
[UnitTest]
public class PrepareCacheActivityTest
{
private readonly Mock<IApplicationEventEngine> _eventClient;
private readonly Mock<ICacheManager> _cacheManager;
private readonly PrepareCacheActivity _activity;
private readonly Mock<ICacheManager> _cacheManager;
private readonly Mock<IApplicationEventEngine> _eventClient;

public PrepareCacheActivityTest()
{
Expand Down
10 changes: 5 additions & 5 deletions Corgibytes.Freshli.Cli.Test/Services/AgentReaderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ namespace Corgibytes.Freshli.Cli.Test.Services;
[UnitTest]
public class AgentReaderTest
{
private readonly Mock<ICommandInvoker> _commandInvoker;
private readonly Mock<ICacheManager> _cacheManager;
private readonly Mock<ICacheDb> _cacheDb;
private readonly PackageURL _packageUrl;
private readonly Package _alphaPackage;
private readonly Package _betaPackage;
private readonly Package _gammaPackage;
private readonly Mock<ICacheDb> _cacheDb;
private readonly Mock<ICacheManager> _cacheManager;
private readonly Mock<ICommandInvoker> _commandInvoker;
private readonly List<Package> _expectedPackages;
private readonly Package _gammaPackage;
private readonly PackageURL _packageUrl;
private readonly AgentReader _reader;

public AgentReaderTest()
Expand Down
1 change: 1 addition & 0 deletions Corgibytes.Freshli.Cli/Corgibytes.Freshli.Cli.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
<PackageReference Include="NLog.Extensions.Hosting" Version="5.1.0" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.1.0" />
<PackageReference Include="packageurl-dotnet" Version="1.1.0" />
<PackageReference Include="Polly" Version="7.2.3" />
<PackageReference Include="ServiceStack.Text" Version="6.4.0" />
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
<PackageReference Include="System.CommandLine.Hosting" Version="0.4.0-alpha.22272.1" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@ namespace Corgibytes.Freshli.Cli.Functionality.Cache;

public class CachePrepareFailedEvent : FailureEvent
{

}
32 changes: 28 additions & 4 deletions Corgibytes.Freshli.Cli/Functionality/CacheDb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
using System.Linq;
using Corgibytes.Freshli.Cli.DataModel;
using Corgibytes.Freshli.Cli.Functionality.Git;
using Microsoft.Data.Sqlite;
using PackageUrl;
using Polly;

namespace Corgibytes.Freshli.Cli.Functionality;

Expand All @@ -20,25 +22,32 @@ public Guid SaveAnalysis(CachedAnalysis analysis)
if (analysis.Id == Guid.Empty)
{
var savedEntity = Db.CachedAnalyses.Add(analysis);
Db.SaveChanges();
SaveChanges();
return savedEntity.Entity.Id;
}

Db.CachedAnalyses.Update(analysis);
Db.SaveChanges();
SaveChanges();
return analysis.Id;
}

public CachedAnalysis? RetrieveAnalysis(Guid id) => Db.CachedAnalyses.Find(id);
public CachedGitSource? RetrieveCachedGitSource(CachedGitSourceId id) => Db.CachedGitSources.Find(id.Id);
public void RemoveCachedGitSource(CachedGitSource cachedGitSource) => Db.CachedGitSources.Remove(cachedGitSource);

public void AddCachedGitSource(CachedGitSource cachedGitSource)
{
Db.CachedGitSources.Add(cachedGitSource);
SaveChanges();
}

public CachedHistoryStopPoint? RetrieveHistoryStopPoint(int historyStopPointId) =>
Db.CachedHistoryStopPoints.Find(historyStopPointId);

public int AddHistoryStopPoint(CachedHistoryStopPoint historyStopPoint)
{
var savedEntity = Db.CachedHistoryStopPoints.Add(historyStopPoint);
Db.SaveChanges();
SaveChanges();
return savedEntity.Entity.Id;
}

Expand All @@ -57,7 +66,7 @@ public void StoreCachedReleaseHistory(List<CachedPackage> packages)
public int AddPackageLibYear(CachedPackageLibYear packageLibYear)
{
var savedEntity = Db.CachedPackageLibYears.Add(packageLibYear);
Db.SaveChanges();
SaveChanges();
return savedEntity.Entity.Id;
}

Expand All @@ -72,4 +81,19 @@ public void Dispose()
_disposed = true;
GC.SuppressFinalize(this);
}

private void SaveChanges()
{
void Changes()
{
Db.SaveChanges();
}

Policy
.Handle<SqliteException>()
.WaitAndRetry(6, retryAttempt =>
TimeSpan.FromMilliseconds(Math.Pow(10, retryAttempt / 2.0))
)
.Execute(Changes);
}
}
2 changes: 2 additions & 0 deletions Corgibytes.Freshli.Cli/Functionality/Git/CachedGitSourceId.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,7 @@ public CachedGitSourceId(string url, string? branch = null)
Id = stringBuilder.ToString();
}

public CachedGitSourceId(string id) => Id = id;

public string Id { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,9 @@ public CachedGitSourceRepository(ICommandInvoker commandInvoker, IConfiguration
[JsonProperty] private ICacheManager CacheManager { get; }
[JsonProperty] private IConfiguration Configuration { get; }

public CachedGitSource FindOneByHash(string hash)
public CachedGitSource FindOneByRepositoryId(string repositoryId)
{
using var db = new CacheContext(Configuration.CacheDir);
var entry = db.CachedGitSources.Find(hash);
var entry = CacheManager.GetCacheDb().RetrieveCachedGitSource(new CachedGitSourceId(repositoryId));
if (entry == null)
{
throw new CacheException(CliOutput.CachedGitSourceRepository_No_Repository_Found_In_Cache);
Expand All @@ -34,33 +33,23 @@ public CachedGitSource FindOneByHash(string hash)
return entry;
}

public void Save(CachedGitSource cachedGitSource)
{
using var db = new CacheContext(Configuration.CacheDir);
db.CachedGitSources.Add(cachedGitSource);
db.SaveChanges();
}
public void Save(CachedGitSource cachedGitSource) => CacheManager.GetCacheDb().AddCachedGitSource(cachedGitSource);

public CachedGitSource CloneOrPull(string url, string? branch)
{
// Ensure the cache directory is ready for use.
CacheManager.Prepare();
// Generate a unique repositoryId for the repository based on its URL and branch.
var id = new CachedGitSourceId(url, branch);

// Generate a unique hash for the repository based on its URL and branch.
var hash = new CachedGitSourceId(url, branch).Id;

using var db = new CacheContext(Configuration.CacheDir);
var existingCachedGitSource = db.CachedGitSources.Find(hash);
var existingCachedGitSource = CacheManager.GetCacheDb().RetrieveCachedGitSource(id);
if (existingCachedGitSource is not null)
{
return existingCachedGitSource;
}

var directory = CacheManager.GetDirectoryInCache("repositories", hash);
var directory = CacheManager.GetDirectoryInCache("repositories", id.Id);

var cachedGitSource = new CachedGitSource(hash, url, branch, directory.FullName);
db.CachedGitSources.Add(cachedGitSource);
db.SaveChanges();
var cachedGitSource = new CachedGitSource(id.Id, url, branch, directory.FullName);
CacheManager.GetCacheDb().AddCachedGitSource(cachedGitSource);

if (directory.GetFiles().Any() || directory.GetDirectories().Any())
{
Expand Down Expand Up @@ -123,8 +112,11 @@ private void Delete(CachedGitSource cachedGitSource)
{
var directory = new DirectoryInfo(cachedGitSource.LocalPath);
using var db = new CacheContext(Configuration.CacheDir);
var entry = db.CachedGitSources.Find(cachedGitSource.Id);
db.CachedGitSources.Remove(entry!);
var entry = CacheManager.GetCacheDb().RetrieveCachedGitSource(new CachedGitSourceId(cachedGitSource.Id));
if (entry != null)
{
CacheManager.GetCacheDb().RemoveCachedGitSource(entry);
}

directory.Delete(true);
}
Expand Down
2 changes: 1 addition & 1 deletion Corgibytes.Freshli.Cli/Functionality/Git/GitArchive.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public GitArchive(IConfiguration configuration, ICachedGitSourceRepository cache

public string CreateArchive(string repositoryId, GitCommitIdentifier gitCommitIdentifier)
{
var cachedGitSource = _cachedGitSourceRepository.FindOneByHash(repositoryId);
var cachedGitSource = _cachedGitSourceRepository.FindOneByRepositoryId(repositoryId);

var gitSourceTarget = new DirectoryInfo(Path.Combine(_configuration.CacheDir, "histories", cachedGitSource.Id,
gitCommitIdentifier.ToString()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace Corgibytes.Freshli.Cli.Functionality.Git;

public interface ICachedGitSourceRepository
{
public CachedGitSource FindOneByHash(string hash);
public CachedGitSource FindOneByRepositoryId(string repositoryId);

public void Save(CachedGitSource cachedGitSource);

Expand Down
2 changes: 2 additions & 0 deletions Corgibytes.Freshli.Cli/Functionality/ICache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ public interface ICacheDb
public int AddHistoryStopPoint(CachedHistoryStopPoint historyStopPoint);
public int AddPackageLibYear(CachedPackageLibYear packageLibYear);
public CachedGitSource? RetrieveCachedGitSource(CachedGitSourceId id);
public void AddCachedGitSource(CachedGitSource cachedGitSource);
public void RemoveCachedGitSource(CachedGitSource cachedGitSource);
public CachedHistoryStopPoint? RetrieveHistoryStopPoint(int historyStopPointId);
public CachedPackageLibYear? RetrievePackageLibYear(int packageLibYearId);
public List<CachedPackage> RetrieveCachedReleaseHistory(PackageURL packageUrl);
Expand Down
3 changes: 1 addition & 2 deletions Corgibytes.Freshli.Cli/Functionality/ICacheManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ namespace Corgibytes.Freshli.Cli.Functionality;
public interface ICacheManager
{
public bool ValidateCacheDirectory();
public bool Prepare();
public bool Destroy();
public DirectoryInfo GetDirectoryInCache(params string[] directoryStructure);

public bool Prepare();
public string StoreBomInCache(string pathToBom, Guid analysisId, DateTimeOffset asOfDateTime);

public ICacheDb GetCacheDb();
Expand Down

0 comments on commit 6f06cdf

Please sign in to comment.