Merge pull request #1028 from tgstation/979-TryFixPostgres

Try to fix postgres
This commit is contained in:
Jordan Brown
2020-05-27 16:57:20 -04:00
committed by GitHub
24 changed files with 277 additions and 105 deletions
@@ -76,14 +76,21 @@ namespace Tgstation.Server.Host.Components.Chat.Commands
head = repo.Head;
}
await databaseContextFactory.UseContext(async db => results = await db.RevisionInformations.Where(x => x.Instance.Id == instance.Id && x.CommitSha == head)
.SelectMany(x => x.ActiveTestMerges)
.Select(x => x.TestMerge)
.Select(x => new Models.TestMerge
{
Number = x.Number,
PullRequestRevision = x.PullRequestRevision
}).ToListAsync(cancellationToken).ConfigureAwait(false)).ConfigureAwait(false);
await databaseContextFactory.UseContext(
async db => results = await db
.RevisionInformations
.AsQueryable()
.Where(x => x.Instance.Id == instance.Id && x.CommitSha == head)
.SelectMany(x => x.ActiveTestMerges)
.Select(x => x.TestMerge)
.Select(x => new Models.TestMerge
{
Number = x.Number,
PullRequestRevision = x.PullRequestRevision
})
.ToListAsync(cancellationToken)
.ConfigureAwait(false))
.ConfigureAwait(false);
}
else
{
@@ -197,11 +197,17 @@ namespace Tgstation.Server.Host.Components.Deployment
// ensure we have the entire compile job tree
logger.LogTrace("Loading compile job {0}...", compileJob.Id);
await databaseContextFactory.UseContext(async db => compileJob = await db.CompileJobs.Where(x => x.Id == compileJob.Id)
.Include(x => x.Job).ThenInclude(x => x.StartedBy)
.Include(x => x.RevisionInformation).ThenInclude(x => x.PrimaryTestMerge).ThenInclude(x => x.MergedBy)
.Include(x => x.RevisionInformation).ThenInclude(x => x.ActiveTestMerges).ThenInclude(x => x.TestMerge).ThenInclude(x => x.MergedBy)
.FirstAsync(cancellationToken).ConfigureAwait(false)).ConfigureAwait(false); // can't wait to see that query
await databaseContextFactory.UseContext(
async db => compileJob = await db
.CompileJobs
.AsQueryable()
.Where(x => x.Id == compileJob.Id)
.Include(x => x.Job).ThenInclude(x => x.StartedBy)
.Include(x => x.RevisionInformation).ThenInclude(x => x.PrimaryTestMerge).ThenInclude(x => x.MergedBy)
.Include(x => x.RevisionInformation).ThenInclude(x => x.ActiveTestMerges).ThenInclude(x => x.TestMerge).ThenInclude(x => x.MergedBy)
.FirstAsync(cancellationToken)
.ConfigureAwait(false))
.ConfigureAwait(false); // can't wait to see that query
if (!compileJob.Job.StoppedAt.HasValue)
{
@@ -269,8 +275,12 @@ namespace Tgstation.Server.Host.Components.Deployment
// find the uids of locked directories
await databaseContextFactory.UseContext(async db =>
{
jobUidsToNotErase = (await db.CompileJobs.Where(
x => x.Job.Instance.Id == instance.Id && jobIdsToSkip.Contains(x.Id))
jobUidsToNotErase = (await db
.CompileJobs
.AsQueryable()
.Where(
x => x.Job.Instance.Id == instance.Id
&& jobIdsToSkip.Contains(x.Id))
.Select(x => x.DirectoryName.Value)
.ToListAsync(cancellationToken)
.ConfigureAwait(false))
@@ -506,6 +506,7 @@ namespace Tgstation.Server.Host.Components.Deployment
ddSettings = await databaseContext
.DreamDaemonSettings
.AsQueryable()
.Where(x => x.InstanceId == metadata.Id)
.Select(x => new Models.DreamDaemonSettings
{
@@ -516,12 +517,18 @@ namespace Tgstation.Server.Host.Components.Deployment
if (ddSettings == default)
throw new JobException(ErrorCode.InstanceMissingDreamDaemonSettings);
dreamMakerSettings = await databaseContext.DreamMakerSettings.Where(x => x.InstanceId == metadata.Id).FirstAsync(cancellationToken).ConfigureAwait(false);
dreamMakerSettings = await databaseContext
.DreamMakerSettings
.AsQueryable()
.Where(x => x.InstanceId == metadata.Id)
.FirstAsync(cancellationToken)
.ConfigureAwait(false);
if (dreamMakerSettings == default)
throw new JobException(ErrorCode.InstanceMissingDreamMakerSettings);
repositorySettings = await databaseContext
.RepositorySettings
.AsQueryable()
.Where(x => x.InstanceId == metadata.Id)
.Select(x => new Models.RepositorySettings
{
@@ -550,6 +557,7 @@ namespace Tgstation.Server.Host.Components.Deployment
var repoSha = repo.Head;
revInfo = await databaseContext
.RevisionInformations
.AsQueryable()
.Where(x => x.CommitSha == repoSha && x.Instance.Id == metadata.Id)
.Include(x => x.ActiveTestMerges)
.ThenInclude(x => x.TestMerge)
@@ -686,7 +694,9 @@ namespace Tgstation.Server.Host.Components.Deployment
/// <returns>A <see cref="Task{TResult}"/> resulting in the average <see cref="TimeSpan"/> of the 10 previous deployments or <see langword="null"/> if there are none.</returns>
async Task<TimeSpan?> CalculateExpectedDeploymentTime(IDatabaseContext databaseContext, CancellationToken cancellationToken)
{
var previousCompileJobs = await databaseContext.CompileJobs
var previousCompileJobs = await databaseContext
.CompileJobs
.AsQueryable()
.Where(x => x.Job.Instance.Id == metadata.Id)
.OrderByDescending(x => x.Job.StoppedAt)
.Take(10)
@@ -162,6 +162,7 @@ namespace Tgstation.Server.Host.Components
await databaseContextFactory.UseContext(
async (db) => user = await db
.Users
.AsQueryable()
.Where(x => x.CanonicalName == User.CanonicalizeName(Api.Models.User.AdminName))
.FirstAsync(cancellationToken)
.ConfigureAwait(false))
@@ -189,7 +190,11 @@ namespace Tgstation.Server.Host.Components
await databaseContextFactory.UseContext(
async databaseContext =>
{
var repositorySettingsTask = databaseContext.RepositorySettings.Where(x => x.InstanceId == metadata.Id).FirstAsync(jobCancellationToken);
var repositorySettingsTask = databaseContext
.RepositorySettings
.AsQueryable()
.Where(x => x.InstanceId == metadata.Id)
.FirstAsync(jobCancellationToken);
const int NumSteps = 3;
var doneSteps = 0;
@@ -225,6 +230,7 @@ namespace Tgstation.Server.Host.Components
bool hasDbChanges = false;
Task<RevisionInformation> LoadRevInfo() => databaseContext.RevisionInformations
.AsQueryable()
.Where(x => x.CommitSha == startSha && x.Instance.Id == metadata.Id)
.Include(x => x.ActiveTestMerges).ThenInclude(x => x.TestMerge)
.FirstOrDefaultAsync(cancellationToken);
@@ -294,6 +300,7 @@ namespace Tgstation.Server.Host.Components
var currentHead = repo.Head;
currentRevInfo = await databaseContext.RevisionInformations
.AsQueryable()
.Where(x => x.CommitSha == currentHead && x.Instance.Id == metadata.Id)
.FirstOrDefaultAsync(jobCancellationToken).ConfigureAwait(false);
@@ -213,10 +213,14 @@ namespace Tgstation.Server.Host.Components
var tasks = new List<Task>();
await databaseContextFactory.UseContext(async db =>
{
var jobs = db.Jobs.Where(x => x.Instance.Id == metadata.Id).Select(x => new Models.Job
{
Id = x.Id
}).ToAsyncEnumerable();
var jobs = db
.Jobs
.AsQueryable()
.Where(x => x.Instance.Id == metadata.Id)
.Select(x => new Models.Job
{
Id = x.Id
});
await jobs.ForEachAsync(job =>
{
lock (tasks)
@@ -271,7 +275,10 @@ namespace Tgstation.Server.Host.Components
var factoryStartup = instanceFactory.StartAsync(cancellationToken);
await databaseContext.Initialize(cancellationToken).ConfigureAwait(false);
await jobManager.StartAsync(cancellationToken).ConfigureAwait(false);
var dbInstances = databaseContext.Instances.Where(x => x.Online.Value)
var dbInstances = databaseContext
.Instances
.AsQueryable()
.Where(x => x.Online.Value)
.Include(x => x.RepositorySettings)
.Include(x => x.ChatSettings)
.ThenInclude(x => x.Channels)
@@ -56,7 +56,11 @@ namespace Tgstation.Server.Host.Components.Session
logger.LogDebug("Saving reattach information: {0}...", reattachInformation);
var deleteTask = db.WatchdogReattachInformations.Where(x => x.InstanceId == metadata.Id).DeleteAsync(cancellationToken);
var deleteTask = db
.WatchdogReattachInformations
.AsQueryable()
.Where(x => x.InstanceId == metadata.Id)
.DeleteAsync(cancellationToken);
Models.ReattachInformation ConvertReattachInfo(ReattachInformation wdInfo)
{
@@ -93,7 +97,9 @@ namespace Tgstation.Server.Host.Components.Session
Models.DualReattachInformation result = null;
await databaseContextFactory.UseContext(async (db) =>
{
var instance = await db.Instances.Where(x => x.Id == metadata.Id)
var instance = await db.Instances
.AsQueryable()
.Where(x => x.Id == metadata.Id)
.Include(x => x.WatchdogReattachInformation).ThenInclude(x => x.Alpha).ThenInclude(x => x.CompileJob)
.Include(x => x.WatchdogReattachInformation).ThenInclude(x => x.Bravo).ThenInclude(x => x.CompileJob)
.FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
@@ -857,6 +857,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
await databaseContextFactory.UseContext(
async db => adminUserId = await db
.Users
.AsQueryable()
.Where(x => x.CanonicalName == Models.User.CanonicalizeName(Api.Models.User.AdminName))
.Select(x => x.Id)
.FirstAsync(cancellationToken)
@@ -80,6 +80,7 @@ namespace Tgstation.Server.Host.Controllers
var countOfExistingBotsInInstance = await DatabaseContext
.ChatBots
.AsQueryable()
.Where(x => x.InstanceId == Instance.Id)
.CountAsync(cancellationToken)
.ConfigureAwait(false);
@@ -140,7 +141,14 @@ namespace Tgstation.Server.Host.Controllers
public async Task<IActionResult> Delete(long id, CancellationToken cancellationToken)
{
var instance = instanceManager.GetInstance(Instance);
await Task.WhenAll(instance.Chat.DeleteConnection(id, cancellationToken), DatabaseContext.ChatBots.Where(x => x.Id == id).DeleteAsync(cancellationToken)).ConfigureAwait(false);
await Task.WhenAll(
instance.Chat.DeleteConnection(id, cancellationToken),
DatabaseContext
.ChatBots
.AsQueryable()
.Where(x => x.Id == id)
.DeleteAsync(cancellationToken))
.ConfigureAwait(false);
return Ok();
}
@@ -156,7 +164,11 @@ namespace Tgstation.Server.Host.Controllers
[ProducesResponseType(typeof(IEnumerable<Api.Models.ChatBot>), 200)]
public async Task<IActionResult> List(CancellationToken cancellationToken)
{
var query = DatabaseContext.ChatBots.Where(x => x.InstanceId == Instance.Id).Include(x => x.Channels);
var query = DatabaseContext
.ChatBots
.AsQueryable()
.Where(x => x.InstanceId == Instance.Id)
.Include(x => x.Channels);
var results = await query.ToListAsync(cancellationToken).ConfigureAwait(false);
@@ -183,7 +195,10 @@ namespace Tgstation.Server.Host.Controllers
[ProducesResponseType(410)]
public async Task<IActionResult> GetId(long id, CancellationToken cancellationToken)
{
var query = DatabaseContext.ChatBots.Where(x => x.Id == id).Include(x => x.Channels);
var query = DatabaseContext.ChatBots
.AsQueryable()
.Where(x => x.Id == id)
.Include(x => x.Channels);
var results = await query.FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
if (results == default)
@@ -221,7 +236,11 @@ namespace Tgstation.Server.Host.Controllers
if (earlyOut != null)
return earlyOut;
var query = DatabaseContext.ChatBots.Where(x => x.InstanceId == Instance.Id && x.Id == model.Id).Include(x => x.Channels);
var query = DatabaseContext
.ChatBots
.AsQueryable()
.Where(x => x.InstanceId == Instance.Id && x.Id == model.Id)
.Include(x => x.Channels);
var current = await query.FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
@@ -109,7 +109,13 @@ namespace Tgstation.Server.Host.Controllers
if (settings == null)
{
settings = await DatabaseContext.Instances.Where(x => x.Id == Instance.Id).Select(x => x.DreamDaemonSettings).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
settings = await DatabaseContext
.Instances
.AsQueryable()
.Where(x => x.Id == Instance.Id)
.Select(x => x.DreamDaemonSettings)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
if (settings == default)
return StatusCode((int)HttpStatusCode.Gone);
}
@@ -191,7 +197,13 @@ namespace Tgstation.Server.Host.Controllers
return BadRequest(new ErrorMessage(ErrorCode.DreamDaemonDoubleSoft));
// alias for changing DD settings
var current = await DatabaseContext.Instances.Where(x => x.Id == Instance.Id).Select(x => x.DreamDaemonSettings).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
var current = await DatabaseContext
.Instances
.AsQueryable()
.Where(x => x.Id == Instance.Id)
.Select(x => x.DreamDaemonSettings)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
if (current == default)
return StatusCode((int)HttpStatusCode.Gone);
@@ -61,7 +61,12 @@ namespace Tgstation.Server.Host.Controllers
public async Task<IActionResult> Read(CancellationToken cancellationToken)
{
var instance = instanceManager.GetInstance(Instance);
var dreamMakerSettings = await DatabaseContext.DreamMakerSettings.Where(x => x.InstanceId == Instance.Id).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
var dreamMakerSettings = await DatabaseContext
.DreamMakerSettings
.AsQueryable()
.Where(x => x.InstanceId == Instance.Id)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
return Json(dreamMakerSettings.ToApi());
}
@@ -79,7 +84,9 @@ namespace Tgstation.Server.Host.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> GetId(long id, CancellationToken cancellationToken)
{
var compileJob = await DatabaseContext.CompileJobs
var compileJob = await DatabaseContext
.CompileJobs
.AsQueryable()
.Where(x => x.Id == id && x.Job.Instance.Id == Instance.Id)
.Include(x => x.Job).ThenInclude(x => x.StartedBy)
.Include(x => x.RevisionInformation).ThenInclude(x => x.PrimaryTestMerge).ThenInclude(x => x.MergedBy)
@@ -101,10 +108,17 @@ namespace Tgstation.Server.Host.Controllers
[ProducesResponseType(typeof(List<EntityId>), 200)]
public async Task<IActionResult> List(CancellationToken cancellationToken)
{
var compileJobs = await DatabaseContext.CompileJobs.Where(x => x.Job.Instance.Id == Instance.Id).OrderByDescending(x => x.Job.StoppedAt).Select(x => new EntityId
{
Id = x.Id
}).ToListAsync(cancellationToken).ConfigureAwait(false);
var compileJobs = await DatabaseContext
.CompileJobs
.AsQueryable()
.Where(x => x.Job.Instance.Id == Instance.Id)
.OrderByDescending(x => x.Job.StoppedAt)
.Select(x => new EntityId
{
Id = x.Id
})
.ToListAsync(cancellationToken)
.ConfigureAwait(false);
return Json(compileJobs);
}
@@ -159,7 +173,12 @@ namespace Tgstation.Server.Host.Controllers
if (model.ApiValidationPort == 0)
throw new InvalidOperationException("ApiValidationPort cannot be 0!");
var hostModel = await DatabaseContext.DreamMakerSettings.Where(x => x.InstanceId == Instance.Id).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
var hostModel = await DatabaseContext
.DreamMakerSettings
.AsQueryable()
.Where(x => x.InstanceId == Instance.Id)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
if (hostModel == null)
return StatusCode((int)HttpStatusCode.Gone);
@@ -196,12 +196,12 @@ namespace Tgstation.Server.Host.Controllers
using (systemIdentity)
{
// Get the user from the database
IQueryable<User> query;
IQueryable<User> query = DatabaseContext.Users.AsQueryable();
string canonicalName = Models.User.CanonicalizeName(ApiHeaders.Username);
if (systemIdentity == null)
query = DatabaseContext.Users.Where(x => x.CanonicalName == canonicalName);
query = query.Where(x => x.CanonicalName == canonicalName);
else
query = DatabaseContext.Users.Where(x => x.CanonicalName == canonicalName || x.SystemIdentifier == systemIdentity.Uid);
query = query.Where(x => x.CanonicalName == canonicalName || x.SystemIdentifier == systemIdentity.Uid);
var users = await query.Select(x => new User
{
Id = x.Id,
@@ -174,18 +174,25 @@ namespace Tgstation.Server.Host.Controllers
var newCancellationToken = cts.Token;
try
{
await DatabaseContext.Instances.ForEachAsync(
otherInstance =>
await DatabaseContext
.Instances
.AsQueryable()
.Select(x => new Models.Instance
{
if (++countOfOtherInstances >= generalConfiguration.InstanceLimit)
earlyOut ??= Conflict(new ErrorMessage(ErrorCode.InstanceLimitReached));
else if (InstanceIsChildOf(otherInstance.Path))
earlyOut ??= Conflict(new ErrorMessage(ErrorCode.InstanceAtConflictingPath));
Path = x.Path
})
.ForEachAsync(
otherInstance =>
{
if (++countOfOtherInstances >= generalConfiguration.InstanceLimit)
earlyOut ??= Conflict(new ErrorMessage(ErrorCode.InstanceLimitReached));
else if (InstanceIsChildOf(otherInstance.Path))
earlyOut ??= Conflict(new ErrorMessage(ErrorCode.InstanceAtConflictingPath));
if (earlyOut != null && !newCancellationToken.IsCancellationRequested)
cts.Cancel();
},
newCancellationToken)
if (earlyOut != null && !newCancellationToken.IsCancellationRequested)
cts.Cancel();
},
newCancellationToken)
.ConfigureAwait(false);
}
catch (OperationCanceledException)
@@ -312,7 +319,10 @@ namespace Tgstation.Server.Host.Controllers
[ProducesResponseType(410)]
public async Task<IActionResult> Delete(long id, CancellationToken cancellationToken)
{
var originalModel = await DatabaseContext.Instances.Where(x => x.Id == id)
var originalModel = await DatabaseContext
.Instances
.AsQueryable()
.Where(x => x.Id == id)
.Include(x => x.WatchdogReattachInformation)
.Include(x => x.WatchdogReattachInformation.Alpha)
.Include(x => x.WatchdogReattachInformation.Bravo)
@@ -358,7 +368,10 @@ namespace Tgstation.Server.Host.Controllers
if (model == null)
throw new ArgumentNullException(nameof(model));
IQueryable<Models.Instance> InstanceQuery() => DatabaseContext.Instances.Where(x => x.Id == model.Id);
IQueryable<Models.Instance> InstanceQuery() => DatabaseContext
.Instances
.AsQueryable()
.Where(x => x.Id == model.Id);
var moveJob = await InstanceQuery()
.SelectMany(x => x.Jobs).
@@ -435,6 +448,7 @@ namespace Tgstation.Server.Host.Controllers
{
var countOfExistingChatBots = await DatabaseContext
.ChatBots
.AsQueryable()
.Where(x => x.InstanceId == originalModel.Id)
.CountAsync(cancellationToken)
.ConfigureAwait(false);
@@ -582,7 +596,10 @@ namespace Tgstation.Server.Host.Controllers
var cantList = !AuthenticationContext.User.InstanceManagerRights.Value.HasFlag(InstanceManagerRights.List);
IQueryable<Models.Instance> QueryForUser()
{
var query = DatabaseContext.Instances.Where(x => x.Id == id);
var query = DatabaseContext
.Instances
.AsQueryable()
.Where(x => x.Id == id);
if (cantList)
query = query.Include(x => x.InstanceUsers);
@@ -101,7 +101,14 @@ namespace Tgstation.Server.Host.Controllers
if (earlyOut != null)
return earlyOut;
var originalUser = await DatabaseContext.Instances.Where(x => x.Id == Instance.Id).SelectMany(x => x.InstanceUsers).Where(x => x.UserId == model.UserId).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
var originalUser = await DatabaseContext
.Instances
.AsQueryable()
.Where(x => x.Id == Instance.Id)
.SelectMany(x => x.InstanceUsers)
.Where(x => x.UserId == model.UserId)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
if (originalUser == null)
return StatusCode((int)HttpStatusCode.Gone);
@@ -141,7 +148,13 @@ namespace Tgstation.Server.Host.Controllers
[ProducesResponseType(typeof(IEnumerable<Api.Models.InstanceUser>), 200)]
public async Task<IActionResult> List(CancellationToken cancellationToken)
{
var users = await DatabaseContext.Instances.Where(x => x.Id == Instance.Id).SelectMany(x => x.InstanceUsers).ToListAsync(cancellationToken).ConfigureAwait(false);
var users = await DatabaseContext
.Instances
.AsQueryable()
.Where(x => x.Id == Instance.Id)
.SelectMany(x => x.InstanceUsers)
.ToListAsync(cancellationToken)
.ConfigureAwait(false);
return Json(users.Select(x => x.ToApi()));
}
@@ -160,7 +173,14 @@ namespace Tgstation.Server.Host.Controllers
public async Task<IActionResult> GetId(long id, CancellationToken cancellationToken)
{
// this functions as userId
var user = await DatabaseContext.Instances.Where(x => x.Id == Instance.Id).SelectMany(x => x.InstanceUsers).Where(x => x.UserId == id).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
var user = await DatabaseContext
.Instances
.AsQueryable()
.Where(x => x.Id == Instance.Id)
.SelectMany(x => x.InstanceUsers)
.Where(x => x.UserId == id)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
if (user == default)
return StatusCode((int)HttpStatusCode.Gone);
return Json(user.ToApi());
@@ -178,7 +198,14 @@ namespace Tgstation.Server.Host.Controllers
[ProducesResponseType(204)]
public async Task<IActionResult> Delete(long id, CancellationToken cancellationToken)
{
await DatabaseContext.Instances.Where(x => x.Id == Instance.Id).SelectMany(x => x.InstanceUsers).Where(x => x.UserId == id).DeleteAsync(cancellationToken).ConfigureAwait(false);
await DatabaseContext
.Instances
.AsQueryable()
.Where(x => x.Id == Instance.Id)
.SelectMany(x => x.InstanceUsers)
.Where(x => x.UserId == id)
.DeleteAsync(cancellationToken)
.ConfigureAwait(false);
return NoContent();
}
}
@@ -49,7 +49,13 @@ namespace Tgstation.Server.Host.Controllers
[ProducesResponseType(typeof(IEnumerable<Api.Models.Job>), 200)]
public async Task<IActionResult> Read(CancellationToken cancellationToken)
{
var result = await DatabaseContext.Jobs.Where(x => x.Instance.Id == Instance.Id && !x.StoppedAt.HasValue).OrderByDescending(x => x.StartedAt).ToListAsync(cancellationToken).ConfigureAwait(false);
var result = await DatabaseContext
.Jobs
.AsQueryable()
.Where(x => x.Instance.Id == Instance.Id && !x.StoppedAt.HasValue)
.OrderByDescending(x => x.StartedAt)
.ToListAsync(cancellationToken)
.ConfigureAwait(false);
return Json(result.Select(x => x.ToApi()));
}
@@ -65,10 +71,17 @@ namespace Tgstation.Server.Host.Controllers
public async Task<IActionResult> List(CancellationToken cancellationToken)
{
// you KNOW this will need pagination eventually right?
var jobs = await DatabaseContext.Jobs.Where(x => x.Instance.Id == Instance.Id).OrderByDescending(x => x.StartedAt).Select(x => new Api.Models.EntityId
{
Id = x.Id
}).ToListAsync(cancellationToken).ConfigureAwait(false);
var jobs = await DatabaseContext
.Jobs
.AsQueryable()
.Where(x => x.Instance.Id == Instance.Id)
.OrderByDescending(x => x.StartedAt)
.Select(x => new Api.Models.EntityId
{
Id = x.Id
})
.ToListAsync(cancellationToken)
.ConfigureAwait(false);
return Json(jobs);
}
@@ -89,7 +102,12 @@ namespace Tgstation.Server.Host.Controllers
public async Task<IActionResult> Delete(long id, CancellationToken cancellationToken)
{
// don't care if an instance post or not at this point
var job = await DatabaseContext.Jobs.Where(x => x.Id == id && x.Instance.Id == Instance.Id).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
var job = await DatabaseContext
.Jobs
.AsQueryable()
.Where(x => x.Id == id && x.Instance.Id == Instance.Id)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
if (job == default(Job))
return NotFound();
@@ -119,6 +137,7 @@ namespace Tgstation.Server.Host.Controllers
{
var job = await DatabaseContext
.Jobs
.AsQueryable()
.Where(x => x.Id == id && x.Instance.Id == Instance.Id)
.Include(x => x.StartedBy)
.FirstOrDefaultAsync(cancellationToken)
@@ -156,7 +156,12 @@ namespace Tgstation.Server.Host.Controllers
if (model.AccessUser == null ^ model.AccessToken == null)
return BadRequest(ErrorCode.RepoMismatchUserAndAccessToken);
var currentModel = await DatabaseContext.RepositorySettings.Where(x => x.InstanceId == Instance.Id).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
var currentModel = await DatabaseContext
.RepositorySettings
.AsQueryable()
.Where(x => x.InstanceId == Instance.Id)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
if (currentModel == default)
return StatusCode((int)HttpStatusCode.Gone);
@@ -236,7 +241,12 @@ namespace Tgstation.Server.Host.Controllers
[ProducesResponseType(410)]
public async Task<IActionResult> Delete(CancellationToken cancellationToken)
{
var currentModel = await DatabaseContext.RepositorySettings.Where(x => x.InstanceId == Instance.Id).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
var currentModel = await DatabaseContext
.RepositorySettings
.AsQueryable()
.Where(x => x.InstanceId == Instance.Id)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
if (currentModel == default)
return StatusCode((int)HttpStatusCode.Gone);
@@ -275,7 +285,12 @@ namespace Tgstation.Server.Host.Controllers
[ProducesResponseType(410)]
public async Task<IActionResult> Read(CancellationToken cancellationToken)
{
var currentModel = await DatabaseContext.RepositorySettings.Where(x => x.InstanceId == Instance.Id).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
var currentModel = await DatabaseContext
.RepositorySettings
.AsQueryable()
.Where(x => x.InstanceId == Instance.Id)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
if (currentModel == default)
return StatusCode((int)HttpStatusCode.Gone, new ErrorMessage(ErrorCode.RepoMissing));
@@ -346,6 +361,7 @@ namespace Tgstation.Server.Host.Controllers
var currentModel = await DatabaseContext
.RepositorySettings
.AsQueryable()
.Where(x => x.InstanceId == Instance.Id)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
@@ -654,6 +670,7 @@ namespace Tgstation.Server.Host.Controllers
await databaseContextFactory.UseContext(
async databaseContext =>
dbPull = await databaseContext.RevisionInformations
.AsQueryable()
.Where(x => x.Instance.Id == Instance.Id
&& x.OriginCommitSha == lastRevisionInfo.OriginCommitSha
&& x.ActiveTestMerges.Count <= model.NewTestMerges.Count
@@ -192,7 +192,10 @@ namespace Tgstation.Server.Host.Controllers
var originalUser = passwordEditOnly
? AuthenticationContext.User
: await DatabaseContext.Users.Where(x => x.Id == model.Id)
: await DatabaseContext
.Users
.AsQueryable()
.Where(x => x.Id == model.Id)
.Include(x => x.CreatedBy)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
@@ -301,6 +304,7 @@ namespace Tgstation.Server.Host.Controllers
return Forbid();
var user = await DatabaseContext.Users
.AsQueryable()
.Where(x => x.Id == id)
.Include(x => x.CreatedBy)
.FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
@@ -5,7 +5,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
namespace Tgstation.Server.Host.Database
{
@@ -48,9 +47,7 @@ namespace Tgstation.Server.Host.Database
public void Attach(TModel model) => dbSet.Attach(model);
/// <inheritdoc />
public Task ForEachAsync(Action<TModel> action, CancellationToken cancellationToken) => dbSet
.AsAsyncEnumerable()
.ForEachAsync(action, cancellationToken);
public IAsyncEnumerator<TModel> GetAsyncEnumerator(CancellationToken cancellationToken = default) => dbSet.AsAsyncEnumerable().GetAsyncEnumerator();
/// <inheritdoc />
public IEnumerator<TModel> GetEnumerator() => dbSet.AsQueryable().GetEnumerator();
@@ -61,9 +58,6 @@ namespace Tgstation.Server.Host.Database
/// <inheritdoc />
public void RemoveRange(IEnumerable<TModel> models) => dbSet.RemoveRange(models);
/// <inheritdoc />
public Task<List<TModel>> ToListAsync(CancellationToken cancellationToken) => dbSet.AsQueryable().ToListAsync(cancellationToken);
/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator() => dbSet.AsQueryable().GetEnumerator();
}
@@ -76,7 +76,11 @@ namespace Tgstation.Server.Host.Database
if (platformIdentifier.IsWindows)
{
// normalize backslashes to forward slashes
var allInstances = await databaseContext.Instances.ToListAsync(cancellationToken).ConfigureAwait(false);
var allInstances = await databaseContext
.Instances
.AsQueryable()
.ToListAsync(cancellationToken)
.ConfigureAwait(false);
foreach (var instance in allInstances)
instance.Path = instance.Path.Replace('\\', '/');
}
@@ -107,6 +111,7 @@ namespace Tgstation.Server.Host.Database
{
var admin = await databaseContext
.Users
.AsQueryable()
.Where(x => x.CanonicalName == User.CanonicalizeName(Api.Models.User.AdminName))
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
@@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Tgstation.Server.Host.Database
{
@@ -10,7 +7,7 @@ namespace Tgstation.Server.Host.Database
/// Represents a database table.
/// </summary>
/// <typeparam name="TModel">The type of model.</typeparam>
public interface IDatabaseCollection<TModel> : IQueryable<TModel>
public interface IDatabaseCollection<TModel> : IQueryable<TModel>, IAsyncEnumerable<TModel>
{
/// <summary>
/// An <see cref="IEnumerable{T}"/> of <typeparamref name="TModel"/>s prioritizing in the working set.
@@ -46,20 +43,5 @@ namespace Tgstation.Server.Host.Database
/// </summary>
/// <param name="models">An <see cref="IEnumerable{T}"/> of <typeparamref name="TModel"/>s to remove.</param>
void RemoveRange(IEnumerable<TModel> models);
/// <summary>
/// Asyncronously run a given <paramref name="action"/> on the <see cref="IDatabaseCollection{TModel}"/>.
/// </summary>
/// <param name="action">The <see cref="Action{T}"/> to run.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
Task ForEachAsync(Action<TModel> action, CancellationToken cancellationToken);
/// <summary>
/// Retrieve all the <typeparamref name="TModel"/>s in the table.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="Task{TResult}"/> resulting in a <see cref="List{T}"/> of all <typeparamref name="TModel"/> in the table.</returns>
Task<List<TModel>> ToListAsync(CancellationToken cancellationToken);
}
}
@@ -41,7 +41,7 @@ namespace Tgstation.Server.Host.Database
throw new NotImplementedException("PostgresSQL implementation is not complete yet!");
if (DatabaseType != DatabaseType.PostgresSql)
throw new InvalidOperationException("Invalid DatabaseType for SqliteDatabaseContext!");
throw new InvalidOperationException("Invalid DatabaseType for PostgresSqlDatabaseContext!");
}
}
}
@@ -30,6 +30,7 @@ namespace Tgstation.Server.Host.Extensions
return databaseContext
.CompileJobs
.AsQueryable()
.Where(x => x.Job.Instance.Id == instance.Id)
.OrderByDescending(x => x.Job.StoppedAt)
.FirstOrDefaultAsync(cancellationToken);
+7 -1
View File
@@ -186,7 +186,13 @@ namespace Tgstation.Server.Host.Jobs
await databaseContextFactory.UseContext(async databaseContext =>
{
// mark all jobs as cancelled
var badJobs = await databaseContext.Jobs.Where(y => !y.StoppedAt.HasValue).Select(y => y.Id).ToListAsync(cancellationToken).ConfigureAwait(false);
var badJobs = await databaseContext
.Jobs
.AsQueryable()
.Where(y => !y.StoppedAt.HasValue)
.Select(y => y.Id)
.ToListAsync(cancellationToken)
.ConfigureAwait(false);
if (badJobs.Count > 0)
{
logger.LogTrace("Cleaning {0} unfinished jobs...", badJobs.Count);
@@ -55,7 +55,10 @@ namespace Tgstation.Server.Host.Security
if (CurrentAuthenticationContext != null)
throw new InvalidOperationException("Authentication context has already been loaded");
var user = await databaseContext.Users.Where(x => x.Id == userId)
var user = await databaseContext
.Users
.AsQueryable()
.Where(x => x.Id == userId)
.Include(x => x.CreatedBy)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
@@ -85,6 +88,7 @@ namespace Tgstation.Server.Host.Security
if (instanceId.HasValue)
{
instanceUser = await databaseContext.InstanceUsers
.AsQueryable()
.Where(x => x.UserId == userId && x.InstanceId == instanceId && x.Instance.Online.Value)
.Include(x => x.Instance)
.FirstOrDefaultAsync(cancellationToken)
@@ -13,7 +13,7 @@ namespace Tgstation.Server.Host.Core.Tests
{
var delayer = new AsyncDelayer();
var startDelay = delayer.Delay(TimeSpan.FromSeconds(1), default);
var checkDelay = Task.Delay(TimeSpan.FromSeconds(1) - TimeSpan.FromMilliseconds(10), default);
var checkDelay = Task.Delay(TimeSpan.FromSeconds(1) - TimeSpan.FromMilliseconds(100), default);
await startDelay.ConfigureAwait(false);
Assert.IsTrue(checkDelay.IsCompleted);
}
@@ -22,11 +22,9 @@ namespace Tgstation.Server.Host.Core.Tests
public async Task TestCancel()
{
var delayer = new AsyncDelayer();
using (var cts = new CancellationTokenSource())
{
cts.Cancel();
await Assert.ThrowsExceptionAsync<TaskCanceledException>(() => delayer.Delay(TimeSpan.FromSeconds(1), cts.Token)).ConfigureAwait(false);
}
using var cts = new CancellationTokenSource();
cts.Cancel();
await Assert.ThrowsExceptionAsync<TaskCanceledException>(() => delayer.Delay(TimeSpan.FromSeconds(1), cts.Token)).ConfigureAwait(false);
}
}
}