Как избежать сбоя задачи SSIS FTP при отсутствии файлов для загрузки? - PullRequest
18 голосов
/ 26 сентября 2008

Я использую SQL Server 2005 и создаю задачи ftp в SSIS.

Иногда будут файлы для FTP, иногда нет. Если файлов нет, я не хочу, чтобы задача или пакет не работали. Я изменил стрелку, переходящую от задачи ftp к следующей: «завершение», поэтому пакет проходит. Я изменил допустимое количество ошибок на 4 (потому что есть задачи 4 ftp, и у любого из 4 каталогов могут быть или не быть файлы).

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

Как установить свойства в задаче ftp, чтобы не найти файлы по ftp не было ошибкой? Я использую операцию «Отправить файлы».

Вот еще немного информации: файлы находятся на сервере, к которому у меня нет доступа, кроме ftp. И я не знаю имен файлов заранее. Пользователь может называть их как угодно. Так что я не могу проверить конкретные файлы, и, я думаю, я не могу проверить вообще. За исключением случаев использования ftp-соединения и задач, основанных на этом соединении. Файлы находятся на удаленном сервере, и я хочу скопировать их на мой сервер, чтобы получить их с этого удаленного сервера.

Я могу использовать командный уровень ftp в скриптовом задании. Возможно, это то, что мне нужно использовать вместо задачи ftp. (Я перешел на использование командной строки ftp с файлом параметров, вызванным из задачи скрипта. Он не выдает ошибок, когда нет файлов для получения. Я думаю, что это решение будет работать для меня. Я создаю файл параметров динамически, что означает, что мне не нужно иметь информацию о соединении в простом текстовом файле, а скорее можно сохранить в моем файле конфигурации, который находится в более безопасном месте.)

Ответы [ 12 ]

14 голосов
/ 16 июля 2011

Я понимаю, что вы нашли ответ на свой вопрос. Это для других пользователей, которые могут наткнуться на этот вопрос. Вот один из возможных способов достижения этого. Script Task может использоваться для поиска списка файлов, присутствующих в пути к папке FTP для данного шаблона (скажем, *.txt). Ниже приведен пример того, как это можно сделать.

Пошаговый процесс:

  1. В пакете служб SSIS создайте FTP Connection с именем FTP , а также создайте 5 переменных, как показано на скриншоте # 1 . Переменная RemotePath содержит путь к папке FTP; LocalPath содержит папку, в которую будут загружены файлы; FilePattern содержит шаблон файла для поиска списка файлов для загрузки с FTP-сервера; FileName будет заполняться Foreach loop container, но во избежание ошибки времени разработки задачи FTP его можно заполнить / или для свойства DelayValidation задачи FTP можно установить True .

  2. В пакете служб SSIS поместите Script Task, Foreach Loop container и FTP Task в Foreach Loop container, как показано на скриншотах # 2 .

  3. Замените метод Main() в Script Task на код в разделе Код задачи сценария . Задача сценария заполнит переменную ListOfFiles набором файлов, соответствующих заданному шаблону. В этом примере сначала будет использоваться шаблон * .txt, который не даст результатов, а затем шаблон * .xls, который будет соответствовать нескольким файлам на FTP-сервере.

  4. Настройте Foreach Loop container, как показано на скриншотах # 3 и # 4 . Эта задача будет проходить через переменную ** ListOfFiles *. Если нет файлов, задача FTP внутри контейнера цикла не будет выполнена. Если есть файлы, задача FTP внутри контейнера цикла будет выполняться для задачи с количеством файлов, найденных на сервере FTP.

  5. Настройте FTP Task, как показано на скриншотах # 5 и # 6 .

  6. Снимок экрана # 7 показывает пример выполнения пакета при обнаружении нет соответствующих файлов для шаблона *.txt.

  7. Снимок экрана # 8 показывает содержимое папки C:\temp\ до выполнения пакета.

  8. Снимок экрана # 9 показывает пример выполнения пакета при обнаружении подходящих файлов для шаблона *.xls.

  9. Снимок экрана # 10 показывает содержимое удаленного пути FTP /Practice/Directory_New.

  10. Снимок экрана # 11 показывает содержимое папки C:\temp\ после выполнения пакета.

  11. Снимок экрана # 12 показывает сбой пакета при наличии неправильного Удаленный путь .

  12. Снимок экрана # 13 показывает сообщение об ошибке, связанное с ошибкой пакета.

Надеюсь, это поможет.

Код задачи скрипта:

C # код, который можно использовать в SSIS 2008 and above.

Включить оператор using с использованием System.Text.RegularExpressions;

public void Main()
{
    Variables varCollection = null;
    ConnectionManager ftpManager = null;
    FtpClientConnection ftpConnection = null;
    string[] fileNames = null;
    string[] folderNames = null;
    System.Collections.ArrayList listOfFiles = null;
    string remotePath = string.Empty;
    string filePattern = string.Empty;
    Regex regexp;
    int counter;

    Dts.VariableDispenser.LockForWrite("User::RemotePath");
    Dts.VariableDispenser.LockForWrite("User::FilePattern");
    Dts.VariableDispenser.LockForWrite("User::ListOfFiles");
    Dts.VariableDispenser.GetVariables(ref varCollection);

    try
    {
        remotePath = varCollection["User::RemotePath"].Value.ToString();
        filePattern = varCollection["User::FilePattern"].Value.ToString();

        ftpManager = Dts.Connections["FTP"];
        ftpConnection = new FtpClientConnection(ftpManager.AcquireConnection(null));
        ftpConnection.Connect();
        ftpConnection.SetWorkingDirectory(remotePath);
        ftpConnection.GetListing(out folderNames, out fileNames);
        ftpConnection.Close();

        listOfFiles = new System.Collections.ArrayList();
        if (fileNames != null)
        {
            regexp = new Regex("^" + filePattern + "$");
            for (counter = 0; counter <= fileNames.GetUpperBound(0); counter++)
            {
                if (regexp.IsMatch(fileNames[counter]))
                {
                    listOfFiles.Add(remotePath + fileNames[counter]);
                }
            }
        }

        varCollection["User::ListOfFiles"].Value = listOfFiles;
    }
    catch (Exception ex)
    {
        Dts.Events.FireError(-1, string.Empty, ex.ToString(), string.Empty, 0);
        Dts.TaskResult = (int) ScriptResults.Failure;
    }
    finally
    {
        varCollection.Unlock();
        ftpConnection = null;
        ftpManager = null;
    }

    Dts.TaskResult = (int)ScriptResults.Success;
}

VB код, который можно использовать в SSIS 2005 and above.

Включить оператор Imports Imports System.Text.RegularExpressions

Public Sub Main()
    Dim varCollection As Variables = Nothing
    Dim ftpManager As ConnectionManager = Nothing
    Dim ftpConnection As FtpClientConnection = Nothing
    Dim fileNames() As String = Nothing
    Dim folderNames() As String = Nothing
    Dim listOfFiles As Collections.ArrayList
    Dim remotePath As String = String.Empty
    Dim filePattern As String = String.Empty
    Dim regexp As Regex
    Dim counter As Integer

    Dts.VariableDispenser.LockForRead("User::RemotePath")
    Dts.VariableDispenser.LockForRead("User::FilePattern")
    Dts.VariableDispenser.LockForWrite("User::ListOfFiles")
    Dts.VariableDispenser.GetVariables(varCollection)

    Try

        remotePath = varCollection("User::RemotePath").Value.ToString()
        filePattern = varCollection("User::FilePattern").Value.ToString()

        ftpManager = Dts.Connections("FTP")
        ftpConnection = New FtpClientConnection(ftpManager.AcquireConnection(Nothing))

        ftpConnection.Connect()
        ftpConnection.SetWorkingDirectory(remotePath)
        ftpConnection.GetListing(folderNames, fileNames)
        ftpConnection.Close()

        listOfFiles = New Collections.ArrayList()
        If fileNames IsNot Nothing Then
            regexp = New Regex("^" & filePattern & "$")
            For counter = 0 To fileNames.GetUpperBound(0)
                If regexp.IsMatch(fileNames(counter)) Then
                    listOfFiles.Add(remotePath & fileNames(counter))
                End If
            Next counter
        End If

        varCollection("User::ListOfFiles").Value = listOfFiles

        Dts.TaskResult = ScriptResults.Success

    Catch ex As Exception
        Dts.Events.FireError(-1, String.Empty, ex.ToString(), String.Empty, 0)
        Dts.TaskResult = ScriptResults.Failure
    Finally
        varCollection.Unlock()
        ftpConnection = Nothing
        ftpManager = Nothing
    End Try

    Dts.TaskResult = ScriptResults.Success
End Sub

Скриншот № 1:

1

Скриншот №2:

2

Скриншот № 3:

3

Снимок экрана № 4:

4

Снимок экрана № 5:

5

Снимок экрана № 6:

6

Снимок экрана № 7:

7

Снимок экрана № 8:

8

Снимок экрана № 9:

9

Снимок экрана № 10:

10

Снимок экрана № 11:

11

Снимок экрана № 12:

12

Снимок экрана № 13:

13

14 голосов
/ 20 ноября 2008

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

У меня была почти такая же проблема, но с получением файлов. Я хотел, чтобы пакет НЕ потерпел неудачу, когда на FTP-сервере не было найдено файлов. Приведенная выше ссылка останавливает появление ошибки и приводит к сбою пакета; что-то, что вы бы подумали, FailPackageOnError = false должен был сделать? : -S

Надеюсь, это решит и тебя!

4 голосов
/ 16 октября 2015

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

Моя задача FTP была неудачной, так как я не разрешил перезаписывать файлы, скажем, задание запускалось дважды подряд, первый проход будет в порядке, потому что некоторые файлы передаются, но произойдет сбой, если локальный файл уже существует ,

Мое решение было простым:

  1. Задача правой кнопкой мыши - Свойства
  2. Set ForceExecutionResult = "Success"
3 голосов
/ 03 октября 2008

(Я не могу принять свой собственный ответ, но это было решение, которое работало для меня.)

Возможно, это не лучшее решение, но это работает.

Я использую задачу скрипта, и у меня есть куча переменных для информации о соединении ftp, а также исходных и целевых каталогов. (Потому что мы будем менять сервер, на котором он запущен, и его будет проще изменить в пакете конфигурации.)

Я создаю текстовый файл на лету и записываю в него команды ftp:

    Dim ftpStream As StreamWriter = ftpFile.CreateText()
    ftpStream.WriteLine(ftpUser)
    ftpStream.WriteLine(ftpPassword)
    ftpStream.WriteLine("prompt off")
    ftpStream.WriteLine("binary")
    ftpStream.WriteLine("cd " & ftpDestDir)
    ftpStream.WriteLine("mput " & ftpSourceDir)
    ftpStream.WriteLine("quit 130")
    ftpStream.Close()

Затем, предоставив достаточно времени для реального закрытия, я запускаю процесс для выполнения команды ftp:

    ftpParameters = "-s:" & ftpParameterLoc & ftpParameterFile & " " & ftpServer
    proc = System.Diagnostics.Process.Start("ftp", ftpParameters)

Затем, после того, как я дал ему некоторое время для запуска процесса ftp, я удаляю временный файл ftp (в котором есть информация о соединении!).

Если файлы не существуют в исходном каталоге (переменная имеет отображение \\ drive \ dir \ *. *), То ошибки нет. Если возникает какая-то другая ошибка, задача все равно не выполняется, как и должно быть.

Я новичок в SSIS, и это может быть клуджем. Но это работает на данный момент. Наверное, я попросил лучший способ, и я, конечно, не буду утверждать, что это так.

Как я указывал, у меня нет возможности узнать, как называются файлы, и даже если там вообще есть какие-либо файлы. Если они там, я хочу их получить.

1 голос
/ 16 февраля 2018

1) Установите свойство задачи FTP ForceExecutionResult = Success

2) Добавьте этот код в обработчик событий FTP Task OnError.

    public void Main()
    {
        // TODO: Add your code here

        int errorCode = (int)Dts.Variables["System::ErrorCode"].Value;

        if (errorCode.ToString().Equals("-1073573501"))
        {
            Dts.Variables["System::Propagate"].Value = false;
        }
        else
        {
            Dts.Variables["System::Propagate"].Value = true;
        }


        Dts.TaskResult = (int)ScriptResults.Success;
    }
1 голос
/ 26 сентября 2008

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

Вы должны иметь возможность установить переменную в задаче сценария ActiveX, а затем использовать ее, чтобы решить, должна ли выполняться задача FTP. Вот пример здесь , который работает с локальными путями. Надеюсь, вы сможете адаптировать концепцию (или, если возможно, подключить диск FTP и сделать это таким образом).

0 голосов
/ 18 июля 2012

Альтернативой является использование этого FTP File Enumerator enter image description here

0 голосов
/ 20 февраля 2012

Это еще одно решение, которое работает для меня, использует встроенные функции и поэтому без переписывания логики FTP вручную:

1) Создайте в вашем пакете переменную с именем FTP_Error

2) Выберите задачу FTP, затем перейдите на вкладку «Обработчики событий»

3) Нажмите на странице, чтобы создать обработчик событий для «Задачи FTP / OnError» - он будет срабатывать при возникновении проблем с FTP

4) На панели инструментов перетащите элемент «Задача сценария» и дважды щелкните его, чтобы открыть его

5) В первом всплывающем окне ReadOnlyVariables - добавить System :: ErrorCode, System :: ErrorDescription

6) В первом всплывающем окне ReadWriteVariables - добавьте переменную User :: FTP_Error

7) Редактировать скрипт

8) В скрипте установите переменную FTP_Error для хранения переменных ReadOnlyVariable, которые у нас были выше:

Dts.Variables["FTP_Error"].Value = "ErrorCode:" + Dts.Variables["ErrorCode"].Value.ToString() + ", ErrorDescription=" + Dts.Variables["ErrorDescription"].Value.ToString();

9) Сохранить и закрыть скрипт

10) Нажмите «ОК» для выполнения сценария

11) Вернуться на вкладку «Поток управления»

12) В задаче FTP OnError перейдите к новой задаче «Сценарий» и отредактируйте ее

13) ReadOnlyVariables: User :: FTP_Error from before

14) Теперь, когда на FTP не найдено файлов, код ошибки -1073573501 (список ссылок кода ошибки можно найти здесь: http://msdn.microsoft.com/en-us/library/ms345164.aspx)

15) В вашем скрипте вставьте логику, чтобы делать то, что вы хотите - если вы найдете код «файлы не найдены», то, возможно, вы скажете, что задача выполнена успешно. Если нет, то задача не выполнена. И ваш нормальный поток может справиться с этим, как вы хотите:

if (Dts.Variables["FTP_Error"].Value.ToString().Contains("-1073573501"))
{
  // file not found - not a problem
  Dts.TaskResult = (int)ScriptResults.Success;
}
else
{
  // some other error - raise alarm!
  Dts.TaskResult = (int)ScriptResults.Failure;
}

И оттуда ваш поток Succeeded / Failed будет делать то, что вы хотите с ним делать.

0 голосов
/ 10 марта 2010

Вы можете использовать бесплатную задачу SSIS FTP ++ от eaSkills. Он не выдает ошибку, если файл или файлы не существуют, он поддерживает групповые символы и дает вам возможность загружать и удалять, если вам нужно это сделать.

Вот ссылка на страницу функции: http://www.easkills.com/ssis/ftptask

0 голосов
/ 02 октября 2008

ага, окей - спасибо за разъяснения. Поскольку задача FTP не может вернуть список папок, будет невозможно использовать ForEach, как я первоначально сказал - это работает, только если вы загружаете количество файлов X в удаленный источник.

Чтобы загрузить X файлов, вы можете пойти двумя путями, либо вы можете сделать это полностью в .Net в задаче сценария, либо вы можете заполнить ArrayList именами файлов из задачи сценария .Net, а затем ForEach. через ArrayList, передавая имя файла переменной и загружая это имя переменной в стандартную задачу FTP.

Пример кода для костюма: http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=2472491&SiteID=1

Итак, в приведенном выше примере вы получите FileNames () и заполните ArrayList из этого, затем назначите ArrayList переменной типа Object в Dts.Variables, а затем ForEach поверх этой переменной Object (ArrayList), используя код как: http://www.sqlservercentral.com/articles/SSIS/64014/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...