Запустить событие с работы - PullRequest
1 голос
/ 15 июня 2019

Я очень новичок в powershell. Мой вопрос очень прост, если вы знаете что-нибудь о powershell.

В приведенном ниже коде я пытаюсь вызвать событие из фрагмента кода, выполняемого асинхронно как задание. По какой-то причине код не работает.

$callback = {
  param($event);
  Write "IN CALLBACK";
};

$jobScript = {
  while ($true) {
    sleep -s 1;
    "IN JOB SCRIPT";
    New-Event myEvent;
  }
}
Register-EngineEvent -SourceIdentifier myEvent -Action $callback;
Start-Job -Name Job -ScriptBlock $jobScript;

while ($true) {
  sleep -s 1;
  "IN LOOP";
}

Ожидаемый результат:

IN LOOP
IN JOB SCRIPT
IN CALLBACK
IN LOOP 
IN JOB SCRIPT
IN CALLBACK
...

Фактический объем производства:

IN LOOP
IN LOOP 
IN LOOP
IN LOOP 
...

После прочтения я изменил эту строку

Start-Job -Name Job -ScriptBlock $jobScript

до

Start-Job -Name Job -ScriptBlock $jobScript | Wait-Job | Receive-Job;

и я вообще ничего не получаю, потому что работа никогда не заканчивается.

Это вроде асинхронно, но не совсем. Было бы довольно просто выполнить в JS.

const fireEvent = (eventName) => { ... }
const subscribeToEvent = (eventName, callback) => { ... }
const callback = () => console.log('IN CALLBACK')

subscribeToEvent('myEvent', callback);

setInterval(() => {
   console.log('IN LOOP')
   fireEvent('myEvent');
}, 1000)

Пожалуйста, помогите!

Ответы [ 2 ]

4 голосов
/ 15 июня 2019

Запуск:

while ($true) {
  sleep -s 1;
  "IN LOOP";
}

всегда даст вам только:

IN LOOP
IN LOOP
IN LOOP
IN LOOP

Запуск этого блока:

$callback = {
  param($event);
  Write "IN CALLBACK";
};

$jobScript = {
  while ($true) {
    sleep -s 1;
    "IN JOB SCRIPT";
    New-Event myEvent;
  }
}
Register-EngineEvent -SourceIdentifier myEvent -Action $callback;
Start-Job -Name Job -ScriptBlock $jobScript;

даст вам задание под названием Работа.Эта работа будет выполняться, пока вы не остановите ее.Вывод задания будет примерно таким:

get-job Job | receive-job
IN JOB SCRIPT

RunspaceId       : cf385728-926c-4dda-983e-6a5cfd4fd67f
ComputerName     :
EventIdentifier  : 1
Sender           :
SourceEventArgs  :
SourceArgs       : {}
SourceIdentifier : myEvent
TimeGenerated    : 6/15/2019 3:35:09 PM
MessageData      :

IN JOB SCRIPT
RunspaceId       : cf385728-926c-4dda-983e-6a5cfd4fd67f
ComputerName     :
EventIdentifier  : 2
Sender           :
SourceEventArgs  :
SourceArgs       : {}
SourceIdentifier : myEvent
TimeGenerated    : 6/15/2019 3:35:10 PM
MessageData      :


...

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

Если вы сделаете это:

$jobScript = {
    $callback = {
        Write-Host "IN CALLBACK"
    }

    $null = Register-EngineEvent -SourceIdentifier myEvent -Action $callback

    while ($true) {
        sleep -s 1
        Write-Host "IN JOB SCRIPT"
        $Null = New-Event myEvent 
    }
}

$Null = Start-Job -Name Job -ScriptBlock $jobScript;

while ($true) {
    sleep -s 1
    "IN LOOP"
    Get-Job -Name Job | Receive-Job 
}

При выполнении $null = Register-EngineEvent ... или $null = Start-Job ... вы избегаетеобъекты, создаваемые этими командами для отображения на консоли.Кроме того, вам не нужно заканчивать свои строки с ; в PowerShell.

1 голос
/ 16 июня 2019

В дополнение Полезный ответ Акселя Андерсона :

  • Register-EngineEvent подписывается на событие в текущем сеансе , тогда как команды, запущенные с Start-Job, выполняются в фоновом задании, которое является дочерним процессом , который определение является отдельной сессией.

  • Аналогично, любые события, которые вы вызываете с помощью New-Event, видны только в том же сеансе , поэтому вызывающий сеанс никогда не видел события.

Перемещая всю логику событий в фоновое задание, как в ответе Акселя, события обрабатываются в фоновом задании , но есть важное ограничение - которое может иметь или не иметь важно для вас:

Вы не сможете захватить вывод из обработчика событий: пока вы можете сделать вывод на печать на консоль , используя Write-Host, этот вывод не может быть захвачен для программной обработки . Кроме того, такой Write-Host вывод не может быть подавлен .

Напротив, выходные данные отправляются в поток успешного вывода непосредственно из фонового задания - например, "IN JOB SCRIPT" is, неявно (подразумеваемое использование Write-Output) - можно получить через Receive-Job, который извлекает выходные данные из фоновых заданий.

Поэтому, возможно, в вашем случае достаточно, что вообще не требует использования событий:

# Code to execute in the background, defined a script block.
$jobScript = {
  while ($true) {
    Start-Sleep -Seconds 1
    "JOB OUTPUT #$(($i++))"
  }
}

# Launch the background job and save the job object in variable $job.
$job = Start-Job -Name Job -ScriptBlock $jobScript;

# Periodically relay the background job's output.
while ($true) {
  Start-Sleep -Seconds 1
  "IN LOOP, about to get latest job output:"
  $latestOutput = Receive-Job $job
  "latest output: $latestOutput"
}

Для объяснения конструкции $(($i++)) см. этот ответ .

Выше приведено следующее:

IN LOOP, about to get latest job output:
latest output:
IN LOOP, about to get latest job output:
latest output: JOB OUTPUT #0
IN LOOP, about to get latest job output:
latest output: JOB OUTPUT #1
IN LOOP, about to get latest job output:
latest output: JOB OUTPUT #2
IN LOOP, about to get latest job output:
latest output: JOB OUTPUT #3
IN LOOP, about to get latest job output:
latest output: JOB OUTPUT #4
IN LOOP, about to get latest job output:
latest output: JOB OUTPUT #5
IN LOOP, about to get latest job output:
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...