Move live and staged CompileJobs out of IWatchdog and back to db

DmbFactory handles setting staged. Watchdog handles clearing it and setting active
This commit is contained in:
Cyberboss
2018-07-10 12:50:23 -04:00
parent 59b855156b
commit 7a86602b71
9 changed files with 86 additions and 37 deletions
@@ -36,6 +36,11 @@ namespace Tgstation.Server.Host.Components
/// The <see cref="CancellationTokenSource"/> for <see cref="cleanupTask"/>
/// </summary>
readonly CancellationTokenSource cleanupCts;
/// <summary>
/// The <see cref="Api.Models.Instance.Id"/> the <see cref="DmbFactory"/> belongs to
/// </summary>
readonly long instanceId;
/// <summary>
/// <see cref="Task"/> representing calls to <see cref="CleanJob(CompileJob)"/>
@@ -57,10 +62,12 @@ namespace Tgstation.Server.Host.Components
/// </summary>
/// <param name="databaseContextFactory">The value of <see cref="databaseContextFactory"/></param>
/// <param name="ioManager">The value of <see cref="ioManager"/></param>
public DmbFactory(IDatabaseContextFactory databaseContextFactory, IIOManager ioManager)
/// <param name="instance">The <see cref="Models.Instance"/> used to populate <see cref="instanceId"/></param>
public DmbFactory(IDatabaseContextFactory databaseContextFactory, IIOManager ioManager, Models.Instance instance)
{
this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory));
this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
instanceId = instance?.Id ?? throw new ArgumentNullException(nameof(instance));
cleanupCts = new CancellationTokenSource();
jobLockCounts = new Dictionary<long, int>();
@@ -92,12 +99,25 @@ namespace Tgstation.Server.Host.Components
}
/// <inheritdoc />
public void LoadCompileJob(CompileJob job)
public Task LoadCompileJob(CompileJob job, CancellationToken cancellationToken) => LoadCompileJob(job, true, cancellationToken);
async Task LoadCompileJob(CompileJob job, bool setAsStagedInDb, CancellationToken cancellationToken)
{
if (job == null)
throw new ArgumentNullException(nameof(job));
if (!job.DMApiValidated || job.Job.Cancelled || job.Job.ExceptionDetails != null || job.Job.StoppedAt == null)
throw new InvalidOperationException("Cannot load incomplete compile job!");
if (setAsStagedInDb)
await databaseContextFactory.UseContext(async db =>
{
var ddsettings = new DreamDaemonSettings
{
InstanceId = instanceId
};
db.DreamDaemonSettings.Attach(ddsettings);
ddsettings.StagedCompileJob = job;
await db.Save(cancellationToken).ConfigureAwait(false);
}).ConfigureAwait(false);
lock (this)
{
var oldDmbProvider = nextDmbProvider;
@@ -130,13 +150,16 @@ namespace Tgstation.Server.Host.Components
/// <inheritdoc />
public Task StartAsync(CancellationToken cancellationToken) => databaseContextFactory.UseContext(async (db) =>
{
var cj = await db.CompileJobs.OrderByDescending(x => x.Job.StoppedAt).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
//where complete clause not necessary, only successful COMPILEjobs get in the db
var cj = await db.Instances.Where(x => x.Id == instanceId).SelectMany(x => x.CompileJobs).OrderByDescending(x => x.Job.StoppedAt).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
if (cj == default(CompileJob))
return;
LoadCompileJob(cj);
var directoriesTask = ioManager.GetDirectories(".", cancellationToken);
var compileJobTask = LoadCompileJob(cj, false, cancellationToken);
//delete all other compile jobs
var directories = await ioManager.GetDirectories(".", cancellationToken).ConfigureAwait(false);
var directories = await directoriesTask.ConfigureAwait(false);
await Task.WhenAll(directories.Where(x => x != cj.Job.ToString()).Select(x => ioManager.DeleteDirectory(x, cancellationToken))).ConfigureAwait(false);
await compileJobTask.ConfigureAwait(false);
});
/// <inheritdoc />
@@ -172,7 +172,7 @@ namespace Tgstation.Server.Host.Components
/// <param name="job">The <see cref="Host.Models.CompileJob"/> for the operation</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task"/> representing the running operation</returns>
async Task ModifyDme(Host.Models.CompileJob job, CancellationToken cancellationToken)
async Task ModifyDme(Models.CompileJob job, CancellationToken cancellationToken)
{
var dirA = ioManager.ConcatPath(job.DirectoryName.ToString(), ADirectoryName);
var dmePath = ioManager.ConcatPath(dirA, String.Concat(job.DmeName, DmeExtension));
@@ -288,7 +288,7 @@ namespace Tgstation.Server.Host.Components
await configuration.SymlinkStaticFilesTo(ioManager.ResolvePath(dirB), cancellationToken).ConfigureAwait(false);
await symATask.ConfigureAwait(false);
}
compileJobConsumer.LoadCompileJob(job);
await compileJobConsumer.LoadCompileJob(job, cancellationToken).ConfigureAwait(false);
return job;
}
catch
@@ -1,11 +1,13 @@
using Microsoft.Extensions.Hosting;
using System;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Host.Models;
namespace Tgstation.Server.Host.Components
{
interface ICompileJobConsumer : IHostedService, IDisposable
{
void LoadCompileJob(CompileJob job);
Task LoadCompileJob(CompileJob job, CancellationToken cancellationToken);
}
}
@@ -28,7 +28,7 @@ namespace Tgstation.Server.Host.Components
}
/// <inheritdoc />
public IInstance CreateInstance(Host.Models.Instance metadata)
public IInstance CreateInstance(Models.Instance metadata)
{
//Create the ioManager for the instance
@@ -41,7 +41,7 @@ namespace Tgstation.Server.Host.Components
var configurationIoManager = new ResolvingIOManager(instanceIoManager, "Configuration");
var codeModificationsIoMananger = new ResolvingIOManager(instanceIoManager, "CodeModifications");
var dmbFactory = new DmbFactory(databaseContextFactory, gameIoManager);
var dmbFactory = new DmbFactory(databaseContextFactory, gameIoManager, metadata);
@@ -26,16 +26,6 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// </summary>
LaunchResult LastLaunchResult { get; }
/// <summary>
/// The <see cref="Models.CompileJob"/> that is currently live
/// </summary>
Models.CompileJob LiveCompileJob { get; }
/// <summary>
/// The <see cref="Models.CompileJob"/> that is staged to go live
/// </summary>
Models.CompileJob StagedCompileJob { get; }
/// <summary>
/// The <see cref="DreamDaemonLaunchParameters"/> the active server is using
/// </summary>
@@ -29,12 +29,6 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// <inheritdoc />
public LaunchResult LastLaunchResult { get; private set; }
/// <inheritdoc />
public Models.CompileJob LiveCompileJob { get; private set; }
/// <inheritdoc />
public Models.CompileJob StagedCompileJob { get; private set; }
/// <inheritdoc />
public DreamDaemonLaunchParameters ActiveLaunchParameters { get; private set; }
@@ -69,11 +63,21 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// </summary>
readonly IReattachInfoHandler reattachInfoHandler;
/// <summary>
/// The <see cref="IDatabaseContextFactory"/> for the <see cref="Watchdog"/>
/// </summary>
readonly IDatabaseContextFactory databaseContextFactory;
/// <summary>
/// The <see cref="SemaphoreSlim"/> for the <see cref="Watchdog"/>
/// </summary>
readonly SemaphoreSlim semaphore;
/// <summary>
/// The <see cref="Api.Models.Instance.Id"/> the <see cref="Watchdog"/> belongs to
/// </summary>
readonly long instanceId;
CancellationTokenSource monitorCts;
Task monitorTask;
@@ -94,14 +98,18 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// <param name="serverUpdater">The <see cref="IServerUpdater"/> for the <see cref="Watchdog"/></param>
/// <param name="logger">The value of <see cref="logger"/></param>
/// <param name="reattachInfoHandler">The value of <see cref="reattachInfoHandler"/></param>
/// <param name="databaseContextFactory">The value of <see cref="databaseContextFactory"/></param>
/// <param name="initialLaunchParameters">The initial value of <see cref="ActiveLaunchParameters"/></param>
public Watchdog(IChat chat, ISessionControllerFactory sessionControllerFactory, IDmbFactory dmbFactory, IServerUpdater serverUpdater, ILogger<Watchdog> logger, IReattachInfoHandler reattachInfoHandler, DreamDaemonLaunchParameters initialLaunchParameters)
/// <param name="instance">The <see cref="Models.Instance"/> containing the value of <see cref="instanceId"/></param>
public Watchdog(IChat chat, ISessionControllerFactory sessionControllerFactory, IDmbFactory dmbFactory, IServerUpdater serverUpdater, ILogger<Watchdog> logger, IReattachInfoHandler reattachInfoHandler, IDatabaseContextFactory databaseContextFactory, DreamDaemonLaunchParameters initialLaunchParameters, Models.Instance instance)
{
this.chat = chat ?? throw new ArgumentNullException(nameof(chat));
this.sessionControllerFactory = sessionControllerFactory ?? throw new ArgumentNullException(nameof(sessionControllerFactory));
this.dmbFactory = dmbFactory ?? throw new ArgumentNullException(nameof(dmbFactory));
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
this.reattachInfoHandler = reattachInfoHandler ?? throw new ArgumentNullException(nameof(reattachInfoHandler));
this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory));
instanceId = instance?.Id ?? throw new ArgumentNullException(nameof(instance));
if (serverUpdater == null)
throw new ArgumentNullException(nameof(serverUpdater));
@@ -416,11 +424,24 @@ namespace Tgstation.Server.Host.Components.Watchdog
using (cancellationToken.Register(() => cancelTcs.SetCanceled()))
await Task.WhenAny(allTask, cancelTcs.Task).ConfigureAwait(false);
//update the live and staged jobs in the db
await databaseContextFactory.UseContext(async db =>
{
var settings = new Models.DreamDaemonSettings
{
InstanceId = instanceId
};
var cj = (AlphaIsActive ? alphaServer : bravoServer).Dmb.CompileJob;
db.CompileJobs.Attach(cj);
db.DreamDaemonSettings.Attach(settings);
settings.StagedCompileJob = null;
settings.ActiveCompileJob = cj;
await db.Save(cancellationToken).ConfigureAwait(false);
}).ConfigureAwait(false);
//both servers are now running, alpha is the active server, huzzah
AlphaIsActive = doReattach ? reattachInfo.AlphaIsActive : true;
LiveCompileJob = AlphaIsActive ? alphaServer.Dmb.CompileJob : bravoServer.Dmb.CompileJob;
LastLaunchResult = alphaLrt.Result;
StagedCompileJob = null;
Running = true;
if (startMonitor)
@@ -34,6 +34,17 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// </summary>
readonly IReattachInfoHandler reattachInfoHandler;
/// <summary>
/// The <see cref="IDatabaseContextFactory"/> for the <see cref="WatchdogFactory"/>
/// </summary>
readonly IDatabaseContextFactory databaseContextFactory;
/// <summary>
/// The <see cref="Models.Instance"/> for the <see cref="WatchdogFactory"/>
/// </summary>
readonly Models.Instance instance;
/// <summary>
/// Construct a <see cref="WatchdogFactory"/>
/// </summary>
@@ -42,16 +53,20 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// <param name="serverUpdater">The value of <see cref="serverUpdater"/></param>
/// <param name="loggerFactory">The value of <see cref="loggerFactory"/></param>
/// <param name="reattachInfoHandler">The value of <see cref="reattachInfoHandler"/></param>
public WatchdogFactory(IChat chat, ISessionControllerFactory sessionManagerFactory, IServerUpdater serverUpdater, ILoggerFactory loggerFactory, IReattachInfoHandler reattachInfoHandler)
/// <param name="databaseContextFactory">The value of <see cref="databaseContextFactory"/></param>
/// <param name="instance">The value of <see cref="instance"/></param>
public WatchdogFactory(IChat chat, ISessionControllerFactory sessionManagerFactory, IServerUpdater serverUpdater, ILoggerFactory loggerFactory, IReattachInfoHandler reattachInfoHandler, IDatabaseContextFactory databaseContextFactory, Models.Instance instance)
{
this.chat = chat ?? throw new ArgumentNullException(nameof(chat));
this.sessionManagerFactory = sessionManagerFactory ?? throw new ArgumentNullException(nameof(sessionManagerFactory));
this.serverUpdater = serverUpdater ?? throw new ArgumentNullException(nameof(serverUpdater));
this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
this.reattachInfoHandler = reattachInfoHandler ?? throw new ArgumentNullException(nameof(reattachInfoHandler));
this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory));
this.instance = instance ?? throw new ArgumentNullException(nameof(instance));
}
/// <inheritdoc />
public IWatchdog CreateWatchdog(IDmbFactory dmbFactory, DreamDaemonLaunchParameters launchParameters) => new Watchdog(chat, sessionManagerFactory, dmbFactory, serverUpdater, loggerFactory.CreateLogger<Watchdog>(), reattachInfoHandler, launchParameters);
public IWatchdog CreateWatchdog(IDmbFactory dmbFactory, DreamDaemonLaunchParameters launchParameters) => new Watchdog(chat, sessionManagerFactory, dmbFactory, serverUpdater, loggerFactory.CreateLogger<Watchdog>(), reattachInfoHandler, databaseContextFactory, launchParameters, instance);
}
}
@@ -83,7 +83,7 @@ namespace Tgstation.Server.Host.Controllers
var metadata = (AuthenticationContext.GetRight(RightsType.DreamDaemon) & (int)DreamDaemonRights.ReadMetadata) != 0;
var revision = (AuthenticationContext.GetRight(RightsType.DreamDaemon) & (int)DreamDaemonRights.ReadRevision) != 0;
var settings = metadata ? await DatabaseContext.Instances.Where(x => x.Id == Instance.Id).Select(x => x.DreamDaemonSettings).FirstAsync(cancellationToken).ConfigureAwait(false) : null;
var settings = await DatabaseContext.Instances.Where(x => x.Id == Instance.Id).Select(x => x.DreamDaemonSettings).FirstAsync(cancellationToken).ConfigureAwait(false);
var result = new DreamDaemon();
if(metadata)
{
@@ -104,8 +104,8 @@ namespace Tgstation.Server.Host.Controllers
};
if (revision)
{
result.ActiveCompileJob = dd.LiveCompileJob?.ToApi();
result.StagedCompileJob = dd.StagedCompileJob?.ToApi();
result.ActiveCompileJob = settings.ActiveCompileJob?.ToApi();
result.StagedCompileJob = settings.StagedCompileJob?.ToApi();
}
return Json(result);
@@ -57,9 +57,7 @@ namespace Tgstation.Server.Host.Models
/// </summary>
public DbSet<ChatChannel> ChatChannels { get; set; }
/// <summary>
/// The <see cref="Job"/>s in the <see cref="DatabaseContext{TParentContext}"/>
/// </summary>
/// <inheritdoc />
public DbSet<Job> Jobs { get; set; }
/// <summary>