#powershell
#powershell
Вопрос:
Я нахожусь в процессе переписывания сценария ниже, чтобы иметь возможность работать параллельно, как видно из кода, скрипту передается массив серверов, а затем он загружает его в хеш-таблицу, перебирает каждый сервер за раз для выполнения развертывания,для каждого сервера существуют файлы для выполнения в определенном порядке (см. Массив файлов). Глядя на структуру, я чувствую, что workspace — это правильный путь, но я могу ошибаться.
Где, на мой взгляд, можно увидеть прирост производительности или наличие кода, позволяющего запускать несколько серверов одновременно, а не ждать завершения работы каждого сервера и перехода к следующему. для каждого параллельного
Я запустил тест для вызова функции, объявленной вне рабочей области, она сработала.Является ли это хорошей практикой для вызова функции, объявленной вне рабочей области? Я спрашиваю об этом, потому что я хотел бы повторно использовать некоторые функции за пределами рабочей области, или вообще лучше поместить весь код в рабочую область, даже те, которые не предназначены для параллельных рабочих нагрузок, т.е. Одноразовые вызовы кода. ?
Ниже приведен код, с которым я тестирую.
Function Check-Instance-Connection{
param
(
[Parameter(Mandatory=$true,
ValueFromPipelineByPropertyName=$true,
Position=0)]
$sql_server,
[Parameter(Mandatory=$true,
ValueFromPipelineByPropertyName=$true,
Position=1)]
$db_name
)
try
{
#Return extra useful info by using custom objects
$check_outcome = "" | Select-Object -Property log_date, stage, status, error_message
$check_outcome.log_date = (Get-Date)
$check_outcome.stage = 'Ping SQL instance for $sql_server'
#test connection for a sql instance
$connectionstring = "Data Source=$sql_server;Integrated Security =true;Initial Catalog=$db_name;Connect Timeout=5;"
$sqllconnection = New-Object System.Data.SqlClient.SqlConnection $connectionstring
$sqllconnection.Open();
$check_outcome.status = $true
$check_outcome.error_message = ''
return $check_outcome
}
Catch
{
$check_outcome.status = $false
$check_outcome.error_message = $_.Exception.Message
return $check_outcome
}
finally{
$sqllconnection.Close();
}
}
$file_list = @("deployment_1.sql","deployment_2.sql","deployment_3.sql","deployment_4.sql","deployment_5.sql")
$x = (1,"Server1",3,1),(4,"Server2",6,2),(3,"Server3",4,3)
$k = 'serverid','servername','locationid','appid' # key names correspond to data positions in each array in $x
$h = @{}
For($i=0;$i -lt $x[0].length; $i ){
$x |
ForEach-Object{
[array]$h.($k[$i]) = [string]$_[$i]
}
}
$folder = "F:Files"
$database_name = "Test"
foreach ($server_id in $all_server_ids)
{
$severid = $h["serverid"][$all_server_ids.indexof($server_id)]
$servername = $h["servername"][$all_server_ids.indexof($server_id)]
$locationid = $h["locationid"][$all_server_ids.indexof($server_id)]
$message = 'ServerID {0} has a servername of {1} and a location id of {2}' -f $server_id, $h["servername"][$all_server_ids.indexof($server_id)],$h["locationid"][$all_server_ids.indexof($server_id)]
Write-Output $message
Write-Output "This $severid and this $servername and this $locationid"
foreach ($file in $file_list)
{
$is_instance_ok = Check-Instance-Connection $servername $database_name
if ($is_instance_ok.check_outcome -eq $true){
invoke-sqlcmd -ServerInstance "$servername" -inputfile $folder$file -Database "$database_name" -Querytimeout 60 -OutputSqlErrors $true -ConnectionTimeout 10 -ErrorAction Continue -Errorvariable generated_error | Out-Null
}
}
}
Комментарии:
1. В PowerShell v5 вы можете использовать Workflow и / или Jobs для выполнения параллельной обработки. Это описано в файлах справки PowerShell. В PowerShell Core v7 можно использовать новую опцию ForEach -parallel .
Ответ №1:
Спасибо, я провел гораздо больше исследований и рассмотрел множество примеров того, как работают рабочие процессы. Это то, что я придумал.
Workflow RunExecution
{
Function Check-Instance-Connection{
param
(
[Parameter(Mandatory=$true,
ValueFromPipelineByPropertyName=$true,
Position=0)]
$sql_server,
[Parameter(Mandatory=$true,
ValueFromPipelineByPropertyName=$true,
Position=1)]
$db_name
)
try
{
#Return extra useful info by using custom objects
$check_outcome = "" | Select-Object -Property log_date, stage, status, error_message
$check_outcome.log_date = (Get-Date)
$check_outcome.stage = 'Ping SQL instance for $sql_server'
#test connection for a sql instance
$connectionstring = "Data Source=$sql_server;Integrated Security =true;Initial Catalog=$db_name;Connect Timeout=5;"
$sqllconnection = New-Object System.Data.SqlClient.SqlConnection $connectionstring
$sqllconnection.Open();
$check_outcome.status = $true
$check_outcome.error_message = ''
return $check_outcome
}
Catch
{
$check_outcome.status = $false
$check_outcome.error_message = $_.Exception.Message
return $check_outcome
}
finally{
$sqllconnection.Close();
}
}
$file_list = @("deployment_1.sql","deployment_2.sql","deployment_3.sql","deployment_4.sql","deployment_5.sql")
$x = (1,"server1DEV3",3,1),(4,"serer1DEV2",6,2),(3,"serer2DEV1",4,3)
$k = 'serverid','servername','locationid','appid'
$h = @{}
For($i=0;$i -lt $x[0].length; $i ){
$x |
ForEach-Object{
[array]$h.($k[$i]) = [string]$_[$i]
}
}
$folder = "C:Temp"
$database_name = "Test"
$all_server_ids = $h['serverid']
foreach -parallel ($server_id in $all_server_ids)
{
$severid = $h["serverid"][$all_server_ids.indexof($server_id)]
$servername = $h["servername"][$all_server_ids.indexof($server_id)]
$locationid = $h["locationid"][$all_server_ids.indexof($server_id)]
foreach ($file in $file_list)
{
# $check_fine = $is_instance_ok.check_outcome
# if ($check_fine = $true){
invoke-sqlcmd -ServerInstance "$servername" -inputfile $folder$file -Database "$database_name" -Querytimeout 60 -OutputSqlErrors $true -ConnectionTimeout 10 -ErrorAction Continue
write-output "invoke-sqlcmd -ServerInstance $servername -inputfile $folder$file -Database $database_name -Querytimeout 60 -OutputSqlErrors $true -ConnectionTimeout 10 -ErrorAction Continue "
# }
}
}
}
RunExecution
Комментарии:
1. Я понял, что не могу запустить это в рамках рабочего процесса
if ($check_fine = $true)
. Интересно, есть ли здесь обходной путь. Могу ли я преобразовать выходные данные пользовательского объекта в строку вместо bool и использовать вместо этого -eq ?2.
-eq
работает с любым типом объекта, а не только со строкой. Предполагая$is_instance_ok
, что содержит вывод изCheck-Internet-Connection
, вашеif
условие должно бытьif ($is_instance_ok.status){...}