Quantcast
Channel: SQL.ru: Microsoft SQL Server
Viewing all articles
Browse latest Browse all 7251

SSIS обработка ошибок

$
0
0
Добрый день, подскажите пожалуйста, больше спрашивать не у кого...

Есть ETL пакет, который трансформирует и актуализирует данные ХД из промежуточной области (StageDB). Таблицы промежуточной области заполняет дочерний пакет, по факту родительский пакет параллельно запускает N'ое количество дочерних пакетов (количество указывается в параметрах родителя), при этом все шаги получения данных дочернего объекта обернуты в цикл, на тот случай если параметр количества параллельной обработки имеет меньшее значение чем количество источников данных. Все пакеты имеют обработчик событий OnError, который пишет (обычный insert с параметрами) в таблицу логирования.
Вопрос:
В Visual Studio все работает отлично, если у одного из экземпляров дочернего пакета в каком-то источнике данных возникает исключение (сервер недоступен, БД в монопольном режиме…) то обработчик событий фиксирует ошибку и переходит в цикле к следующему источнику. Все прям так, как и хотел. Но развернутый пакет в службу Integration Services ведет себя совсем по-другому, в случае выявленного исключения дочернего пакета фиксирует ошибку в таблицу логирования и просто заворачивает родительский пакет. Причину пока не удается выявить, отчеты SSIS нечего внятного не показывают, обработчик событий не фиксирует исключения в таблицу именно такой ситуации.

Вызов дочернего пакета в родителе осуществляет компонент Script, есть одна особенность, развернутый родительский пакет в службе Integ.Services так же обращается к локальному файлу дочернего пакета, но я сомневаюсь что тут причина.

+
           string DTSXPackage = Dts.Variables["$Package::Local_DTSXPackageDirectory"].Value.ToString()
                               + Dts.Variables["$Package::Local_DTSXPackageNameFor1C"].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;
            }
        }
        #region ScriptResults declaration

        enum ScriptResults
        {
            Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
            Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
        };
        #endregion

    }


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

Viewing all articles
Browse latest Browse all 7251