Implement a primary key on jobs so that they only run one at a time

This commit is contained in:
Timothy Baldridge
2020-04-11 07:59:15 -06:00
parent ac7b4ed3ac
commit c02c1cd693
13 changed files with 41 additions and 4 deletions

View File

@ -41,6 +41,10 @@ namespace Wabbajack.BuildServer.Test
var found = await sqlService.GetJob(); var found = await sqlService.GetJob();
Assert.NotNull(found); Assert.NotNull(found);
Assert.Equal(pri, found.Priority); Assert.Equal(pri, found.Priority);
found.Result = JobResult.Success();
// Finish the job so the next can run
await sqlService.FinishJob(found);
} }
} }

View File

@ -204,6 +204,7 @@ GO
CREATE TABLE [dbo].[Jobs]( CREATE TABLE [dbo].[Jobs](
[Id] [bigint] IDENTITY(1,1) NOT NULL, [Id] [bigint] IDENTITY(1,1) NOT NULL,
[Priority] [int] NOT NULL, [Priority] [int] NOT NULL,
[PrimaryKeyString] [nvarchar](max) NULL,
[Started] [datetime] NULL, [Started] [datetime] NULL,
[Ended] [datetime] NULL, [Ended] [datetime] NULL,
[Created] [datetime] NOT NULL, [Created] [datetime] NOT NULL,

View File

@ -30,6 +30,10 @@ namespace Wabbajack.BuildServer.Models.JobQueue
public virtual bool UsesNexus { get; } = false; public virtual bool UsesNexus { get; } = false;
public abstract Task<JobResult> Execute(SqlService sql,AppSettings settings); public abstract Task<JobResult> Execute(SqlService sql,AppSettings settings);
protected abstract IEnumerable<object> PrimaryKey { get; }
public string PrimaryKeyString => string.Join("|", PrimaryKey.Cons(this.GetType().Name).Select(i => i.ToString()));
static AJobPayload() static AJobPayload()
{ {

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Linq; using System.Linq;
using Wabbajack.BuildServer.Model.Models; using Wabbajack.BuildServer.Model.Models;
@ -38,6 +39,8 @@ namespace Wabbajack.BuildServer.Models.Jobs
return JobResult.Success(); return JobResult.Success();
} }
protected override IEnumerable<object> PrimaryKey => new object[0];
private static async Task EnqueueFromList(SqlService sql, ModlistMetadata list, WorkQueue queue) private static async Task EnqueueFromList(SqlService sql, ModlistMetadata list, WorkQueue queue)
{ {
var modlistPath = Consts.ModListDownloadFolder.Combine(list.Links.MachineURL + Consts.ModListExtension); var modlistPath = Consts.ModListDownloadFolder.Combine(list.Links.MachineURL + Consts.ModListExtension);

View File

@ -1,4 +1,5 @@
using System.Linq; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Wabbajack.BuildServer.Models.JobQueue; using Wabbajack.BuildServer.Models.JobQueue;
using Wabbajack.Common; using Wabbajack.Common;
@ -65,5 +66,7 @@ namespace Wabbajack.BuildServer.Models.Jobs
} }
} }
protected override IEnumerable<object> PrimaryKey => new object[0];
} }
} }

View File

@ -71,6 +71,8 @@ namespace Wabbajack.BuildServer.Models.Jobs
return JobResult.Success(); return JobResult.Success();
} }
protected override IEnumerable<object> PrimaryKey => new object[0];
public static DateTime LastNexusSync { get; set; } = DateTime.Now; public static DateTime LastNexusSync { get; set; } = DateTime.Now;
public static async Task<long> UpdateNexusCacheFast(SqlService sql) public static async Task<long> UpdateNexusCacheFast(SqlService sql)
{ {

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -64,5 +65,7 @@ namespace Wabbajack.BuildServer.Models.Jobs
return JobResult.Success(); return JobResult.Success();
} }
protected override IEnumerable<object> PrimaryKey => new object[0];
} }
} }

View File

@ -63,6 +63,7 @@ namespace Wabbajack.BuildServer.Models.Jobs
return JobResult.Success(); return JobResult.Success();
} }
protected override IEnumerable<object> PrimaryKey => Archive.State.PrimaryKey;
} }
} }

View File

@ -69,5 +69,7 @@ namespace Wabbajack.BuildServer.Models.Jobs
} }
return JobResult.Success(); return JobResult.Success();
} }
protected override IEnumerable<object> PrimaryKey => new object[0];
} }
} }

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Wabbajack.BuildServer.Model.Models; using Wabbajack.BuildServer.Model.Models;
@ -43,7 +44,9 @@ namespace Wabbajack.BuildServer.Models.Jobs
return JobResult.Success(); return JobResult.Success();
} }
protected override IEnumerable<object> PrimaryKey => new object[0];
private async Task ValidateList(SqlService sql, ModlistMetadata list, WorkQueue queue, ValidateModlist whitelists) private async Task ValidateList(SqlService sql, ModlistMetadata list, WorkQueue queue, ValidateModlist whitelists)
{ {
var modlistPath = Consts.ModListDownloadFolder.Combine(list.Links.MachineURL + Consts.ModListExtension); var modlistPath = Consts.ModListDownloadFolder.Combine(list.Links.MachineURL + Consts.ModListExtension);

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Net; using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using Alphaleonis.Win32.Filesystem; using Alphaleonis.Win32.Filesystem;
@ -72,6 +73,8 @@ namespace Wabbajack.BuildServer.Models.Jobs
return JobResult.Success(); return JobResult.Success();
} }
protected override IEnumerable<object> PrimaryKey => new object[] {FileId};
public class Progress : IProgress<FluentFTP.FtpProgress> public class Progress : IProgress<FluentFTP.FtpProgress>
{ {
private RelativePath _name; private RelativePath _name;

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Net; using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using FluentFTP; using FluentFTP;
@ -74,6 +75,8 @@ namespace Wabbajack.BuildServer.Models
} }
protected override IEnumerable<object> PrimaryKey => new object[] {Src, DestPK};
public static AbsolutePath CdnPath(Hash srcHash, Hash destHash) public static AbsolutePath CdnPath(Hash srcHash, Hash destHash)
{ {
return $"updates/{srcHash.ToHex()}_{destHash.ToHex()}".RelativeTo(AbsolutePath.EntryPoint); return $"updates/{srcHash.ToHex()}_{destHash.ToHex()}".RelativeTo(AbsolutePath.EntryPoint);

View File

@ -181,9 +181,10 @@ namespace Wabbajack.BuildServer.Model.Models
{ {
await using var conn = await Open(); await using var conn = await Open();
await conn.ExecuteAsync( await conn.ExecuteAsync(
@"INSERT INTO dbo.Jobs (Created, Priority, Payload, OnSuccess) VALUES (GETDATE(), @Priority, @Payload, @OnSuccess)", @"INSERT INTO dbo.Jobs (Created, Priority, PrimaryKeyString, Payload, OnSuccess) VALUES (GETDATE(), @Priority, @PrimaryKeyString, @Payload, @OnSuccess)",
new { new {
job.Priority, job.Priority,
PrimaryKeyString = job.Payload.PrimaryKeyString,
Payload = job.Payload.ToJson(), Payload = job.Payload.ToJson(),
OnSuccess = job.OnSuccess?.ToJson() ?? null}); OnSuccess = job.OnSuccess?.ToJson() ?? null});
} }
@ -217,7 +218,11 @@ namespace Wabbajack.BuildServer.Model.Models
{ {
await using var conn = await Open(); await using var conn = await Open();
var result = await conn.QueryAsync<Job>( var result = await conn.QueryAsync<Job>(
@"UPDATE jobs SET Started = GETDATE(), RunBy = @RunBy WHERE ID in (SELECT TOP(1) ID FROM Jobs WHERE Started is NULL ORDER BY Priority DESC, Created); @"UPDATE jobs SET Started = GETDATE(), RunBy = @RunBy
WHERE ID in (SELECT TOP(1) ID FROM Jobs
WHERE Started is NULL
AND PrimaryKeyString NOT IN (SELECT PrimaryKeyString from jobs WHERE Started IS NOT NULL and Ended IS NULL)
ORDER BY Priority DESC, Created);
SELECT TOP(1) * FROM jobs WHERE RunBy = @RunBy ORDER BY Started DESC", SELECT TOP(1) * FROM jobs WHERE RunBy = @RunBy ORDER BY Started DESC",
new {RunBy = Guid.NewGuid().ToString()}); new {RunBy = Guid.NewGuid().ToString()});
return result.FirstOrDefault(); return result.FirstOrDefault();