Как динамически добавлять задачи в очередь заданий PowerShell

422
Mavaddat Javid

Я создал сценарий PowerShell, который копирует все загружаемые мною электронные книги в заранее определенный каталог, который периодически сканируется моим менеджером электронных книг и добавляется в мою библиотеку. Скрипт запускается сразу после каждой загрузки.

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

Поэтому я хотел бы поставить в очередь копирование с помощью заданий PowerShell, но я не знаю, как создать одну очередь (единый параллелизм), чтобы каждое последующее задание ожидало завершения каждого более старого задания.

То есть я хотел бы, чтобы скрипт создавал задание (назовем его «Книжное задание»), которое периодически проверяет очередь запуска Книжных заданий, чтобы увидеть, все ли старые работы с книгами завершились до того, как он запустится. Когда оно завершается, Книжное задание должно объявить, что оно каким-то образом завершено, что может быть обнаружено более молодыми Книжными заданиями.

Кто-нибудь знает, как я могу это сделать? Я увидел похожий вопрос, на который я смотрю: фоновые задачи Powershell, однако в моем случае я запускаю скрипт несколько раз (после каждой новой загрузки).

3
Я не хочу этого делать (переведите скрипт в спящий режим и проверьте снова после некоторого интервала), потому что скрипт PowerShell запускается после каждой загрузки (с входным параметром для определенного подкаталога, который содержит вновь загруженные файлы). Это означает, что логика очередей не может полагаться на сам скрипт, сохраняющийся в фоновом режиме. Мне бы хотелось, чтобы скрипт создавал задание, которое могло сохраняться в фоновом режиме, и проверял, является ли оно самым старым заданием в своем роде, перед выполнением логики копирования. Mavaddat Javid 6 лет назад 1
Приведенный ниже ответ выглядит как разумное решение для ваших нужд? Мне любопытно, если вы хотите, чтобы очередь ожидания была для каждого файла, найденного один за другим, поэтому при каждом выполнении сценария выполняется один файл или только для тех файлов, которые каждое выполнение обнаруживает при выполнении, только для обработки этих файлов для копирования или чего-то еще, и что-нибудь добавлено в контролируемую папку загрузки после того, как задание начало свое выполнение? Может быть, добавление дополнительной папки в цикл и очистка файлов в ней перед копированием других - это то, что может быть полезным в этом процессе. Pimp Juice IT 6 лет назад 0

1 ответ на вопрос

3
root

Моя мысль состоит в том, чтобы создать очередь, создавая один файл блокировки для каждого нового экземпляра вашего скрипта. При запуске сценария он проверяет каталог, предназначенный для отслеживания очереди на наличие существующих экземпляров сценария. Если их нет, скрипт добавляет себя в начало очереди, выполняет какое-то действие (запускает ваш код), а затем очищает свою блокировку. Если существуют блокировки, новая будет добавлена ​​в конец очереди, и экземпляр будет бесконечно проверяться, пока не окажется в начале очереди.

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

Файлы блокировки структурированы как Индекс, разделитель ("_"), идентификатор процесса.

Clear-Host  function New-Lock ([int] $index) { $newLock = "$index" + "_" + $pid + ".lck" New-Item $queue$newLock | Out-Null }  $queue = "C:\locks\"  # find the end of the stack $locks = gci $queue *.lck | sort | select -expandproperty name  # if locks exist, find the end of the stack by selecting the index of the last lock if($locks) { # gets the last lock file, selects the index by splitting on the delimiter [int]$last = [convert]::ToInt32(($locks | select -last 1).Split("_")[0],10)  # add the lock to the end of the stack New-Lock ($last + 1) } # if no locks exist, create one at the top of the stack else { New-Lock 0 }  # check if we're at the top of the stack do { $locks = gci $queue *.lck | sort | select -expandproperty name  # this is the PID on the top of the stack [int]$top = [convert]::ToInt32(($locks | select -first 1).Split("_")[1].Split(".")[0],10) write-verbose "not at the top..." sleep 1 } until ($pid -eq $top)  # if we're here, we've been to the top. it's our turn to do something Write-Verbose "we've reached the top!" # <do something. put your code here> # might be good to add some Start-Sleep here # </do something put your code here>  # now that we're done, let's delete our lock gci $queue | select -first 1 | Remove-Item 

Ниже приведен пример вымышленной временной шкалы, в котором вы загрузили три файла (я выбрал случайные PID).

  • Файл 1 загружается и запускает скрипт. Там нет существующих замков. Создать блокировку "0_19831". Мы находимся на вершине стека, поэтому ваш код выполняется. Это большая электронная книга, поэтому запуск кода передачи файлов займет всего минуту.
  • Файл 2 загружается и запускает скрипт. Блокировка (и) существуют. Создать блокировку "1_332". Мы не на вершине стека, поэтому мы подождем do/untilи продолжим проверять, пока не окажемся первыми в очереди.
  • Файл 1 закончил копирование. Удалить блокировку "0_19831".
  • Файл 3 загружается и запускает скрипт. Блокировка (и) существуют. Создать блокировку "2_7582". Мы не на вершине стека, подождите, пока мы не.
  • Файл 2 закончил копирование. Удалить блокировку "1_332".
  • Файл 3 закончил копирование. Удалить блокировку "2_7582".

Это решение не является пуленепробиваемым, но может работать в зависимости от масштаба.