Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 SSIS запуск дочернего пакета.  [new]
IDVT
Member

Откуда:
Сообщений: 314
Всем привет, что-то я совсем ослеп.....

Не могу найти документацию, мне нужно запустить в родительском пакете несколько экземпляров дочернего пакета, делаю это в контейнере скрипта (C#), все по стандартной схеме:

.
.
.
 static void RunPackage(int NumFlowsExecute, int NumRepetition, object SourceDataList, string DTSXPackage, ref Boolean ExceptionFlow)
        {
            Application app = new Application();
            Package pkg = app.LoadPackage(DTSXPackage, null);
            Variables vars = pkg.Variables;
            vars["User::NumFlowsExecute"].Value = NumFlowsExecute;
            vars["User::SourceDataList"].Value = SourceDataList;
            vars["User::NumRepetition"].Value = NumRepetition;
            pkg.Execute(null, vars, null, null, null);

            if (pkg.ExecutionResult.ToString() == "Failure")
            {
                ExceptionFlow = true;
            }
        }
.
.
.
где переменная "DTSXPackage" полный локальный путь к дочернему пакету.
После развертывания проекта на сервер мне необходимо запускать несколько экземпляров дочернего пакета из каталога служб Integration Services (в место локального), но не получается найти документацию как обратиться к нему, подскажите пожалуйста.
9 фев 17, 08:38    [20195412]     Ответить | Цитировать Сообщить модератору
 Re: SSIS запуск дочернего пакета.  [new]
SQL2008
Member

Откуда: Москва
Сообщений: 4260
А вариант запустить несколько контейнеров С# вас не устроит?
9 фев 17, 09:21    [20195516]     Ответить | Цитировать Сообщить модератору
 Re: SSIS запуск дочернего пакета.  [new]
IDVT
Member

Откуда:
Сообщений: 314
К сожалению нет, дочерний пакет имеет в алгоритме ветвления, переход по которым осуществляется исходя из значения переменных, т.е. повторный вызов дочернего пакета с дополнительными действиями над данными. Если все засунуть в один пакет (Родитель) то слишком усложнит сопровождение проекта.
9 фев 17, 09:37    [20195587]     Ответить | Цитировать Сообщить модератору
 Re: SSIS запуск дочернего пакета.  [new]
ShIgor
Member

Откуда: Нижний Новгород
Сообщений: 2347
IDVT,

одна из LoadFromDtsServer или LoadFromSQLServer.
Сам для отладки запускаю из локального файла, а после развертывания с SQLServer
9 фев 17, 10:18    [20195752]     Ответить | Цитировать Сообщить модератору
 Re: SSIS запуск дочернего пакета.  [new]
IDVT
Member

Откуда:
Сообщений: 314
ShIgor
IDVT,

одна из LoadFromDtsServer или LoadFromSQLServer.
Сам для отладки запускаю из локального файла, а после развертывания с SQLServer


ОК, спасибо за направление, сейчас пока тупо дочерний пакет скопировал на сервер! буду читать документацию..
9 фев 17, 10:25    [20195774]     Ответить | Цитировать Сообщить модератору
 Re: SSIS запуск дочернего пакета.  [new]
Ferdipux
Member

Откуда: Москва
Сообщений: 554
IDVT
... необходимо запускать несколько экземпляров дочернего пакета из каталога служб Integration Services (в место локального)...

Каталог служб SSIS - это SSISDB?

Тогда огорчу - пакеты там запускаются совсем иначе. Приведенный вами код работает в режиме совместимости с SSIS 2008, и может загрузить пакет с диска или БД.
Чтобы запустить пакет из SSIS каталога, нужно использовать другой код - вот фрагмент примера:
using System.Data.SqlClient;
using Microsoft.SqlServer.Management.IntegrationServices;
using System.Collections.ObjectModel;
...
statiс void Start_Pkg() {
    // Connection to the database server where the packages are located
    SqlConnection ssisConnection = new SqlConnection(@"Data Source=.\SQL2012;Initial Catalog=master;Integrated Security=SSPI;");
 
    // SSIS server object with connection
    IntegrationServices ssisServer = new IntegrationServices(ssisConnection);
 
    // The reference to the package which you want to execute
    PackageInfo ssisPackage = ssisServer.Catalogs["SSISDB"].Folders["MasterChild"].Projects["MasterChildPackages"].Packages["master.dtsx"];
 
    // Add execution parameter to override the default asynchronized execution. If you leave this out the package is executed asynchronized
    Collection<PackageInfo.ExecutionValueParameterSet> executionParameter = new Collection<PackageInfo.ExecutionValueParameterSet>();

    // Добавляем параметр для синхронного выполнения
    executionParameter.Add(new PackageInfo.ExecutionValueParameterSet { 
        ObjectType = 50,
        ParameterName = "SYNCHRONIZED",
        ParameterValue = 1 }
    );

    // Переопределяем CM SourceDB
    executionParameter.Add(new PackageInfo.ExecutionValueParameterSet { 
        ObjectType = 30,
        ParameterName = @"CM.SourceDB.ConnectionString",
        ParameterValue = @"Data Source=B540P;Initial Catalog=AdventureWorks;Integrated Security=True;" }
    );

    // Указываем параметр пакета
    package.Parameters["SourceFile"].Set(
    ParameterInfo.ParameterValueType.Literal,
    strSourceFile
    );
 
    // Get the identifier of the execution to get the log
    long executionIdentifier = ssisPackage.Execute(false, null, executionParameter);
 
    // Проверяем ошибки выполнения
    var errors = execution.Messages.Where(
        m => m.MessageType == 120 || m.MessageType == 110)
        .Select(m => m.Message);
}


Можете попробовать переопределять значение переменных внутри пакета, но я бы перешел на параметры - они же immutable и устанавливаются при вызове.
9 фев 17, 10:41    [20195848]     Ответить | Цитировать Сообщить модератору
 Re: SSIS запуск дочернего пакета.  [new]
IDVT
Member

Откуда:
Сообщений: 314
Ferdipux

Спасибо! буду разбираться...
9 фев 17, 10:47    [20195881]     Ответить | Цитировать Сообщить модератору
 Re: SSIS запуск дочернего пакета.  [new]
Ferdipux
Member

Откуда: Москва
Сообщений: 554
IDVT,

И еще - пропустил переход от executionIdentifier к execution. Делается так:
var execution = ssisServer.Catalogs["SSISDB"].Executions.Single(x => x.Id.Equals(executionIdentifier));


Короче, в запуске пакетов переход SSIS 2008->2012 получился довольно радикальным.
9 фев 17, 10:55    [20195928]     Ответить | Цитировать Сообщить модератору
 Re: SSIS запуск дочернего пакета.  [new]
IDVT
Member

Откуда:
Сообщений: 314
Ferdipux,
Спасибо, как раз искал где же запуск пакета.
Подскажите пожалуйста, параллельный запуск дочерних пакетов тоже выполняется иначе?
мой листинг, но пока без рефакторинга, т.к. пока дурень, познакомился с SSIS и C# 2 месяца назад

public void Main()
        {
            // переменные

            string DTSXPackage = Dts.Variables["$Package::Local_DTSXPackageDirectory"].Value.ToString()
                               + Dts.Variables["$Package::Local_DTSXPackageName"].Value.ToString();           // путь + имя дочернего пакета 
            var TasksFlow = new List<Thread>();                                                               // список задач
            Int32 CountRunFlow = Convert.ToInt32(Dts.Variables["$Package::CountFlows"].Value);                // количество потоков
            Int32 NumRepetition = Convert.ToInt32(Dts.Variables["User::NumRepetition"].Value);                // номер итерации цикла повторной попытки загрузки данных
            Boolean ExceptionFlow = false;                                                                    // признак наличия хотя бы одного исключения, в дочерних пакетах



            DataTable DTableList = new DataTable();
            DTableList.Columns.Add("NumGroupFlow", typeof(int));
            DTableList.Columns.Add("CFDid", typeof(string));
            DTableList.Columns.Add("LinkedName", typeof(string));
            DTableList.Columns.Add("DBName", typeof(string));
            DTableList.Columns.Add("DateLoad", typeof(DateTime));


            OleDbDataAdapter OLDBA = new OleDbDataAdapter();
            System.Data.DataTable DTable = new System.Data.DataTable();
            OLDBA.Fill(DTable, Dts.Variables["User::SourceDataList"].Value);

            foreach (DataRow row in DTable.Rows)
            {
                object[] array = row.ItemArray;
                DTableList.Rows.Add(new object[] { Convert.ToInt32( array[0].ToString())      // (NumGroupFlow) номер группы потока
                                                 , array[1].ToString()                        // (CFDId)        код ЦФО
                                                 , array[2].ToString()                        // (LinkedName)   наименование связанного сервера
                                                 , array[3].ToString()                        // (DBName)       наименование БД источника
                                                 , Convert.ToDateTime(array[4].ToString())    // (DateGP)       дата ГП
                                                  });
            }

            // от кривых рук, (кол. потоков не может быть меньше 1 и превышать количество строк в источнике данных*)
            // источник данных - таблица, содержащая перечень параметров (линк, имя БД, дата ГП,..) по всем ЦФО
            if (CountRunFlow < 1)
            {
                CountRunFlow = 1;
            }
            if (CountRunFlow > DTable.Rows.Count)
            {
                CountRunFlow = DTable.Rows.Count;
            }

            // формирование задач потоков

            for (int i = 0; i < CountRunFlow; i++)
            {
                int NumFlowsExecute = i + 1;                                   // текущий номер потока
                var Thread = new Thread(() => RunPackage( NumFlowsExecute      // номер группы для потока
                                                        , NumRepetition        // номер итерации цикла повторной загрузки данных ЦФО, в которых выявлено исключение
                                                        , DTableList           // список параметров (переменных) по всем ЦФО
                                                        , DTSXPackage          // путь к дочернему пакету
                                                        , ref ExceptionFlow));
                Thread.Start();
                TasksFlow.Add(Thread);
            }

            // проверка на завершение потоков

            while (TasksFlow.Any(t => t.ThreadState == System.Threading.ThreadState.Running))
            {
                Thread.Sleep(1000);
            };

            Dts.Variables["User::ExceptionFlow"].Value = ExceptionFlow;

            Dts.TaskResult = (int)ScriptResults.Success;

        }
        static void RunPackage(int NumFlowsExecute, int NumRepetition, object SourceDataList, string DTSXPackage, ref Boolean ExceptionFlow)
        {
            Application app = new Application();
            Package pkg = app.LoadPackage(DTSXPackage, null);
            Variables vars = pkg.Variables;
            vars["User::NumFlowsExecute"].Value = NumFlowsExecute;
            vars["User::SourceDataList"].Value = SourceDataList;
            vars["User::NumRepetition"].Value = NumRepetition;
            pkg.Execute(null, vars, null, null, null);

            if (pkg.ExecutionResult.ToString() == "Failure")
            {
                ExceptionFlow = true;
            }
        }
9 фев 17, 11:30    [20196064]     Ответить | Цитировать Сообщить модератору
 Re: SSIS запуск дочернего пакета.  [new]
Ferdipux
Member

Откуда: Москва
Сообщений: 554
IDVT
Ferdipux,
Спасибо, как раз искал где же запуск пакета.
Подскажите пожалуйста, параллельный запуск дочерних пакетов тоже выполняется иначе?
...

Параллельный, хм...
Если запустить пакет без установки свойства
"SYNCHRONIZED"
, он будет работать асинхронно, но вам придется как-то мониторить его судьбу - то есть периодически проверять статус выполнения определенного executionId.
Можно попробовать создать функцию запуска с типом
async Task
, в которой выполняется запуск пакета и затем - сохранение статуса. Запустить их разом, а затем - ждать результатов. Или запустить пакеты через
Task.ParallelFor
. Вообще, написать небольшой framework для async запуска пакетов - тема интересная, нужно подумать.
Слово параллельно немного пугает, так как - в SSISDB есть проблема при одновременном запуске нескольких пакетов. Запуск 3-4 пакета на SQL 2014 отваливается с ошибкой блокировки в SSISDB. Я проблему решал запаздыванием на 0,05 - 0,1 секунду между запусками.
9 фев 17, 12:09    [20196199]     Ответить | Цитировать Сообщить модератору
 Re: SSIS запуск дочернего пакета.  [new]
IDVT
Member

Откуда:
Сообщений: 314
Ferdipux,

ОК, спасибо за информацию, буду разбираться с этим.
9 фев 17, 12:16    [20196222]     Ответить | Цитировать Сообщить модератору
 Re: SSIS запуск дочернего пакета.  [new]
ShIgor
Member

Откуда: Нижний Новгород
Сообщений: 2347
IDVT,

подсмотрено где-то и успешно используется у меня.

в ScriptTask до ScriptMain class определяем вспомогательный класс
public class SSISpkg
    {
        Package c_pkg;
        public SSISpkg(Package p_pkg)
        {
            c_pkg = p_pkg;
        }

        public void Start()
        {
            string sql_str;

            DTSExecResult rslt = c_pkg.Execute(null, c_pkg.Variables, null, null, null);

            sql_str = c_pkg.Name + ": ";
            if (c_pkg.Errors.Count > 0)
            {
                ErrorEnumerator errEnum = c_pkg.Errors.GetEnumerator();
                while ((errEnum.MoveNext()) && (errEnum.Current != null))
                {
                    sql_str += errEnum.Current.Description.Replace("'", "\"") + "\r\n";
                }
            }
            else
            {
                sql_str += rslt.ToString();
            }
            LogWriteClass.LogWrite(sql_str);
        }
    }


в ScriptMain class до процедуры Main делаем несколько определений
static ManualResetEvent _waitEvent;
        static int runningWorkers = 0;

        private void RunPakage(object a_pkg) 
        {
            int value = Interlocked.Increment(ref runningWorkers);
            (a_pkg as SSISpkg).Start();
            
            value = Interlocked.Decrement(ref runningWorkers);
            if (value == 0)
            {
                _waitEvent.Set();
            }
        } 


В Main первыми строками:
WaitCallback _callback = new WaitCallback(RunPakage);
            _waitEvent = new ManualResetEvent(false);


ну а потом, там же что-то типа:
foreach (/*у кого как у меня*/ DataRow crow in /*ну в каких-то Rows*/) 
            {
                Package pkg = app.LoadFromSqlServer(Dts.Variables["$Package::cChildPackage"].Value.ToString(), Dts.Variables["$Package::cSSISServer"].Value.ToString(), null, null, null);

                pkg.Parameters["p_xxx"].Value = Dts.Variables["User::v_xxx"].Value;
                pkg.Parameters["p_yyy"].Value = crow.ItemArray[1].ToString();
                pkg.Name = "ПакетТруЛаЛа_" + crow.ItemArray[0].ToString() + "_" + crow.ItemArray[2].ToString();
                SSISpkg threadedSSISpkg = new SSISpkg(pkg);

                ThreadPool.QueueUserWorkItem(_callback, threadedSSISpkg);
                Thread.Sleep(25); // Лучше подождать :)
            }

            _waitEvent.WaitOne();


Что хорошо - запускается почти разом 50 и более пакетов, далее пул растет до какого-то момента, потом новое задание не запускается пока не закончится какое-то из запущенных из пула, за этим следит вроде ось. Нет необходимости опрашивать запущенные пакеты на завершение, сами скажут.
Что плохо - Труднее отлаживать - это понятно. Стандартный ThreadPool не умеет ограничивать размер своего пула, хотя функции для этого есть, но реально не работают. Видел реализации SmartThreadPool, чуть сложнее и интереснее, но руки не доходят.

LogWriteClass - это еще один класс для записи ошибок в базу.
Все оказалось просто и быстро. Работает в паре десятков проектов, причем разные мастер-пакеты могут исполнятся одновременно, друг с другом особо не "бодаются".

а, ну и using System.Threading; не забыть.
9 фев 17, 17:10    [20197715]     Ответить | Цитировать Сообщить модератору
 Re: SSIS запуск дочернего пакета.  [new]
IDVT
Member

Откуда:
Сообщений: 314
ShIgor,

Спасибо огромное!
10 фев 17, 09:32    [20199268]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить