mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-27 07:04:57 +01:00
Cleanup cleanup
This commit is contained in:
@@ -4,9 +4,9 @@
|
||||
public sealed class CompileJob : Internal.CompileJob
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="User"/> that triggered the job
|
||||
/// The <see cref="Job"/> relating to this job
|
||||
/// </summary>
|
||||
public User TriggeredBy { get; set; }
|
||||
public Job Job { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Git revision the compiler ran on. Not modifiable
|
||||
|
||||
@@ -13,18 +13,6 @@ namespace Tgstation.Server.Api.Models.Internal
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When the compilation started
|
||||
/// </summary>
|
||||
[Required]
|
||||
public DateTimeOffset StartedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When the compilation finished
|
||||
/// </summary>
|
||||
[Required]
|
||||
public DateTimeOffset FinishedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the DMAPI version detected is compatible
|
||||
/// </summary>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Tgstation.Server.Api.Rights;
|
||||
|
||||
namespace Tgstation.Server.Api.Models.Internal
|
||||
{
|
||||
@@ -43,5 +44,17 @@ namespace Tgstation.Server.Api.Models.Internal
|
||||
/// </summary>
|
||||
[Permissions(DenyWrite = true)]
|
||||
public bool Cancelled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="RightsType"/> of <see cref="CancelRight"/> if it can be cancelled
|
||||
/// </summary>
|
||||
[Permissions(DenyWrite = true)]
|
||||
public RightsType? CancelRightsType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Rights"/> required to cancel the <see cref="Job"/>
|
||||
/// </summary>
|
||||
[Permissions(DenyWrite = true)]
|
||||
public int? CancelRight { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -11,16 +11,16 @@
|
||||
[Permissions(DenyWrite = true)]
|
||||
public int Progress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the current user has permission to cancel the job
|
||||
/// </summary>
|
||||
[Permissions(DenyWrite = true)]
|
||||
public bool UserCanCancel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="User"/> that started the job
|
||||
/// </summary>
|
||||
[Permissions(DenyWrite = true)]
|
||||
public User StartedBy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="User"/> that cancelled the job
|
||||
/// </summary>
|
||||
[Permissions(DenyWrite = true)]
|
||||
public User CancelledBy { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,67 +194,59 @@ namespace Tgstation.Server.Host.Components
|
||||
var job = new Host.Models.CompileJob
|
||||
{
|
||||
DirectoryName = Guid.NewGuid(),
|
||||
StartedAt = DateTimeOffset.Now,
|
||||
DmeName = dmeName
|
||||
};
|
||||
try
|
||||
await ioManager.CreateDirectory(job.DirectoryName.ToString(), cancellationToken).ConfigureAwait(false);
|
||||
var dirA = ioManager.ConcatPath(job.DirectoryName.ToString(), ADirectoryName);
|
||||
var dirB = ioManager.ConcatPath(job.DirectoryName.ToString(), "B");
|
||||
|
||||
async Task CleanupFailedCompile()
|
||||
{
|
||||
await ioManager.CreateDirectory(job.DirectoryName.ToString(), cancellationToken).ConfigureAwait(false);
|
||||
var dirA = ioManager.ConcatPath(job.DirectoryName.ToString(), ADirectoryName);
|
||||
var dirB = ioManager.ConcatPath(job.DirectoryName.ToString(), "B");
|
||||
|
||||
async Task CleanupFailedCompile()
|
||||
{
|
||||
try
|
||||
{
|
||||
await ioManager.DeleteDirectory(job.DirectoryName.ToString(), CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
//copy the repository
|
||||
var fullDirA = ioManager.ResolvePath(dirA);
|
||||
using (repository)
|
||||
await repository.CopyTo(fullDirA, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
await ModifyDme(job, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
//run compiler, verify api
|
||||
var ddVerified = await byond.UseExecutables(async (dreamMakerPath, dreamDaemonPath) =>
|
||||
{
|
||||
await RunDreamMaker(dreamMakerPath, job, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return job.ExitCode == 0 && await VerifyApi(dreamDaemonPath, job, cancellationToken).ConfigureAwait(false);
|
||||
}, true).ConfigureAwait(false);
|
||||
|
||||
if (!ddVerified)
|
||||
//server never validated or compile failed
|
||||
await CleanupFailedCompile().ConfigureAwait(false);
|
||||
else
|
||||
{
|
||||
job.DMApiValidated = true;
|
||||
|
||||
//duplicate the dmb et al
|
||||
await ioManager.CopyDirectory(dirA, dirB, null, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
//symlink in the static data
|
||||
var symATask = configuration.SymlinkStaticFilesTo(fullDirA, cancellationToken);
|
||||
await configuration.SymlinkStaticFilesTo(ioManager.ResolvePath(dirB), cancellationToken).ConfigureAwait(false);
|
||||
await symATask.ConfigureAwait(false);
|
||||
}
|
||||
return job;
|
||||
await ioManager.DeleteDirectory(job.DirectoryName.ToString(), CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await CleanupFailedCompile().ConfigureAwait(false);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
finally
|
||||
catch { }
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
job.FinishedAt = DateTimeOffset.Now;
|
||||
//copy the repository
|
||||
var fullDirA = ioManager.ResolvePath(dirA);
|
||||
using (repository)
|
||||
await repository.CopyTo(fullDirA, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
await ModifyDme(job, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
//run compiler, verify api
|
||||
var ddVerified = await byond.UseExecutables(async (dreamMakerPath, dreamDaemonPath) =>
|
||||
{
|
||||
await RunDreamMaker(dreamMakerPath, job, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return job.ExitCode == 0 && await VerifyApi(dreamDaemonPath, job, cancellationToken).ConfigureAwait(false);
|
||||
}, true).ConfigureAwait(false);
|
||||
|
||||
if (!ddVerified)
|
||||
//server never validated or compile failed
|
||||
await CleanupFailedCompile().ConfigureAwait(false);
|
||||
else
|
||||
{
|
||||
job.DMApiValidated = true;
|
||||
|
||||
//duplicate the dmb et al
|
||||
await ioManager.CopyDirectory(dirA, dirB, null, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
//symlink in the static data
|
||||
var symATask = configuration.SymlinkStaticFilesTo(fullDirA, cancellationToken);
|
||||
await configuration.SymlinkStaticFilesTo(ioManager.ResolvePath(dirB), cancellationToken).ConfigureAwait(false);
|
||||
await symATask.ConfigureAwait(false);
|
||||
}
|
||||
return job;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await CleanupFailedCompile().ConfigureAwait(false);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,13 +40,16 @@ namespace Tgstation.Server.Host.Controllers
|
||||
var job = new Job
|
||||
{
|
||||
Description = "Compile active repository code",
|
||||
StartedBy = AuthenticationContext.User
|
||||
StartedBy = AuthenticationContext.User,
|
||||
CancelRightsType = RightsType.DreamMaker,
|
||||
CancelRight = (int)DreamMakerRights.CancelCompile
|
||||
};
|
||||
await jobManager.RegisterOperation(job, (serviceProvider, ct) => RunCompile(serviceProvider, Instance, AuthenticationContext.Clone(), ct), cancellationToken).ConfigureAwait(false);
|
||||
await jobManager.RegisterOperation(job, (paramJob, serviceProvider, ct) => RunCompile(paramJob, serviceProvider, Instance, ct), cancellationToken).ConfigureAwait(false);
|
||||
return Json(job);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[TgsAuthorize(DreamMakerRights.CancelCompile)]
|
||||
public override async Task<IActionResult> Delete([FromBody] Api.Models.CompileJob model, CancellationToken cancellationToken)
|
||||
{
|
||||
//alias for cancelling the latest job
|
||||
@@ -60,12 +63,12 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// <summary>
|
||||
/// Run the compile job and insert it into the database
|
||||
/// </summary>
|
||||
/// <param name="job">The running <see cref="Job"/></param>
|
||||
/// <param name="serviceProvider">The <see cref="IServiceProvider"/> for the operation</param>
|
||||
/// <param name="instanceModel">The <see cref="Models.Instance"/> for the operation</param>
|
||||
/// <param name="authenticationContext">The <see cref="IAuthenticationContext"/> for the operation</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
|
||||
/// <returns></returns>
|
||||
static async Task RunCompile(IServiceProvider serviceProvider, Models.Instance instanceModel, IAuthenticationContext authenticationContext, CancellationToken cancellationToken)
|
||||
/// <returns>A <see cref="Task"/> representing the running operation</returns>
|
||||
static async Task RunCompile(Job job, IServiceProvider serviceProvider, Models.Instance instanceModel, CancellationToken cancellationToken)
|
||||
{
|
||||
var instanceManager = serviceProvider.GetRequiredService<IInstanceManager>();
|
||||
var databaseContext = serviceProvider.GetRequiredService<IDatabaseContext>();
|
||||
@@ -82,7 +85,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
compileJob = await instance.DreamMaker.Compile(projectName, repo, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
compileJob.TriggeredBy = authenticationContext.User;
|
||||
compileJob.Job = job;
|
||||
compileJob.RevisionInformation = await revInfoTask.ConfigureAwait(false);
|
||||
|
||||
databaseContext.CompileJobs.Add(compileJob);
|
||||
|
||||
@@ -15,10 +15,10 @@ namespace Tgstation.Server.Host.Core
|
||||
/// Registers a given <see cref="Job"/> and begins running it
|
||||
/// </summary>
|
||||
/// <param name="job">The <see cref="Job"/></param>
|
||||
/// <param name="operation">The operation to run</param>
|
||||
/// <param name="operation">The operation to run taking the started <see cref="Job"/>, a <see cref="IServiceProvider"/> and a <see cref="CancellationToken"/></param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
|
||||
/// <returns>A <see cref="Task"/> representing a running operation</returns>
|
||||
Task RegisterOperation(Job job, Func<IServiceProvider, CancellationToken, Task> operation, CancellationToken cancellationToken);
|
||||
Task RegisterOperation(Job job, Func<Job, IServiceProvider, CancellationToken, Task> operation, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Wait for a given <paramref name="job"/> to complete
|
||||
|
||||
@@ -53,20 +53,21 @@ namespace Tgstation.Server.Host.Core
|
||||
/// <param name="operation">The operation for the <paramref name="job"/></param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
|
||||
/// <returns>A <see cref="Task"/> representing the running operation</returns>
|
||||
async Task RunJob(Job job, Func<IServiceProvider, CancellationToken, Task> operation, CancellationToken cancellationToken)
|
||||
async Task RunJob(Job job, Func<Job, IServiceProvider, CancellationToken, Task> operation, CancellationToken cancellationToken)
|
||||
{
|
||||
using (var scope = serviceProvider.CreateScope())
|
||||
{
|
||||
IDatabaseContext databaseContext = null;
|
||||
try
|
||||
{
|
||||
var oldJob = job;
|
||||
job = new Job { Id = oldJob.Id };
|
||||
try
|
||||
{
|
||||
await operation(scope.ServiceProvider, cancellationToken).ConfigureAwait(false);
|
||||
await operation(job, scope.ServiceProvider, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
job = new Job { Id = job.Id };
|
||||
databaseContext = scope.ServiceProvider.GetRequiredService<IDatabaseContext>();
|
||||
databaseContext.Jobs.Attach(job);
|
||||
}
|
||||
@@ -85,7 +86,7 @@ namespace Tgstation.Server.Host.Core
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task RegisterOperation(Job job, Func<IServiceProvider, CancellationToken, Task> operation, CancellationToken cancellationToken)
|
||||
public async Task RegisterOperation(Job job, Func<Job, IServiceProvider, CancellationToken, Task> operation, CancellationToken cancellationToken)
|
||||
{
|
||||
using (var scope = serviceProvider.CreateScope())
|
||||
{
|
||||
|
||||
@@ -1,16 +1,25 @@
|
||||
namespace Tgstation.Server.Host.Models
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Tgstation.Server.Host.Models
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public sealed class CompileJob : Api.Models.Internal.CompileJob
|
||||
{
|
||||
/// <summary>
|
||||
/// See <see cref="Api.Models.CompileJob.TriggeredBy"/>
|
||||
/// The <see cref="Api.Models.Internal.Job.Id"/> of <see cref="Job"/>
|
||||
/// </summary>
|
||||
public User TriggeredBy { get; set; }
|
||||
public long JobId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// See <see cref="Api.Models.CompileJob.Job"/>
|
||||
/// </summary>
|
||||
[Required]
|
||||
public Job Job { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// See <see cref="Api.Models.CompileJob.RevisionInformation"/>
|
||||
/// </summary>
|
||||
[Required]
|
||||
public RevisionInformation RevisionInformation { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user