chore: attempts to debug boot plugin load task deadlock

This commit is contained in:
goat 2022-08-16 23:26:01 +02:00
parent bcc30e8731
commit f0a5dcf0e9
No known key found for this signature in database
GPG key ID: 49E2AA8C6A76498B

View file

@ -429,84 +429,133 @@ internal partial class PluginManager : IDisposable, IServiceType
} }
} }
void LoadPluginsSync(string logPrefix, IEnumerable<PluginDef> pluginDefsList) async Task LoadPluginsSync(string logPrefix, IEnumerable<PluginDef> pluginDefsList)
{ {
Log.Information("============= LoadPluginsSync START =============");
foreach (var pluginDef in pluginDefsList) foreach (var pluginDef in pluginDefsList)
LoadPluginOnBoot(logPrefix, pluginDef).Wait(); await LoadPluginOnBoot(logPrefix, pluginDef);
Log.Information("============= LoadPluginsSync END =============");
} }
Task LoadPluginsAsync(string logPrefix, IEnumerable<PluginDef> pluginDefsList) Task LoadPluginsAsync(string logPrefix, IEnumerable<PluginDef> pluginDefsList)
{ {
Log.Information("============= LoadPluginsAsync START =============");
return Task.WhenAll( return Task.WhenAll(
pluginDefsList pluginDefsList
.Select(pluginDef => Task.Run(Timings.AttachTimingHandle( .Select(pluginDef => Task.Run(Timings.AttachTimingHandle(
() => LoadPluginOnBoot(logPrefix, pluginDef)))) () => LoadPluginOnBoot(logPrefix, pluginDef))))
.ToArray()); .ToArray()).ContinueWith(t => Log.Information($"============= LoadPluginsAsync END {t.IsCompletedSuccessfully} ============="));
} }
var syncPlugins = pluginDefs.Where(def => def.Manifest?.LoadSync == true).ToList(); var syncPlugins = pluginDefs.Where(def => def.Manifest?.LoadSync == true).ToList();
var asyncPlugins = pluginDefs.Where(def => def.Manifest?.LoadSync != true).ToList(); var asyncPlugins = pluginDefs.Where(def => def.Manifest?.LoadSync != true).ToList();
var loadTasks = new List<Task>(); var loadTasks = new List<Task>();
var tokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(5));
// Load plugins that can be loaded anytime // Load plugins that can be loaded anytime
LoadPluginsSync( LoadPluginsSync(
"AnytimeSync", "AnytimeSync",
syncPlugins.Where(def => def.Manifest?.LoadRequiredState == 2)); syncPlugins.Where(def => def.Manifest?.LoadRequiredState == 2)).GetAwaiter().GetResult();
loadTasks.Add( loadTasks.Add(
LoadPluginsAsync( Task.Run(
"AnytimeAsync", () => LoadPluginsAsync(
asyncPlugins.Where(def => def.Manifest?.LoadRequiredState == 2))); "AnytimeAsync",
asyncPlugins.Where(def => def.Manifest?.LoadRequiredState == 2)),
tokenSource.Token));
// Load plugins that want to be loaded during Framework.Tick // Load plugins that want to be loaded during Framework.Tick
loadTasks.Add( loadTasks.Add(
Service<Framework> Task.Run(
.GetAsync() () => Service<Framework>
.ContinueWith( .GetAsync()
x => x.Result.RunOnTick( .ContinueWith(
() => LoadPluginsSync( x => x.Result.RunOnTick(
"FrameworkTickSync", () => LoadPluginsSync(
syncPlugins.Where(def => def.Manifest?.LoadRequiredState == 1))), "FrameworkTickSync",
TaskContinuationOptions.RunContinuationsAsynchronously) syncPlugins.Where(def => def.Manifest?.LoadRequiredState == 1)),
.Unwrap() cancellationToken: tokenSource.Token),
.ContinueWith( tokenSource.Token,
_ => LoadPluginsAsync( TaskContinuationOptions.RunContinuationsAsynchronously,
"FrameworkTickAsync", TaskScheduler.Default)
asyncPlugins.Where(def => def.Manifest?.LoadRequiredState == 1)), .Unwrap()
TaskContinuationOptions.RunContinuationsAsynchronously) .ContinueWith(
.Unwrap()); _ => LoadPluginsAsync(
"FrameworkTickAsync",
asyncPlugins.Where(def => def.Manifest?.LoadRequiredState == 1)),
tokenSource.Token,
TaskContinuationOptions.RunContinuationsAsynchronously,
TaskScheduler.Default)
.Unwrap(),
tokenSource.Token));
// Load plugins that want to be loaded during Framework.Tick, when drawing facilities are available // Load plugins that want to be loaded during Framework.Tick, when drawing facilities are available
loadTasks.Add( loadTasks.Add(
Service<InterfaceManager.InterfaceManagerWithScene> Task.Run(
() => Service<InterfaceManager.InterfaceManagerWithScene>
.GetAsync() .GetAsync()
.ContinueWith( .ContinueWith(
_ => Service<Framework>.Get().RunOnTick( _ => Service<Framework>.Get().RunOnTick(
() => LoadPluginsSync( () => LoadPluginsSync(
"DrawAvailableSync", "DrawAvailableSync",
syncPlugins.Where(def => def.Manifest?.LoadRequiredState is 0 or null)))) syncPlugins.Where(def => def.Manifest?.LoadRequiredState is 0 or null)),
cancellationToken: tokenSource.Token),
tokenSource.Token)
.Unwrap() .Unwrap()
.ContinueWith( .ContinueWith(
_ => LoadPluginsAsync( _ => LoadPluginsAsync(
"DrawAvailableAsync", "DrawAvailableAsync",
asyncPlugins.Where(def => def.Manifest?.LoadRequiredState is 0 or null))) asyncPlugins.Where(def => def.Manifest?.LoadRequiredState is 0 or null)),
.Unwrap()); tokenSource.Token)
.Unwrap(),
tokenSource.Token));
// Save signatures when all plugins are done loading, successful or not. // Save signatures when all plugins are done loading, successful or not.
_ = Task _ = Task
.WhenAll(loadTasks) .WhenAll(loadTasks)
.ContinueWith( .ContinueWith(
_ => Service<SigScanner>.GetAsync(), t =>
TaskContinuationOptions.RunContinuationsAsynchronously) {
Log.Information("Task.WhenAll continuing");
if (!t.IsCompletedSuccessfully)
{
foreach (var loadTask in loadTasks)
{
if (!loadTask.IsCompletedSuccessfully)
{
if (loadTask.Exception != null)
{
Log.Error(loadTask.Exception, " => Exception during load");
}
else
{
Log.Error($" => Task failed, canceled: {t.IsCanceled} faulted: {t.IsFaulted}");
}
}
}
}
return Service<SigScanner>.GetAsync();
},
tokenSource.Token,
TaskContinuationOptions.RunContinuationsAsynchronously,
TaskScheduler.Default)
.Unwrap() .Unwrap()
.ContinueWith( .ContinueWith(
sigScannerTask => sigScannerTask =>
{ {
Log.Information("sigScannerTask continuing");
this.PluginsReady = true; this.PluginsReady = true;
this.NotifyInstalledPluginsChanged(); this.NotifyInstalledPluginsChanged();
sigScannerTask.Result.Save(); sigScannerTask.Result.Save();
}, },
TaskContinuationOptions.RunContinuationsAsynchronously) tokenSource.Token,
TaskContinuationOptions.RunContinuationsAsynchronously,
TaskScheduler.Default)
.ConfigureAwait(false); .ConfigureAwait(false);
} }