Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DevBox] Start the Dev Box while configuring #273

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

huzaifa-d
Copy link
Contributor

Summary of the pull request

The PR addresses the issue where the Dev Box was no running while trying to apply a configuration. The Dev Box is now started, instead of erroring out.

##Before
image

##After
image

Validation steps performed

Manually

PR checklist

{
throw new InvalidOperationException(Resources.GetResource(NotRunningFailedKey));
}
await HandleNonRunningState();
Copy link
Contributor

@bbonaby bbonaby Sep 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we could just call the IComputeSystem StartAsync() method instead since that starts a threadpool timer that wakes up every minute to check the progress of the operation. If we pass the DevBoxInstance to the WingetConfigWrapper then we'd be able to do that. Then we could use a wait event handle within a while loop that waits every minute.

Something like this e.g

if (_devBox.GetState() != ComputeSystemState.Running))
{
    await _devBox.StartAsync(string.Empty);
    var startCancellationTokenSource = new CancellationTokenSource();
    startCancellationTokenSource.CancelAfter(TimeSpan.FromMinutes(30));

    while (_devBoxStartEvent.WaitOne(TimeSpan.FromMinutes(1)))
    {
        if (_devBox.GetState() == ComputeSystemState.Running)
        {
            break;
        }

        if (startCancellationTokenSource.IsCancellationRequested)
        {
            throw new InvalidOperationException(Resources.GetResource(DevBoxErrorStateKey))
        }
    }
 }

This would reduce the code amount by a good amount I believe. You can either use a ManualResetEvent or a Task.Delay like you've been using, but you'd have to have an extra variable to keep the loop alive. Also note, we need to increase the time Dev Home's configuration waits too here: https://github.com/microsoft/devhome/blob/ca1ca04bac3325bc68e29f8f478453d2b4f85971/tools/SetupFlow/DevHome.SetupFlow/Models/ConfigureTargetTask.cs#L419

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1. One question: would we send _devBoxStartEvent event if the device is already running by the time code in _devBox.StartAsync actually runs (since everything is async and in the cloud the device state can change between our last check and Start command)? This is probably not an issue since we check state every minute which, I assume, would be updated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea; changed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sshilov7 I just wanted to let you know that your assumption is right. Although that got me thinking of one more edge case:

  1. If the _devBox.StartAsync method returns an error then we'd be waiting for 15 minutes for no reason. @huzaifa-d, could you add an error check for this one?

private async Task HandleNonRunningState()
{
// Check if the dev box might have been started in the meantime
var stateResult = await _devBox.GetStateAsync();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should use GetState() too so we don't need to await it

ConfigurationSetStateChanged?.Invoke(this, new(new(ConfigurationSetChangeEventType.SetStateChanged, ConfigurationSetState.StartingDevice, ConfigurationUnitState.Unknown, null, null)));

// Wait for the Dev Box to start with an initial wait of 3 minutes and a max of 15 minutes
var delay = TimeSpan.FromSeconds(30);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could use the HalfMinutePeriod in the constants we're adding in this PR for this.

{
throw new InvalidOperationException(Resources.GetResource(DevBoxErrorStateKey));
}
else
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we probably don't need to wrap this in an else statement since throwing would exist the method

<value>The Dev Box isn't running. Please start the Dev Box and try again.</value>
<comment>Error shown when the operation fails due to the Dev Box not currently running.</comment>
<data name="DevBox_ErrorStateKey" xml:space="preserve">
<value>The Dev Box isn't in a valid state</value>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should say something like "{0} couldn't be started. Please try starting the Dev Box manually and try again."

where {0} is the name of the Dev Box

{
throw new InvalidOperationException(Resources.GetResource(NotRunningFailedKey));
}
await HandleNonRunningState();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sshilov7 I just wanted to let you know that your assumption is right. Although that got me thinking of one more edge case:

  1. If the _devBox.StartAsync method returns an error then we'd be waiting for 15 minutes for no reason. @huzaifa-d, could you add an error check for this one?

// Wait for the Dev Box to start with an initial wait of 3 minutes and a max of 15 minutes
var delay = TimeSpan.FromSeconds(30);
var waitTimeLeft = TimeSpan.FromMinutes(12);
await Task.Delay(TimeSpan.FromMinutes(3));
Copy link
Member

@sshilov7 sshilov7 Sep 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this 3-minute wait? Are chances that VM can start earlies so low? The code below checks the state once in 30 seconds. I wouldn't think sending 1 request per 30 seconds is too often.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants