From 4f99568d412d8b965fcfbce71fcb29b1d3a8a42f Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Tue, 18 Sep 2018 10:40:14 -0400 Subject: [PATCH] Replace IServiceProvider parameter in job execution with IDatabaseContext --- .../Components/IInstance.cs | 5 +- .../Components/Instance.cs | 14 ++- .../Components/Watchdog/Watchdog.cs | 2 +- .../Controllers/ByondController.cs | 2 +- .../Controllers/DreamDaemonController.cs | 4 +- .../Controllers/InstanceController.cs | 2 +- .../Controllers/RepositoryController.cs | 17 ++-- src/Tgstation.Server.Host/Core/IJobManager.cs | 4 +- src/Tgstation.Server.Host/Core/JobManager.cs | 86 ++++++++----------- 9 files changed, 59 insertions(+), 77 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/IInstance.cs b/src/Tgstation.Server.Host/Components/IInstance.cs index 921a408266..d90826f9b4 100644 --- a/src/Tgstation.Server.Host/Components/IInstance.cs +++ b/src/Tgstation.Server.Host/Components/IInstance.cs @@ -4,7 +4,6 @@ using System.Threading; using System.Threading.Tasks; using Tgstation.Server.Host.Components.Byond; using Tgstation.Server.Host.Components.Chat; -using Tgstation.Server.Host.Components.Compiler; using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Components.StaticFiles; using Tgstation.Server.Host.Components.Watchdog; @@ -65,10 +64,10 @@ namespace Tgstation.Server.Host.Components /// Run the compile job and insert it into the database. Meant to be called by a /// /// The running - /// The for the operation + /// The for the operation /// The to report compilation progress /// The for the operation /// A representing the running operation - Task CompileProcess(Job job, IServiceProvider serviceProvider, Action progressReporter, CancellationToken cancellationToken); + Task CompileProcess(Job job, IDatabaseContext databaseContext, Action progressReporter, CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/src/Tgstation.Server.Host/Components/Instance.cs b/src/Tgstation.Server.Host/Components/Instance.cs index 79faad2b45..708725c349 100644 --- a/src/Tgstation.Server.Host/Components/Instance.cs +++ b/src/Tgstation.Server.Host/Components/Instance.cs @@ -1,5 +1,4 @@ using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; using System.Linq; @@ -117,18 +116,16 @@ namespace Tgstation.Server.Host.Components } /// - public async Task CompileProcess(Job job, IServiceProvider serviceProvider, Action progressReporter, CancellationToken cancellationToken) + public async Task CompileProcess(Job job, IDatabaseContext databaseContext, Action progressReporter, CancellationToken cancellationToken) { //DO NOT FOLLOW THE SUGGESTION FOR A THROW EXPRESSION HERE if (job == null) throw new ArgumentNullException(nameof(job)); - if (serviceProvider == null) - throw new ArgumentNullException(nameof(serviceProvider)); + if (databaseContext == null) + throw new ArgumentNullException(nameof(databaseContext)); if (progressReporter == null) throw new ArgumentNullException(nameof(progressReporter)); - var databaseContext = serviceProvider.GetRequiredService(); - var ddSettingsTask = databaseContext.DreamDaemonSettings.Where(x => x.InstanceId == metadata.Id).Select(x => new DreamDaemonSettings { StartupTimeout = x.StartupTimeout, @@ -205,10 +202,9 @@ namespace Tgstation.Server.Host.Components }; var noRepo = false; - await jobManager.RegisterOperation(repositoryUpdateJob, async (paramJob, serviceProvider, progressReporter, jobCancellationToken) => + await jobManager.RegisterOperation(repositoryUpdateJob, async (paramJob, databaseContext, progressReporter, jobCancellationToken) => { - var db = serviceProvider.GetRequiredService(); - var repositorySettingsTask = db.RepositorySettings.Where(x => x.InstanceId == metadata.Id).FirstAsync(jobCancellationToken); + var repositorySettingsTask = databaseContext.RepositorySettings.Where(x => x.InstanceId == metadata.Id).FirstAsync(jobCancellationToken); //assume 5 steps with synchronize const int ProgressSections = 5; diff --git a/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs index 28a1eeb60c..412612e49c 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs @@ -836,7 +836,7 @@ namespace Tgstation.Server.Host.Components.Watchdog CancelRight = (ulong)DreamDaemonRights.Shutdown, CancelRightsType = RightsType.DreamDaemon }; - await jobManager.RegisterOperation(job, (j, serviceProvider, progressFunction, ct) => Launch(ct), cancellationToken).ConfigureAwait(false); + await jobManager.RegisterOperation(job, (j, databaseContext, progressFunction, ct) => Launch(ct), cancellationToken).ConfigureAwait(false); } /// diff --git a/src/Tgstation.Server.Host/Controllers/ByondController.cs b/src/Tgstation.Server.Host/Controllers/ByondController.cs index 566aaae2b0..f8be5a0174 100644 --- a/src/Tgstation.Server.Host/Controllers/ByondController.cs +++ b/src/Tgstation.Server.Host/Controllers/ByondController.cs @@ -95,7 +95,7 @@ namespace Tgstation.Server.Host.Controllers CancelRight = (ulong)ByondRights.CancelInstall, Instance = Instance }; - await jobManager.RegisterOperation(job, (paramJob, serviceProvicer, progressHandler, ct) => byondManager.ChangeVersion(installingVersion, ct), cancellationToken).ConfigureAwait(false); + await jobManager.RegisterOperation(job, (paramJob, databaseContext, progressHandler, ct) => byondManager.ChangeVersion(installingVersion, ct), cancellationToken).ConfigureAwait(false); result.InstallJob = job.ToApi(); } result.Version = byondManager.ActiveVersion; diff --git a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs index 85d7841d8c..c13ec7e820 100644 --- a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs +++ b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs @@ -67,7 +67,7 @@ namespace Tgstation.Server.Host.Controllers StartedBy = AuthenticationContext.User }; await jobManager.RegisterOperation(job, - async (paramJob, serviceProvider, progressHandler, innerCt) => + async (paramJob, databaseContext, progressHandler, innerCt) => { var result = await instance.Watchdog.Launch(innerCt).ConfigureAwait(false); if (result == null) @@ -231,7 +231,7 @@ namespace Tgstation.Server.Host.Controllers var watchdog = instanceManager.GetInstance(Instance).Watchdog; - await jobManager.RegisterOperation(job, (paramJob, serviceProvider, progressReporter, ct) => watchdog.Restart(false, ct), cancellationToken).ConfigureAwait(false); + await jobManager.RegisterOperation(job, (paramJob, databaseContext, progressReporter, ct) => watchdog.Restart(false, ct), cancellationToken).ConfigureAwait(false); return Accepted(job.ToApi()); } } diff --git a/src/Tgstation.Server.Host/Controllers/InstanceController.cs b/src/Tgstation.Server.Host/Controllers/InstanceController.cs index aafd0da61e..0c6801cbf2 100644 --- a/src/Tgstation.Server.Host/Controllers/InstanceController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstanceController.cs @@ -352,7 +352,7 @@ namespace Tgstation.Server.Host.Controllers StartedBy = AuthenticationContext.User }; - await jobManager.RegisterOperation(job, (paramJob, serviceProvider, progressHandler, ct) => instanceManager.MoveInstance(originalModel, rawPath, ct), cancellationToken).ConfigureAwait(false); + await jobManager.RegisterOperation(job, (paramJob, databaseContext, progressHandler, ct) => instanceManager.MoveInstance(originalModel, rawPath, ct), cancellationToken).ConfigureAwait(false); api.MoveJob = job.ToApi(); } diff --git a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs index 20f87f6cd1..240227aaaf 100644 --- a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs +++ b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System; @@ -186,20 +185,19 @@ namespace Tgstation.Server.Host.Controllers Instance = Instance }; var api = currentModel.ToApi(); - await jobManager.RegisterOperation(job, async (paramJob, serviceProvider, progressReporter, ct) => + await jobManager.RegisterOperation(job, async (paramJob, databaseContext, progressReporter, ct) => { using (var repos = await repoManager.CloneRepository(new Uri(origin), cloneBranch, currentModel.AccessUser, currentModel.AccessToken, progressReporter, ct).ConfigureAwait(false)) { if (repos == null) throw new JobException("Filesystem conflict while cloning repository!"); - var db = serviceProvider.GetRequiredService(); var instance = new Models.Instance { Id = Instance.Id }; - db.Instances.Attach(instance); - if (await PopulateApi(api, repos, db, instance, ct).ConfigureAwait(false)) - await db.Save(ct).ConfigureAwait(false); + databaseContext.Instances.Attach(instance); + if (await PopulateApi(api, repos, databaseContext, instance, ct).ConfigureAwait(false)) + await databaseContext.Save(ct).ConfigureAwait(false); } }, cancellationToken).ConfigureAwait(false); @@ -238,7 +236,7 @@ namespace Tgstation.Server.Host.Controllers Instance = Instance }; var api = currentModel.ToApi(); - await jobManager.RegisterOperation(job, (paramJob, serviceProvider, progressReporter, ct) => instanceManager.GetInstance(Instance).RepositoryManager.DeleteRepository(cancellationToken), cancellationToken).ConfigureAwait(false); + await jobManager.RegisterOperation(job, (paramJob, databaseContext, progressReporter, ct) => instanceManager.GetInstance(Instance).RepositoryManager.DeleteRepository(cancellationToken), cancellationToken).ConfigureAwait(false); api.ActiveJob = job.ToApi(); return Accepted(api); } @@ -419,7 +417,7 @@ namespace Tgstation.Server.Host.Controllers CancelRight = (ulong)RepositoryRights.CancelPendingChanges, }; - await jobManager.RegisterOperation(job, async (paramJob, serviceProvider, progressReporter, ct) => + await jobManager.RegisterOperation(job, async (paramJob, databaseContext, progressReporter, ct) => { using (var repo = await repoManager.LoadRepository(ct).ConfigureAwait(false)) { @@ -443,8 +441,7 @@ namespace Tgstation.Server.Host.Controllers //get a base line for where we are Models.RevisionInformation lastRevisionInfo = null; - - var databaseContext = serviceProvider.GetRequiredService(); + var attachedInstance = new Models.Instance { Id = Instance.Id diff --git a/src/Tgstation.Server.Host/Core/IJobManager.cs b/src/Tgstation.Server.Host/Core/IJobManager.cs index 7389ce78d5..12ecf7666f 100644 --- a/src/Tgstation.Server.Host/Core/IJobManager.cs +++ b/src/Tgstation.Server.Host/Core/IJobManager.cs @@ -20,10 +20,10 @@ namespace Tgstation.Server.Host.Core /// Registers a given and begins running it /// /// The - /// The operation to run taking the started , a progress reporter and a + /// The operation to run taking the started , a , progress reporter and a /// The for the operation /// A representing a running operation - Task RegisterOperation(Job job, Func, CancellationToken, Task> operation, CancellationToken cancellationToken); + Task RegisterOperation(Job job, Func, CancellationToken, Task> operation, CancellationToken cancellationToken); /// /// Wait for a given to complete diff --git a/src/Tgstation.Server.Host/Core/JobManager.cs b/src/Tgstation.Server.Host/Core/JobManager.cs index 304f2d0acd..2900dc28f4 100644 --- a/src/Tgstation.Server.Host/Core/JobManager.cs +++ b/src/Tgstation.Server.Host/Core/JobManager.cs @@ -1,5 +1,4 @@ using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; @@ -16,7 +15,7 @@ namespace Tgstation.Server.Host.Core /// /// The for the /// - readonly IServiceProvider serviceProvider; + readonly IDatabaseContextFactory databaseContextFactory; /// /// The for the @@ -31,11 +30,11 @@ namespace Tgstation.Server.Host.Core /// /// Construct a /// - /// The value of + /// The value of /// The value of - public JobManager(IServiceProvider serviceProvider, ILogger logger) + public JobManager(IDatabaseContextFactory databaseContextFactory, ILogger logger) { - this.serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); + this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); jobs = new Dictionary(); } @@ -69,11 +68,11 @@ namespace Tgstation.Server.Host.Core /// The operation for the /// The for the operation /// A representing the running operation - async Task RunJob(Job job, Func operation, CancellationToken cancellationToken) + async Task RunJob(Job job, Func operation, CancellationToken cancellationToken) { try { - using (var scope = serviceProvider.CreateScope()) + await databaseContextFactory.UseContext(async databaseContext => { async Task HandleExceptions(Task task) { @@ -97,15 +96,13 @@ namespace Tgstation.Server.Host.Core } } - IDatabaseContext databaseContext = null; async Task RunJobInternal() { var oldJob = job; job = new Job { Id = oldJob.Id }; - databaseContext = scope.ServiceProvider.GetRequiredService(); databaseContext.Jobs.Attach(job); - await operation(job, scope.ServiceProvider, cancellationToken).ConfigureAwait(false); + await operation(job, databaseContext, cancellationToken).ConfigureAwait(false); logger.LogDebug("Job {0} completed!", job.Id); }; @@ -123,7 +120,7 @@ namespace Tgstation.Server.Host.Core if (JobErroredOrCancelled()) await databaseContext.Save(default).ConfigureAwait(false); } - } + }).ConfigureAwait(false); } finally { @@ -137,50 +134,44 @@ namespace Tgstation.Server.Host.Core } /// - public async Task RegisterOperation(Job job, Func, CancellationToken, Task> operation, CancellationToken cancellationToken) + public Task RegisterOperation(Job job, Func, CancellationToken, Task> operation, CancellationToken cancellationToken) => databaseContextFactory.UseContext(async databaseContext => { - using (var scope = serviceProvider.CreateScope()) + job.StartedAt = DateTimeOffset.Now; + job.Cancelled = false; + job.Instance = new Instance { - var databaseContext = scope.ServiceProvider.GetRequiredService(); - job.StartedAt = DateTimeOffset.Now; - job.Cancelled = false; - job.Instance = new Instance + Id = job.Instance.Id + }; + databaseContext.Instances.Attach(job.Instance); + if (job.StartedBy != null) + { + job.StartedBy = new User { - Id = job.Instance.Id + Id = job.StartedBy.Id }; - databaseContext.Instances.Attach(job.Instance); - if (job.StartedBy != null) - { - job.StartedBy = new User - { - Id = job.StartedBy.Id - }; - databaseContext.Users.Attach(job.StartedBy); - } - databaseContext.Jobs.Add(job); - await databaseContext.Save(cancellationToken).ConfigureAwait(false); - logger.LogDebug("Starting job {0}: {1}...", job.Id, job.Description); - var jobHandler = JobHandler.Create(x => RunJob(job, (jobParam, serviceProvider, ct) => - operation(jobParam, serviceProvider, y => - { - lock (this) - if (jobs.TryGetValue(job.Id, out var handler)) - handler.Progress = y; - }, ct), - x)); - lock (this) - jobs.Add(job.Id, jobHandler); + databaseContext.Users.Attach(job.StartedBy); } - } + databaseContext.Jobs.Add(job); + await databaseContext.Save(cancellationToken).ConfigureAwait(false); + logger.LogDebug("Starting job {0}: {1}...", job.Id, job.Description); + var jobHandler = JobHandler.Create(x => RunJob(job, (jobParam, serviceProvider, ct) => + operation(jobParam, serviceProvider, y => + { + lock (this) + if (jobs.TryGetValue(job.Id, out var handler)) + handler.Progress = y; + }, ct), + x)); + lock (this) + jobs.Add(job.Id, jobHandler); + }); /// public async Task StartAsync(CancellationToken cancellationToken) { logger.LogTrace("Starting job manager..."); - using (var scope = serviceProvider.CreateScope()) + await databaseContextFactory.UseContext(async databaseContext => { - var databaseContext = scope.ServiceProvider.GetRequiredService(); - //mark all jobs as cancelled var badJobs = await databaseContext.Jobs.Where(y => !y.StoppedAt.HasValue).Select(y => y.Id).ToListAsync(cancellationToken).ConfigureAwait(false); if (badJobs.Count > 0) @@ -195,7 +186,7 @@ namespace Tgstation.Server.Host.Core } await databaseContext.Save(cancellationToken).ConfigureAwait(false); } - } + }).ConfigureAwait(false); logger.LogDebug("Job manager started!"); } @@ -228,9 +219,8 @@ namespace Tgstation.Server.Host.Core return false; } handler.Cancel(); //this will ensure the db update is only done once - using (var scope = serviceProvider.CreateScope()) + await databaseContextFactory.UseContext(async databaseContext => { - var databaseContext = scope.ServiceProvider.GetRequiredService(); job = new Job { Id = job.Id }; databaseContext.Jobs.Attach(job); user = new User { Id = user.Id }; @@ -238,7 +228,7 @@ namespace Tgstation.Server.Host.Core job.CancelledBy = user; //let either startup or cancellation set job.cancelled await databaseContext.Save(cancellationToken).ConfigureAwait(false); - } + }).ConfigureAwait(false); if (blocking) await handler.Wait(cancellationToken).ConfigureAwait(false); return true;