Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions src/ServiceControl.Config.Tests/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,3 @@ dotnet_diagnostic.CA2007.severity = none
# Justification: Executable specifications intentionally assign properties after the
# object initializer to mirror user interaction order (e.g. typing a name after load)
dotnet_diagnostic.IDE0017.severity = none

# Cancellation analyzer debt. These fire because Particular.Analyzers is no longer pinned to 0.9.0.
# They are scheduled work, not accepted exceptions: remove a line once this project has no
# violations of that rule left, and never add a rule back to this list.
dotnet_diagnostic.PS0003.severity = none
dotnet_diagnostic.PS0013.severity = none
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class FakeEvent;

class FakeEventHandler : IHandle<FakeEvent>
{
public Task HandleAsync(FakeEvent message, CancellationToken cancellationToken) => throw new NotImplementedException();
public Task HandleAsync(FakeEvent message, CancellationToken cancellationToken = default) => throw new NotImplementedException();
}

class FakeNonEventHandler;
Expand All @@ -51,11 +51,13 @@ class FakeEventAggregator : IEventAggregator

public bool HandlerExistsFor(Type messageType) => throw new NotImplementedException();

#pragma warning disable PS0013 // Caliburn.Micro's IEventAggregator declares the marshal delegate as Func<Func<Task>, Task>
public void Subscribe(object subscriber, Func<Func<Task>, Task> marshal) => Subscribers.Add(subscriber);

public void Unsubscribe(object subscriber) => throw new NotImplementedException();

public Task PublishAsync(object message, Func<Func<Task>, Task> marshal, CancellationToken cancellationToken = new CancellationToken()) => throw new NotImplementedException();
#pragma warning restore PS0013
}
}
}
16 changes: 10 additions & 6 deletions src/ServiceControl.Config/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
# Justification: Application synchronization contexts don't require ConfigureAwait(false)
dotnet_diagnostic.CA2007.severity = none

# may be enabled in future
dotnet_diagnostic.PS0003.severity = none # A parameter of type CancellationToken on a non-private delegate or method should be optional
dotnet_diagnostic.PS0013.severity = none # A Func used as a method parameter with a Task, ValueTask, or ValueTask<T> return type argument should have at least one CancellationToken parameter type argument unless it has a parameter type argument implementing ICancellableContext
dotnet_diagnostic.PS0018.severity = none # A task-returning method should have a CancellationToken parameter unless it has a parameter implementing ICancellableContext

# Use auto property - should be fixed in an independent PR
dotnet_diagnostic.IDE0032.severity = suggestion
dotnet_diagnostic.IDE0032.severity = suggestion

# System.Windows.Input.ICommand.Execute(object) returns void and supplies no CancellationToken,
# so the async command chain built on it has no token to accept or forward. A token added here
# could only ever be CancellationToken.None. Command bodies themselves do take tokens: they are
# wired through ReactiveCommand.CreateFromTask(Func<CancellationToken, Task>), which supplies a
# real one.
[{Framework/Commands/*.cs,Framework/Command.cs,Commands/SelectPathCommand.cs}]
dotnet_diagnostic.PS0013.severity = none
dotnet_diagnostic.PS0018.severity = none
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace ServiceControl.Config.Commands;

using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Caliburn.Micro;
using Events;
Expand Down Expand Up @@ -36,34 +37,34 @@ public override async Task ExecuteAsync(ServiceControlAdvancedViewModel model)
return;
}

await UpgradeServiceControlInstance(model, instance, new ServiceControlUpgradeOptions());
await UpgradeServiceControlInstance(model, instance, new ServiceControlUpgradeOptions(), CancellationToken.None);

await eventAggregator.PublishOnUIThreadAsync(new ResetInstances());
}

async Task UpgradeServiceControlInstance(ServiceControlAdvancedViewModel model, ServiceControlAuditInstance instance, ServiceControlUpgradeOptions upgradeOptions)
async Task UpgradeServiceControlInstance(ServiceControlAdvancedViewModel model, ServiceControlAuditInstance instance, ServiceControlUpgradeOptions upgradeOptions, CancellationToken cancellationToken)
{
using (var progress = model.GetProgressObject($"UPGRADING {model.Name}"))
{
var reportCard = new ReportCard();
var restartAgain = model.IsRunning;

var stopped = await model.StopService(progress);
var stopped = await model.StopService(progress, cancellationToken);

if (!stopped)
{
await eventAggregator.PublishOnUIThreadAsync(new RefreshInstances());
await eventAggregator.PublishOnUIThreadAsync(new RefreshInstances(), cancellationToken);

reportCard.Errors.Add("Failed to stop the service");
reportCard.SetStatus();
await windowManager.ShowActionReport(reportCard, "ISSUES UPGRADING INSTANCE", "Could not upgrade instance because of the following errors:");
await windowManager.ShowActionReport(reportCard, "ISSUES UPGRADING INSTANCE", "Could not upgrade instance because of the following errors:", cancellationToken: cancellationToken);

return;
}

if (Directory.Exists(model.ForcedUpgradeBackupLocation))
{
await windowManager.ShowMessage("Cannot make database backup.", $"The target database backup location: {model.ForcedUpgradeBackupLocation} already exists.", hideCancel: true);
await windowManager.ShowMessage("Cannot make database backup.", $"The target database backup location: {model.ForcedUpgradeBackupLocation} already exists.", hideCancel: true, cancellationToken: cancellationToken);

return;
}
Expand All @@ -78,26 +79,26 @@ async Task UpgradeServiceControlInstance(ServiceControlAdvancedViewModel model,

if (reportCard.HasErrors || reportCard.HasWarnings)
{
await windowManager.ShowActionReport(reportCard, "ISSUES UPGRADING INSTANCE", "Could not upgrade instance because of the following errors:", "There were some warnings while upgrading the instance:");
await windowManager.ShowActionReport(reportCard, "ISSUES UPGRADING INSTANCE", "Could not upgrade instance because of the following errors:", "There were some warnings while upgrading the instance:", cancellationToken: cancellationToken);

return;
}

if (restartAgain)
{
var serviceStarted = await model.StartService(progress, maintenanceMode: false);
var serviceStarted = await model.StartService(progress, maintenanceMode: false, cancellationToken);
if (!serviceStarted)
{
reportCard.Errors.Add("The Service failed to start. Please consult the ServiceControl logs for this instance");
await windowManager.ShowActionReport(reportCard, "UPGRADE FAILURE", "Instance reported this error after upgrade:");
await windowManager.ShowActionReport(reportCard, "UPGRADE FAILURE", "Instance reported this error after upgrade:", cancellationToken: cancellationToken);

return;
}
}
}

await model.TryCloseAsync(true);
await eventAggregator.PublishOnUIThreadAsync(new ResetInstances());
await eventAggregator.PublishOnUIThreadAsync(new ResetInstances(), cancellationToken);
}

readonly IEventAggregator eventAggregator;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace ServiceControl.Config.Commands;

using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Caliburn.Micro;
using Events;
Expand Down Expand Up @@ -36,34 +37,34 @@ public override async Task ExecuteAsync(ServiceControlAdvancedViewModel model)
return;
}

await UpgradeServiceControlInstance(model, instance);
await UpgradeServiceControlInstance(model, instance, CancellationToken.None);

await eventAggregator.PublishOnUIThreadAsync(new ResetInstances());
}

async Task UpgradeServiceControlInstance(ServiceControlAdvancedViewModel model, ServiceControlInstance instance)
async Task UpgradeServiceControlInstance(ServiceControlAdvancedViewModel model, ServiceControlInstance instance, CancellationToken cancellationToken)
{
using (var progress = model.GetProgressObject($"UPGRADING {model.Name}"))
{
var reportCard = new ReportCard();
var restartAgain = model.IsRunning;

var stopped = await model.StopService(progress);
var stopped = await model.StopService(progress, cancellationToken);

if (!stopped)
{
await eventAggregator.PublishOnUIThreadAsync(new RefreshInstances());
await eventAggregator.PublishOnUIThreadAsync(new RefreshInstances(), cancellationToken);

reportCard.Errors.Add("Failed to stop the service");
reportCard.SetStatus();
await windowManager.ShowActionReport(reportCard, "ISSUES UPGRADING INSTANCE", "Could not upgrade instance because of the following errors:");
await windowManager.ShowActionReport(reportCard, "ISSUES UPGRADING INSTANCE", "Could not upgrade instance because of the following errors:", cancellationToken: cancellationToken);

return;
}

if (Directory.Exists(model.ForcedUpgradeBackupLocation))
{
await windowManager.ShowMessage("Cannot make database backup.", $"The target database backup location: {model.ForcedUpgradeBackupLocation} already exists.", hideCancel: true);
await windowManager.ShowMessage("Cannot make database backup.", $"The target database backup location: {model.ForcedUpgradeBackupLocation} already exists.", hideCancel: true, cancellationToken: cancellationToken);

return;
}
Expand All @@ -78,28 +79,28 @@ async Task UpgradeServiceControlInstance(ServiceControlAdvancedViewModel model,

if (reportCard.HasErrors || reportCard.HasWarnings)
{
await windowManager.ShowActionReport(reportCard, "ISSUES UPGRADING INSTANCE", "Could not upgrade instance because of the following errors:", "There were some warnings while upgrading the instance:");
await windowManager.ShowActionReport(reportCard, "ISSUES UPGRADING INSTANCE", "Could not upgrade instance because of the following errors:", "There were some warnings while upgrading the instance:", cancellationToken: cancellationToken);

return;
}

if (restartAgain)
{
var serviceStarted = await model.StartService(progress, maintenanceMode: false);
var serviceStarted = await model.StartService(progress, maintenanceMode: false, cancellationToken);
if (!serviceStarted)
{
reportCard.Errors.Add(
"The Service failed to start. Please consult the ServiceControl logs for this instance");
await windowManager.ShowActionReport(reportCard, "UPGRADE FAILURE",
"Instance reported this error after upgrade:");
"Instance reported this error after upgrade:", cancellationToken: cancellationToken);

return;
}
}
}

await model.TryCloseAsync(true);
await eventAggregator.PublishOnUIThreadAsync(new ResetInstances());
await eventAggregator.PublishOnUIThreadAsync(new ResetInstances(), cancellationToken);
}

readonly IEventAggregator eventAggregator;
Expand Down
34 changes: 18 additions & 16 deletions src/ServiceControl.Config/Commands/ScmuCommandChecks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using ServiceControl.Config.Framework;
using ServiceControlInstaller.Engine;
Expand All @@ -18,7 +19,7 @@ public ScmuCommandChecks(IServiceControlWindowManager windowManager)
this.windowManager = windowManager;
}

protected override async Task<bool> PromptForRabbitMqCheck(bool isUpgrade)
protected override async Task<bool> PromptForRabbitMqCheck(bool isUpgrade, CancellationToken cancellationToken = default)
{
var title = isUpgrade ? "UPGRADE WARNING" : "INSTALL WARNING";
var beforeWhat = isUpgrade ? "upgrading" : "installing";
Expand All @@ -34,27 +35,28 @@ protected override async Task<bool> PromptForRabbitMqCheck(bool isUpgrade)
message.AppendLine();
message.AppendLine($"Please confirm your broker meets the minimum requirements before {beforeWhat}.");

var continueInstall = await windowManager.ShowYesNoDialog(title, message.ToString(), question, yes, no);
var continueInstall = await windowManager.ShowYesNoDialog(title, message.ToString(), question, yes, no, cancellationToken);
return continueInstall;
}

protected override Task NotifyForDeprecatedMessageTransport(TransportInfo transport)
protected override Task NotifyForDeprecatedMessageTransport(TransportInfo transport, CancellationToken cancellationToken = default)
{
return windowManager.ShowMessage("DEPRECATED MESSAGE TRANSPORT", $"The message transport '{transport.DisplayName}' is not available in this version of ServiceControl, and this instance cannot be upgraded.", acceptText: "Cancel Upgrade", hideCancel: true);
return windowManager.ShowMessage("DEPRECATED MESSAGE TRANSPORT", $"The message transport '{transport.DisplayName}' is not available in this version of ServiceControl, and this instance cannot be upgraded.", acceptText: "Cancel Upgrade", hideCancel: true, cancellationToken: cancellationToken);
}

protected override Task NotifyForMissingSystemPrerequisites(string missingPrereqsMessage)
protected override Task NotifyForMissingSystemPrerequisites(string missingPrereqsMessage, CancellationToken cancellationToken = default)
{
return windowManager.ShowMessage("Missing prerequisites", missingPrereqsMessage, acceptText: "Cancel", hideCancel: true);
return windowManager.ShowMessage("Missing prerequisites", missingPrereqsMessage, acceptText: "Cancel", hideCancel: true, cancellationToken: cancellationToken);
}

protected override async Task NotifyForIncompatibleStorageEngine(IServiceControlBaseInstance baseInstance)
protected override async Task NotifyForIncompatibleStorageEngine(IServiceControlBaseInstance baseInstance, CancellationToken cancellationToken = default)
{
var openUpgradeGuide = await windowManager.ShowYesNoDialog("STORAGE ENGINE INCOMPATIBLE",
$"The storage format has changed and the {baseInstance.PersistenceManifest.DisplayName} storage engine is no longer available. Upgrading requires a side-by-side deployment of both versions. Migration guidance is available in the version 4 to 5 upgrade guidance at {UpgradeGuide4to5Url}",
"Open online ServiceControl 4 to 5 upgrade guide in system default browser?",
"Yes",
"No"
"No",
cancellationToken
);

if (openUpgradeGuide)
Expand All @@ -63,7 +65,7 @@ protected override async Task NotifyForIncompatibleStorageEngine(IServiceControl
}
}

protected override async Task NotifyForIncompatibleUpgradeVersion(UpgradeInfo upgradeInfo)
protected override async Task NotifyForIncompatibleUpgradeVersion(UpgradeInfo upgradeInfo, CancellationToken cancellationToken = default)
{
var nextVersion = upgradeInfo.UpgradePath[0];
await windowManager.ShowMessage("VERSION UPGRADE INCOMPATIBLE",
Expand All @@ -76,26 +78,26 @@ await windowManager.ShowMessage("VERSION UPGRADE INCOMPATIBLE",
"<ListItem Margin=\"48,0,0,0\"><Paragraph>Upgrade this instance to the latest version of ServiceControl.</Paragraph></ListItem>\r\n" +
"</List>\r\n" +
"</Section>",
hideCancel: true);
hideCancel: true, cancellationToken: cancellationToken);
}

protected override Task NotifyError(string title, string message)
protected override Task NotifyError(string title, string message, CancellationToken cancellationToken = default)
{
return windowManager.ShowMessage(title.ToUpperInvariant(), message, hideCancel: true);
return windowManager.ShowMessage(title.ToUpperInvariant(), message, hideCancel: true, cancellationToken: cancellationToken);
}

protected override Task<bool> PromptToStopRunningInstance(BaseService instance)
protected override Task<bool> PromptToStopRunningInstance(BaseService instance, CancellationToken cancellationToken = default)
{
return windowManager.ShowYesNoDialog($"STOP INSTANCE AND UPGRADE TO {Constants.CurrentVersion}",
$"{instance.Name} needs to be stopped in order to upgrade to version {Constants.CurrentVersion}.",
"Do you want to proceed?",
"Yes, I want to proceed", "No");
"Yes, I want to proceed", "No", cancellationToken);
}

protected override Task<bool> PromptToContinueWithForcedUpgrade()
protected override Task<bool> PromptToContinueWithForcedUpgrade(CancellationToken cancellationToken = default)
{
return windowManager.ShowMessage("Forced migration",
"Do you want to proceed with forced migration to ServiceControl 5? The current RavenDB 3.5 database will be moved aside and a new database will be created.", "Yes");
"Do you want to proceed with forced migration to ServiceControl 5? The current RavenDB 3.5 database will be moved aside and a new database will be created.", "Yes", cancellationToken: cancellationToken);
}
}
}
Loading