Как я могу поддерживать адаптацию и обновление пользовательского интерфейса, в то время как вся работа выполняется в фоновом режиме на локальном компьютере? - PullRequest
0 голосов
/ 07 октября 2018

У меня есть программа, которая отображает UI, позволяет пользователю выбирать имена виртуальных машин, полученные с помощью запроса к главному серверу пула Xen, а затем создает снимки для выбранных виртуальных машин.Я хочу, чтобы моментальные снимки создавались в фоновом режиме, чтобы я мог реагировать на UI и обновлять UI по мере создания каждого снимка.

Первоначально я подключился к главному серверу пула Xen, а затем выполнил командлет Xen create snapshot один раз для выбранной виртуальной машины в потоке UI.Таким образом, UI стал не отвечать.

Затем я подключился к главному серверу пула Xen, а затем сделал start-job (background job) один раз для каждой виртуальной машины, чтобы создать снимок виртуальной машины.Это не удалось, поскольку сеанс Xen, созданный в потоке UI, не мог быть передан в background job (содержимое переменной сеанса превращает его в блок, но командлет Xen Connect в блоке возвращает Could not find open sessions to any XenServers ошибка).

Затем я переместил соединение с главным сервером пула Xen в background job.Это замедлило операции, потому что установление соединения занимает несколько секунд и выполняется один раз для каждой виртуальной машины.Тем не менее, UI оставался отзывчивым, и я смог использовать данные о завершении задания для обновления UI.

. Как сохранить UI отзывчивым, обновлять UI с прогрессом в качестве каждого снимкасоздан и не будет принудительно подключаться к серверу один раз за моментальный снимок?

1 Ответ

0 голосов
/ 07 октября 2018

Обновление

Это решение позволяет получать обновления в потоке пользовательского интерфейса во время выполнения фонового задания, но оно не поддерживает отзывчивость пользовательского интерфейса.См. Мой ответ Рохину ниже.

Решение состояло в том, чтобы переместить весь цикл в background job и использовать командлет Write-Progress, чтобы сообщить о прогрессе на UI.Кредит для использования командлета Write-Progress в этом сценарии идет на Райан

Вот простая демонстрация, иллюстрирующая все необходимые части

cls

## Job code
$ScriptBlockCode = 
{
    param($items)
    $retObj = @{}

    try
    {
        $error.clear()

        for ($i = 0; $i -lt $items.Count; $i++)
        {

            #wait to simulate the time it takes to do work on item $i
            start-sleep -Seconds (get-random -Minimum 2 -Maximum 6)

            # Use Write-Progress to report the completion of each item for as long as the job runs (Can be used to updage the UI)
            # Use the -Completed argument to suppress displaying the progress bar 
            Write-Progress  -Id ($i+1) -Activity ("For UI Update: " + $items[$i] + " processing complete") -Status "Reporting" -PercentComplete ((($i+1)/$items.Count)*100) -Completed

            #Use a hashtable to report the status of each job. To be used in the calling code after the job status is no longer Running
            #simulate some items passing, some failing
            if ((get-random -Minimum 0 -Maximum 2) -eq 0)
            {
                $itemRet = [PSCustomObject]@{status="FAIL";details="some error description"}
            }
            else
            {
                $itemRet = [PSCustomObject]@{status="PASS";details=""}
            }

            $retObj.Add($items[$i],$itemRet)

        }

        return $retObj
    }
    catch
    {
        $itemRet = [PSCustomObject]@{status="ERROR";details=$error}
        $retObj.Add("FATAL",$itemRet)
        return $retObj
    }

}

cls

#clean up before starting
Get-Job -Name "UniqueJobName" -ErrorAction SilentlyContinue | Stop-Job
Get-Job -Name "UniqueJobName" -ErrorAction SilentlyContinue | Remove-Job

#simulate 5 pieces of work
$items = @("Item A", "Item B", "Item C", "Item D", "Item E")

$job = Start-Job -Name "UniqueJobName" -ScriptBlock $ScriptBlockCode -ArgumentList ($items)

#loop and update UI until job is done

$lastActivityId = -99

While ($job.State -eq "Running")
{
    $child = $job.ChildJobs[0]

    #update the UI only if progress has started and the ActivityId has not already been reported on and the Progress report is one I care about
    if ($child.Progress.Count -gt 0 -and $child.Progress[$child.Progress.Count - 1].ActivityId -ne $lastActivityId -and ($child.Progress[$child.Progress.Count - 1]).StatusDescription -eq "Reporting")
    {
        write-host "=============================="
        write-host "in progress updates"
        write-host "=============================="
        #use the progress properties, i.e., RecordType and PercentComplete to update the UI
        $child.Progress[$child.Progress.Count - 1]

        #store this Id so we can ignore progress until Id changes
        $lastActivityId = $child.Progress[$child.Progress.Count - 1].ActivityId
    }

    #period at which the UI is updated
    start-sleep -milliseconds 250
}

$retObj = Receive-Job -Name "UniqueJobName"

write-host "=============================="
write-host "receive job"
write-host "=============================="

# Because the job may finish before progress is captured 
# for each item, use the returned values to update the UI one last time
foreach ($key in $retObj.GetEnumerator())
{
    "retObj=" + $key.name + " " + $key.Value.status + " " + $key.Value.details
}

#cleanup
Get-Job -Name "UniqueJobName" | Stop-Job
Get-Job -Name "UniqueJobName" | Remove-Job

Пример вывода

==============================
in progress updates
==============================


ActivityId        : 1
ParentActivityId  : -1
Activity          : For UI Update: Item A processing complete
StatusDescription : Reporting
CurrentOperation  : 
PercentComplete   : 20
SecondsRemaining  : -1
RecordType        : Completed

==============================
in progress updates
==============================
ActivityId        : 2
ParentActivityId  : -1
Activity          : For UI Update: Item B processing complete
StatusDescription : Reporting
CurrentOperation  : 
PercentComplete   : 40
SecondsRemaining  : -1
RecordType        : Completed

==============================
in progress updates
==============================
ActivityId        : 3
ParentActivityId  : -1
Activity          : For UI Update: Item C processing complete
StatusDescription : Reporting
CurrentOperation  : 
PercentComplete   : 60
SecondsRemaining  : -1
RecordType        : Completed

==============================
in progress updates
==============================
ActivityId        : 4
ParentActivityId  : -1
Activity          : For UI Update: Item D processing complete
StatusDescription : Reporting
CurrentOperation  : 
PercentComplete   : 80
SecondsRemaining  : -1
RecordType        : Completed

==============================
receive job
==============================
retObj=Item D PASS 
retObj=Item E PASS 
retObj=Item A FAIL some error description
retObj=Item B FAIL some error description
retObj=Item C PASS 
...