diff --git a/build/Version.props b/build/Version.props index 5bef0c936b..07bb599fbd 100644 --- a/build/Version.props +++ b/build/Version.props @@ -2,7 +2,7 @@ - 4.4.0 + 4.4.1 2.0.0 7.0.1 8.0.0 diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs index 8754f58c19..1c63870f1b 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs @@ -248,6 +248,7 @@ namespace Tgstation.Server.Host.Components.Deployment if (!dmbExistsAtRoot) { + logger.LogTrace("Didn't find .dmb at game directory root, checking A/B dirs..."); var primaryCheckTask = ioManager.FileExists( ioManager.ConcatPath( newProvider.Directory, diff --git a/src/Tgstation.Server.Host/Components/InstanceManager.cs b/src/Tgstation.Server.Host/Components/InstanceManager.cs index b6909e91e2..46f3ca2bd6 100644 --- a/src/Tgstation.Server.Host/Components/InstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/InstanceManager.cs @@ -285,7 +285,7 @@ namespace Tgstation.Server.Host.Components var factoryStartup = instanceFactory.StartAsync(cancellationToken); await databaseSeeder.Initialize(databaseContext, cancellationToken).ConfigureAwait(false); await jobManager.StartAsync(cancellationToken).ConfigureAwait(false); - var dbInstances = databaseContext + var dbInstances = await databaseContext .Instances .AsQueryable() .Where(x => x.Online.Value) @@ -293,10 +293,22 @@ namespace Tgstation.Server.Host.Components .Include(x => x.ChatSettings) .ThenInclude(x => x.Channels) .Include(x => x.DreamDaemonSettings) - .ToAsyncEnumerable(); - var tasks = new List(); + .ToListAsync(cancellationToken) + .ConfigureAwait(false); await factoryStartup.ConfigureAwait(false); - await dbInstances.ForEachAsync(metadata => tasks.Add(metadata.Online.Value ? OnlineInstance(metadata, cancellationToken) : Task.CompletedTask), cancellationToken).ConfigureAwait(false); + var tasks = dbInstances.Select( + async metadata => + { + try + { + await OnlineInstance(metadata, cancellationToken).ConfigureAwait(false); + } + catch (Exception ex) + { + logger.LogError("Failed to online instance {0}! Exception: {0}", ex); + } + }) + .ToList(); await Task.WhenAll(tasks).ConfigureAwait(false); logger.LogInformation("Server ready!"); readyTcs.SetResult(null); diff --git a/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs b/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs index 30da71fa8c..eef018159e 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs @@ -153,9 +153,16 @@ namespace Tgstation.Server.Host.Components.Session return null; } + var dmb = await dmbFactory.FromCompileJob(result.CompileJob, cancellationToken).ConfigureAwait(false); + if (dmb == null) + { + logger.LogError("Unable to reattach! Could not load .dmb!"); + return null; + } + var info = new ReattachInformation( result, - await dmbFactory.FromCompileJob(result.CompileJob, cancellationToken).ConfigureAwait(false), + dmb, topicTimeout.Value); logger.LogDebug("Reattach information loaded: {0}", info); diff --git a/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdogFactory.cs b/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdogFactory.cs index f075244a10..30a8169e97 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdogFactory.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdogFactory.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using System; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Chat; using Tgstation.Server.Host.Components.Deployment; @@ -73,6 +74,6 @@ namespace Tgstation.Server.Host.Components.Watchdog LoggerFactory.CreateLogger(), settings, instance, - settings.AutoStart.Value); + settings.AutoStart ?? throw new ArgumentNullException(nameof(settings))); } } diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs index fccf313fc4..dbf3fe82e9 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs @@ -97,6 +97,6 @@ namespace Tgstation.Server.Host.Components.Watchdog LoggerFactory.CreateLogger(), settings, instance, - settings.AutoStart.Value); + settings.AutoStart ?? throw new ArgumentNullException(nameof(settings))); } } diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdogFactory.cs b/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdogFactory.cs index 54f5047cdb..1e52e7ecad 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdogFactory.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdogFactory.cs @@ -80,6 +80,6 @@ namespace Tgstation.Server.Host.Components.Watchdog LoggerFactory.CreateLogger(), settings, instance, - settings.AutoStart.Value); + settings.AutoStart ?? throw new ArgumentNullException(nameof(settings))); } } diff --git a/src/Tgstation.Server.Host/Controllers/InstanceController.cs b/src/Tgstation.Server.Host/Controllers/InstanceController.cs index bf274fe9f3..21275a96f3 100644 --- a/src/Tgstation.Server.Host/Controllers/InstanceController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstanceController.cs @@ -393,6 +393,9 @@ namespace Tgstation.Server.Host.Controllers if (originalModel == default(Models.Instance)) return Gone(); + if (ValidateInstanceOnlineStatus(originalModel)) + await DatabaseContext.Save(cancellationToken).ConfigureAwait(false); + var userRights = (InstanceManagerRights)AuthenticationContext.GetRight(RightsType.InstanceManager); bool CheckModified(Expression> expression, InstanceManagerRights requiredRight) { @@ -556,6 +559,13 @@ namespace Tgstation.Server.Host.Controllers .ToListAsync(cancellationToken) .ConfigureAwait(false); + var needsUpdate = false; + foreach (var instance in instances) + needsUpdate |= ValidateInstanceOnlineStatus(instance); + + if (needsUpdate) + await DatabaseContext.Save(cancellationToken).ConfigureAwait(false); + var apis = instances.Select(x => x.ToApi()); foreach(var I in moveJobs) apis.Where(x => x.Id == I.Instance.Id).First().MoveJob = I.ToApi(); // if this .First() fails i will personally murder kevinz000 because I just know he is somehow responsible @@ -594,6 +604,9 @@ namespace Tgstation.Server.Host.Controllers if (instance == null) return Gone(); + if (ValidateInstanceOnlineStatus(instance)) + await DatabaseContext.Save(cancellationToken).ConfigureAwait(false); + if (cantList && !instance.InstanceUsers.Any(instanceUser => instanceUser.UserId == AuthenticationContext.User.Id && (instanceUser.ByondRights != ByondRights.None || instanceUser.ChatBotRights != ChatBotRights.None || @@ -651,5 +664,39 @@ namespace Tgstation.Server.Host.Controllers return NoContent(); } + + /// + /// Corrects discrepencies between the status of s in the database vs the service. + /// + /// The to check. + /// if an unsaved DB update was made, otherwise. + bool ValidateInstanceOnlineStatus(Models.Instance metadata) + { + bool online; + try + { + instanceManager.GetInstance(metadata); + online = true; + } + catch (InvalidOperationException ex) + { + Logger.LogDebug("Expected instance offline exception: {0}", ex); + online = false; + } + + if (metadata.Online.Value == online) + return false; + + const string OfflineWord = "offline"; + const string OnlineWord = "online"; + + Logger.LogWarning( + "Instance {0} is says it's {1} in the database, but it is actually {2} in the service. Updating the database to reflect this...", + online ? OfflineWord : OnlineWord, + online ? OnlineWord : OfflineWord); + + metadata.Online = online; + return true; + } } } diff --git a/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs b/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs index 5b2fbde5ba..8982ce2205 100644 --- a/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs +++ b/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs @@ -133,32 +133,35 @@ namespace Tgstation.Server.Host.Database instance.Path = instance.Path.Replace('\\', '/'); } - var ids = await databaseContext - .DreamDaemonSettings - .AsQueryable() - .Where(x => x.TopicRequestTimeout == 0) - .Select(x => x.Id) - .ToListAsync(cancellationToken) - .ConfigureAwait(false); - - var rowsUpdated = ids.Count; - foreach (var id in ids) + if (generalConfiguration.ByondTopicTimeout != 0) { - var newDDSettings = new DreamDaemonSettings + var ids = await databaseContext + .DreamDaemonSettings + .AsQueryable() + .Where(x => x.TopicRequestTimeout == 0) + .Select(x => x.Id) + .ToListAsync(cancellationToken) + .ConfigureAwait(false); + + var rowsUpdated = ids.Count; + foreach (var id in ids) { - Id = id - }; + var newDDSettings = new DreamDaemonSettings + { + Id = id + }; - databaseContext.DreamDaemonSettings.Attach(newDDSettings); - newDDSettings.TopicRequestTimeout = generalConfiguration.ByondTopicTimeout; + databaseContext.DreamDaemonSettings.Attach(newDDSettings); + newDDSettings.TopicRequestTimeout = generalConfiguration.ByondTopicTimeout; + } + + if (rowsUpdated > 0) + logger.LogInformation( + "Updated {0} instances to use database backed BYOND topic timeouts from configuration setting of {1}", + rowsUpdated, + generalConfiguration.ByondTopicTimeout); } - if (rowsUpdated > 0) - logger.LogInformation( - "Updated {0} instances to use database backed BYOND topic timeouts from configuration setting of {1}", - rowsUpdated, - generalConfiguration.ByondTopicTimeout); - await databaseContext.Save(cancellationToken).ConfigureAwait(false); } diff --git a/src/Tgstation.Server.Host/Server.cs b/src/Tgstation.Server.Host/Server.cs index 45b37f2c74..2d5dc1bd80 100644 --- a/src/Tgstation.Server.Host/Server.cs +++ b/src/Tgstation.Server.Host/Server.cs @@ -286,7 +286,7 @@ namespace Tgstation.Server.Host } RestartRequested = true; - propagatedException = exception; + propagatedException ??= exception; } if (exception == null)