diff --git a/src/Tgstation.Server.Host/Components/IInstanceCoreProvider.cs b/src/Tgstation.Server.Host/Components/IInstanceCoreProvider.cs index 7e6b0b8dc5..ab1db54e91 100644 --- a/src/Tgstation.Server.Host/Components/IInstanceCoreProvider.cs +++ b/src/Tgstation.Server.Host/Components/IInstanceCoreProvider.cs @@ -10,6 +10,6 @@ /// /// The to get the for. /// The if it is online, otherwise. - IInstanceCore GetInstance(Models.Instance instance); + IInstanceCore? GetInstance(Models.Instance instance); } } diff --git a/src/Tgstation.Server.Host/Components/IInstanceManager.cs b/src/Tgstation.Server.Host/Components/IInstanceManager.cs index 3174686efe..516b2a8f30 100644 --- a/src/Tgstation.Server.Host/Components/IInstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/IInstanceManager.cs @@ -19,6 +19,6 @@ namespace Tgstation.Server.Host.Components /// /// The of the desired . /// The associated with the given if it is online, otherwise. - IInstanceReference GetInstanceReference(Api.Models.Instance metadata); + IInstanceReference? GetInstanceReference(Api.Models.Instance metadata); } } diff --git a/src/Tgstation.Server.Host/Components/InstanceManager.cs b/src/Tgstation.Server.Host/Components/InstanceManager.cs index 50da066c52..eeadde0c30 100644 --- a/src/Tgstation.Server.Host/Components/InstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/InstanceManager.cs @@ -21,13 +21,12 @@ using Tgstation.Server.Host.Database; using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; +using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Swarm; using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components { /// @@ -117,7 +116,7 @@ namespace Tgstation.Server.Host.Components readonly Dictionary bridgeHandlers; /// - /// used to guard calls to and . + /// used to guard calls to and . /// readonly SemaphoreSlim instanceStateChangeSemaphore; @@ -149,12 +148,12 @@ namespace Tgstation.Server.Host.Components /// /// The original of . /// - readonly string originalConsoleTitle; + readonly string? originalConsoleTitle; /// /// The returned by . /// - Task startupTask; + Task? startupTask; /// /// If the has been 'd. @@ -243,13 +242,13 @@ namespace Tgstation.Server.Host.Components } /// - public IInstanceReference GetInstanceReference(Api.Models.Instance metadata) + public IInstanceReference? GetInstanceReference(Api.Models.Instance metadata) { ArgumentNullException.ThrowIfNull(metadata); lock (instances) { - if (!instances.TryGetValue(metadata.Id.Value, out var instance)) + if (!instances.TryGetValue(metadata.Require(x => x.Id), out var instance)) return null; return instance.AddReference(); @@ -265,7 +264,7 @@ namespace Tgstation.Server.Host.Components using var instanceReferenceCheck = GetInstanceReference(instance); if (instanceReferenceCheck != null) throw new InvalidOperationException("Cannot move an online instance!"); - var newPath = instance.Path; + var newPath = instance.Path!; try { await ioManager.MoveDirectory(oldPath, newPath, cancellationToken); @@ -328,22 +327,23 @@ namespace Tgstation.Server.Host.Components } /// - public async ValueTask OfflineInstance(Models.Instance metadata, Models.User user, CancellationToken cancellationToken) + public async ValueTask OfflineInstance(Models.Instance metadata, User user, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(metadata); using (await SemaphoreSlimContext.Lock(instanceStateChangeSemaphore, cancellationToken)) { - ReferenceCountingContainer container; + ReferenceCountingContainer? container; + var instanceId = metadata.Require(x => x.Id); lock (instances) { - if (!instances.TryGetValue(metadata.Id.Value, out container)) + if (!instances.TryGetValue(instanceId, out container)) { logger.LogDebug("Not offlining removed instance {instanceId}", metadata.Id); return; } - instances.Remove(metadata.Id.Value); + instances.Remove(instanceId); } logger.LogInformation("Offlining instance ID {instanceId}", metadata.Id); @@ -353,15 +353,15 @@ namespace Tgstation.Server.Host.Components await container.OnZeroReferences.WaitAsync(cancellationToken); // we are the one responsible for cancelling his jobs - ValueTask groupedTask = default; + ValueTask groupedTask = default; await databaseContextFactory.UseContext( async db => { var jobs = await db .Jobs .AsQueryable() - .Where(x => x.Instance.Id == metadata.Id && !x.StoppedAt.HasValue) - .Select(x => new Models.Job(x.Id.Value)) + .Where(x => x.Instance!.Id == metadata.Id && !x.StoppedAt.HasValue) + .Select(x => new Job(x.Id!.Value)) .ToListAsync(cancellationToken); groupedTask = ValueTaskExtensions.WhenAll( @@ -375,7 +375,7 @@ namespace Tgstation.Server.Host.Components { // not too late to change your mind lock (instances) - instances.Add(metadata.Id.Value, container); + instances.Add(instanceId, container); throw; } @@ -397,9 +397,10 @@ namespace Tgstation.Server.Host.Components { ArgumentNullException.ThrowIfNull(metadata); + var instanceId = metadata.Require(x => x.Id); using var lockContext = await SemaphoreSlimContext.Lock(instanceStateChangeSemaphore, cancellationToken); lock (instances) - if (instances.ContainsKey(metadata.Id.Value)) + if (instances.ContainsKey(instanceId)) { logger.LogDebug("Aborting instance creation due to it seemingly already being online"); return; @@ -415,7 +416,7 @@ namespace Tgstation.Server.Host.Components { lock (instances) instances.Add( - metadata.Id.Value, + instanceId, new ReferenceCountingContainer(instance)); } catch (Exception ex) @@ -457,6 +458,12 @@ namespace Tgstation.Server.Host.Components using (cancellationToken.Register(shutdownCancellationTokenSource.Cancel)) try { + if (startupTask == null) + { + logger.LogWarning("InstanceManager was never started!"); + return; + } + logger.LogDebug("Stopping instance manager..."); if (!startupTask.IsCompleted) @@ -499,11 +506,11 @@ namespace Tgstation.Server.Host.Components } /// - public async ValueTask ProcessBridgeRequest(BridgeParameters parameters, CancellationToken cancellationToken) + public async ValueTask ProcessBridgeRequest(BridgeParameters parameters, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(parameters); - IBridgeHandler bridgeHandler = null; + IBridgeHandler? bridgeHandler = null; for (var i = 0; bridgeHandler == null && i < 30; ++i) { // There's a miniscule time period where we could potentially receive a bridge request and not have the registration ready when we launch DD @@ -550,11 +557,11 @@ namespace Tgstation.Server.Host.Components } /// - public IInstanceCore GetInstance(Models.Instance metadata) + public IInstanceCore? GetInstance(Models.Instance metadata) { lock (instances) { - instances.TryGetValue(metadata.Id.Value, out var container); + instances.TryGetValue(metadata.Require(x => x.Id), out var container); return container?.Instance; } } @@ -578,13 +585,13 @@ namespace Tgstation.Server.Host.Components await InitializeSwarm(cancellationToken); - List dbInstances = null; + List? dbInstances = null; async ValueTask EnumerateInstances(IDatabaseContext databaseContext) => dbInstances = await databaseContext .Instances .AsQueryable() - .Where(x => x.Online.Value && x.SwarmIdentifer == swarmConfiguration.Identifier) + .Where(x => x.Online!.Value && x.SwarmIdentifer == swarmConfiguration.Identifier) .Include(x => x.RepositorySettings) .Include(x => x.ChatSettings) .ThenInclude(x => x.Channels) @@ -598,7 +605,7 @@ namespace Tgstation.Server.Host.Components await Task.WhenAll(instanceEnumeration.AsTask(), factoryStartup, jobManagerStartup); - var instanceOnliningTasks = dbInstances.Select( + var instanceOnliningTasks = dbInstances!.Select( async metadata => { try diff --git a/src/Tgstation.Server.Host/Controllers/ComponentInterfacingController.cs b/src/Tgstation.Server.Host/Controllers/ComponentInterfacingController.cs index 34988a5812..f04e620d06 100644 --- a/src/Tgstation.Server.Host/Controllers/ComponentInterfacingController.cs +++ b/src/Tgstation.Server.Host/Controllers/ComponentInterfacingController.cs @@ -129,7 +129,7 @@ namespace Tgstation.Server.Host.Controllers instance ??= Instance ?? throw new InvalidOperationException("ComponentInterfacingController has no Instance!"); using var instanceReference = instanceManager.GetInstanceReference(instance); - using (LogContext.PushProperty(SerilogContextHelper.InstanceReferenceContextProperty, instanceReference.Uid)) + using (LogContext.PushProperty(SerilogContextHelper.InstanceReferenceContextProperty, instanceReference?.Uid)) { if (instanceReference == null) return Conflict(new ErrorMessageResponse(ErrorCode.InstanceOffline)); diff --git a/src/Tgstation.Server.Host/Jobs/JobService.cs b/src/Tgstation.Server.Host/Jobs/JobService.cs index ea2782a821..8db21d3068 100644 --- a/src/Tgstation.Server.Host/Jobs/JobService.cs +++ b/src/Tgstation.Server.Host/Jobs/JobService.cs @@ -460,8 +460,10 @@ namespace Tgstation.Server.Host.Jobs QueueHubUpdate(job.ToApi(), false); logger.LogTrace("Starting job..."); + var instanceCore = instanceCoreProvider.GetInstance(job.Instance!) + ?? throw new JobException("Could not retrieve instance core for job!"); await operation( - instanceCoreProvider.GetInstance(job.Instance!), + instanceCore, databaseContextFactory, job, new JobProgressReporter(