-
Notifications
You must be signed in to change notification settings - Fork 12
Added submissions archives. #1656
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v2-development
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
namespace OJS.Data.Models.Submissions | ||
{ | ||
using System; | ||
using System.ComponentModel.DataAnnotations; | ||
using System.ComponentModel.DataAnnotations.Schema; | ||
using System.Linq.Expressions; | ||
using OJS.Data.Validation; | ||
using OJS.Workers.Common.Models; | ||
|
||
[Table("Submissions")] | ||
public class ArchivedSubmission | ||
{ | ||
public static Expression<Func<Submission, ArchivedSubmission>> FromSubmission => | ||
submission => new ArchivedSubmission | ||
{ | ||
Id = submission.Id, | ||
ParticipantId = submission.ParticipantId, | ||
ProblemId = submission.ProblemId, | ||
SubmissionTypeId = submission.SubmissionTypeId, | ||
Content = submission.Content, | ||
FileExtension = submission.FileExtension, | ||
SolutionSkeleton = submission.SolutionSkeleton, | ||
StartedExecutionOn = submission.StartedExecutionOn, | ||
CompletedExecutionOn = submission.CompletedExecutionOn, | ||
IpAddress = submission.IpAddress, | ||
WorkerName = submission.WorkerName, | ||
ExceptionType = submission.ExceptionType, | ||
Processed = submission.Processed, | ||
Points = submission.Points, | ||
ProcessingComment = submission.ProcessingComment, | ||
TestRunsCache = submission.TestRunsCache, | ||
CreatedOn = submission.CreatedOn, | ||
ModifiedOn = submission.ModifiedOn, | ||
IsHardDeletedFromMainDatabase = false, | ||
}; | ||
|
||
[Key] | ||
[DatabaseGenerated(DatabaseGeneratedOption.None)] | ||
public int Id { get; set; } | ||
|
||
public int ParticipantId { get; set; } | ||
|
||
public int ProblemId { get; set; } | ||
|
||
public int? SubmissionTypeId { get; set; } | ||
|
||
public byte[] Content { get; set; } = Array.Empty<byte>(); | ||
|
||
public string? FileExtension { get; set; } | ||
|
||
public byte[]? SolutionSkeleton { get; set; } | ||
|
||
public DateTime? StartedExecutionOn { get; set; } | ||
|
||
public DateTime? CompletedExecutionOn { get; set; } | ||
|
||
[StringLength(ConstraintConstants.IpAddressMaxLength)] | ||
[Column(TypeName = "varchar")] | ||
public string? IpAddress { get; set; } | ||
|
||
[StringLength(ConstraintConstants.Submission.WorkerNameMaxLength)] | ||
public string? WorkerName { get; set; } | ||
|
||
public ExceptionType? ExceptionType { get; set; } | ||
|
||
public bool Processed { get; set; } | ||
|
||
public int Points { get; set; } | ||
|
||
public string? ProcessingComment { get; set; } | ||
|
||
public string? TestRunsCache { get; set; } | ||
|
||
public DateTime CreatedOn { get; set; } | ||
|
||
public DateTime? ModifiedOn { get; set; } | ||
|
||
public bool IsHardDeletedFromMainDatabase { get; set; } | ||
|
||
[NotMapped] | ||
public bool IsBinaryFile => !string.IsNullOrWhiteSpace(this.FileExtension); | ||
|
||
[NotMapped] | ||
public string ContentAsString | ||
=> this.IsBinaryFile ? string.Empty : this.Content.ToString(); | ||
|
||
public override bool Equals(object? obj) | ||
=> obj is ArchivedSubmission other && this.Equals(other); | ||
|
||
public bool Equals(ArchivedSubmission? other) | ||
=> other != null && this.Id == other.Id; | ||
|
||
public override int GetHashCode() | ||
=> this.Id.GetHashCode(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
namespace OJS.Data; | ||
|
||
using Microsoft.EntityFrameworkCore; | ||
using OJS.Data.Models.Submissions; | ||
|
||
public class ArchivesDbContext(DbContextOptions<ArchivesDbContext> options) : DbContext(options) | ||
{ | ||
public DbSet<ArchivedSubmission> Submissions { get; set; } = null!; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,12 +40,14 @@ public static void ConfigureServices( | |
.AddHttpClients(configuration) | ||
.AddTransient(typeof(IDataService<>), typeof(AdministrationDataService<>)) | ||
.AddTransient<ITransactionsProvider, TransactionsProvider<OjsDbContext>>() | ||
.AddTransient<IArchivesDataService, ArchivesDataService>() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why isn't this autoregistered? |
||
.AddTransient<AdministrationExceptionMiddleware>() | ||
.AddHangfireServer(configuration, AppName, [AdministrationQueueName]) | ||
.AddMessageQueue<Program>(configuration) | ||
.ConfigureGlobalDateFormat() | ||
.ConfigureCorsPolicy(configuration) | ||
.AddIdentityDatabase<OjsDbContext, UserProfile, Role, UserInRole>(configuration) | ||
.AddArchivesDatabase(configuration) | ||
.AddResiliencePipelines() | ||
.AddMemoryCache() | ||
.AddDistributedCaching(configuration) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,6 +34,7 @@ public static void Main(string[] args) | |
.AddTransient(typeof(IDataService<>), typeof(DataService<>)) | ||
.AddTransient<ITransactionsProvider, TransactionsProvider<OjsDbContext>>() | ||
.AddIdentityDatabase<OjsDbContext, UserProfile, Role, UserInRole>(configuration) | ||
.AddArchivesDatabase(configuration) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For now we don't need this db in ui |
||
.AddResiliencePipelines() | ||
.AddOpenAiClient(configuration) | ||
.AddMemoryCache() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
namespace OJS.Services.Administration.Business.Implementations; | ||
|
||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using OJS.Common; | ||
using OJS.Data.Models.Submissions; | ||
using OJS.Services.Administration.Data; | ||
using OJS.Services.Common; | ||
using OJS.Services.Common.Data; | ||
using OJS.Services.Infrastructure; | ||
using OJS.Services.Infrastructure.Extensions; | ||
|
||
public class ArchivedSubmissionsBusinessService : IArchivedSubmissionsBusinessService | ||
{ | ||
private readonly ISubmissionsDataService submissionsData; | ||
private readonly IArchivesDataService archivesData; | ||
private readonly IDatesService dates; | ||
|
||
public ArchivedSubmissionsBusinessService( | ||
ISubmissionsDataService submissionsData, | ||
IArchivesDataService archivesData, | ||
IDatesService dates) | ||
{ | ||
this.submissionsData = submissionsData; | ||
this.archivesData = archivesData; | ||
this.dates = dates; | ||
} | ||
|
||
public async Task<int> ArchiveOldSubmissionsDailyBatch(int limit, int maxSubBatchSize) | ||
{ | ||
await this.archivesData.CreateDatabaseIfNotExists(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not use |
||
|
||
var leftoverSubmissionsFromBatchSplitting = limit % maxSubBatchSize; | ||
var numberOfIterations = limit / maxSubBatchSize; | ||
if(leftoverSubmissionsFromBatchSplitting > 0) | ||
{ | ||
numberOfIterations++; | ||
} | ||
|
||
var archived = 0; | ||
|
||
for (var i = 0; i < numberOfIterations; i++) | ||
{ | ||
var curBatchSize = maxSubBatchSize; | ||
var isLastIteration = i == (numberOfIterations - 1); | ||
if(leftoverSubmissionsFromBatchSplitting > 0 && isLastIteration) | ||
{ | ||
curBatchSize = leftoverSubmissionsFromBatchSplitting; | ||
} | ||
|
||
var allSubmissionsForArchive = this | ||
.GetSubmissionsForArchiving() | ||
.OrderBy(x => x.Id) | ||
.InBatches(GlobalConstants.BatchOperationsChunkSize, curBatchSize); | ||
|
||
foreach (var submissionsForArchiveBatch in allSubmissionsForArchive) | ||
{ | ||
var submissionsForArchives = submissionsForArchiveBatch | ||
.Select(ArchivedSubmission.FromSubmission) | ||
.ToList(); | ||
|
||
if(submissionsForArchives.Count == 0) | ||
{ | ||
break; | ||
} | ||
|
||
archived += await this.archivesData.AddMany(submissionsForArchives); | ||
await this.archivesData.SaveChanges(); | ||
} | ||
|
||
await this.submissionsData.HardDeleteArchived(curBatchSize); | ||
} | ||
|
||
return archived; | ||
} | ||
|
||
public async Task<int> ArchiveOldSubmissionsWithLimit(int limit) | ||
{ | ||
var archived = 0; | ||
await this.archivesData.CreateDatabaseIfNotExists(); | ||
|
||
var allSubmissionsForArchive = this | ||
.GetSubmissionsForArchiving() | ||
.OrderBy(x => x.Id) | ||
.InBatches(GlobalConstants.BatchOperationsChunkSize, limit); | ||
|
||
foreach (var submissionsForArchiveBatch in allSubmissionsForArchive) | ||
{ | ||
var submissionsForArchives = submissionsForArchiveBatch | ||
.Select(ArchivedSubmission.FromSubmission) | ||
.ToList(); | ||
|
||
if(submissionsForArchives.Count == 0) | ||
{ | ||
break; | ||
} | ||
|
||
archived += await this.archivesData.AddMany(submissionsForArchives); | ||
await this.archivesData.SaveChanges(); | ||
} | ||
|
||
return archived; | ||
} | ||
|
||
public async Task<int> HardDeleteArchivedByLimit(int limit) | ||
=> await this.submissionsData.HardDeleteArchived(limit); | ||
|
||
private IQueryable<Submission> GetSubmissionsForArchiving() | ||
{ | ||
var now = this.dates.GetUtcNow(); | ||
var bestSubmissionCutoffDate = now.AddYears(-GlobalConstants.BestSubmissionEligibleForArchiveAgeInYears); | ||
var nonBestSubmissionCutoffDate = now.AddYears(-GlobalConstants.NonBestSubmissionEligibleForArchiveAgeInYears); | ||
|
||
return this.submissionsData | ||
.GetAllCreatedBeforeDateAndNonBestCreatedBeforeDate( | ||
bestSubmissionCutoffDate, | ||
nonBestSubmissionCutoffDate); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make sure it has all the properties.. legacy and alpha might have slight differences already.