¿Cómo evitar que la tarea FTP de SSIS falle cuando no hay archivos para descargar?

Estoy usando SQL Server 2005 y creando tareas ftp dentro de SSIS.

A veces habrá archivos para descargar, a veces no. Si no hay archivos, no quiero que la tarea ni el paquete fallen. Cambié la flecha de la tarea ftp a la siguiente a “finalización”, por lo que el paquete se ejecuta. Cambié el número permitido de errores a 4 (porque hay tareas de 4 ftp, y cualquiera de los 4 directorios puede tener o no archivos).

Pero cuando ejecuto el paquete desde un trabajo en agente, marca el trabajo como un error. Como esto se ejecutará cada 15 minutos, no quiero un montón de x rojas en mi historial de trabajo, lo que hará que no veamos un problema cuando realmente ocurra.

¿Cómo configuro las propiedades en la tarea ftp para que no encontrar un archivo en ftp no sea un error? La operación que estoy usando es “Enviar archivos”.

Aquí hay algo más de información: los archivos están en un servidor al que no tengo acceso excepto ftp. Y, no sé los nombres de los archivos por adelantado. El usuario puede llamarlos lo que quieran. Entonces no puedo verificar archivos específicos, ni creo que pueda verificarlos en absoluto. Excepto a través del uso de la conexión ftp y las tareas basadas en esa conexión. Los archivos están en un servidor remoto y quiero copiarlos en mi servidor para obtenerlos de ese servidor remoto.

Puedo copiar un nivel de comando ftp en una tarea de script. Tal vez eso es lo que necesito usar en lugar de una tarea ftp. (He cambiado para usar la línea de comando ftp, con un archivo de parámetros, llamado desde una tarea de script. No da errores cuando no hay archivos para obtener. Creo que esta solución me va a funcionar. Estoy creando el archivo de parámetros dinámicamente, lo que significa que no necesito tener información de conexión en el archivo de texto plano, sino que puedo almacenarlo en mi archivo de configuración, que está en una ubicación más segura).

Entiendo que ha encontrado una respuesta a su pregunta. Esto es para otros usuarios que puedan tropezar con esta pregunta. Aquí hay una forma posible de lograr esto. Script Task se puede utilizar para buscar la lista de archivos presentes en una ruta de carpeta de FTP para un patrón determinado (digamos *.txt ). El siguiente ejemplo muestra cómo se puede hacer esto.

Proceso paso a paso:

  1. En el paquete SSIS, cree una FTP Connection denominada FTP y también cree 5 variables como se muestra en la captura de pantalla n. ° 1 . Variable RemotePath contiene la ruta de la carpeta FTP; LocalPath contiene la carpeta donde se LocalPath los archivos; FilePattern contiene el patrón de archivo para encontrar la lista de archivos para descargar del servidor FTP; FileName se completará con el Foreach loop container pero para evitar el error de tiempo de diseño de la tarea FTP, se puede completar con / o la propiedad DelayValidation en FTP. La tarea se puede establecer en True .

  2. En el paquete SSIS, coloque una Script Task , Foreach Loop container y una FTP Task dentro del Foreach Loop container como se muestra en las capturas de pantalla # 2 .

  3. Reemplace el método Main() dentro de la Script Task con el código en la sección Código de tarea de secuencia de comandos . La tarea de secuencia de comandos completará la variable ListOfFiles con la colección de archivos que coinciden con un patrón dado. Este ejemplo primero usará el patrón * .txt, que no arroja resultados y luego el patrón * .xls que coincidirá con algunos archivos en el servidor FTP.

  4. Configure el Foreach Loop container como se muestra en las capturas de pantalla # 3 y # 4 . Esta tarea recorrerá la variable ** ListOfFiles *. Si no hay archivos, la tarea FTP dentro del contenedor de bucle no se ejecutará. Si hay archivos, la tarea FTP dentro del contenedor de bucles se ejecutará para la tarea por la cantidad de archivos encontrados en el servidor FTP.

  5. Configure la FTP Task como se muestra en las capturas de pantalla # 5 y # 6 .

  6. La captura de pantalla # 7 muestra la ejecución del paquete de muestra cuando no se encuentran archivos coincidentes para el patrón *.txt .

  7. La captura de pantalla n. ° 8 muestra el contenido de la carpeta C:\temp\ antes de la ejecución del paquete.

  8. La captura de pantalla n. ° 9 muestra la ejecución del paquete de muestra cuando se encuentran los archivos coincidentes para el patrón *.xls .

  9. La captura de pantalla n. ° 10 muestra el contenido de la ruta remota de FTP /Practice/Directory_New .

  10. La captura de pantalla n. ° 11 muestra el contenido de la carpeta C:\temp\ después de la ejecución del paquete.

  11. La captura de pantalla n. ° 12 muestra la falla del paquete cuando se proporciona una ruta remota incorrecta.

  12. La captura de pantalla n. ° 13 muestra el mensaje de error relacionado con la falla del paquete.

Espero que ayude.

Código de tarea de script:

Código de C # que se puede usar en SSIS 2008 and above .

Incluya la instrucción using utilizando 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; } 

Código VB que se puede usar en SSIS 2005 and above .

Incluir la statement de importaciones 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 

Captura de pantalla n. ° 1:

1

Captura de pantalla n. ° 2:

2

Captura de pantalla n. ° 3:

3

Captura de pantalla n. ° 4:

4

Captura de pantalla n. ° 5:

5

Captura de pantalla n.º 6:

6

Captura de pantalla n. ° 7:

7

Captura de pantalla n. ° 8:

8

Captura de pantalla n. ° 9:

9

Captura de pantalla n. ° 10:

10

Captura de pantalla n. ° 11:

11

Captura de pantalla n.º 12:

12

Captura de pantalla n.º 13:

13

Consulte este enlace que describe acerca del manejo elegante de errores de tareas en el paquete SSIS.

Casi tuve el mismo problema pero, al recuperar archivos. Quería que el paquete NO fallara cuando no se encontraran archivos en el servidor FTP. El enlace de arriba detiene el error de burbujeo y hace que el paquete falle; algo que hubieras pensado que FailPackageOnError = false debería haber hecho? : -S

Espero que esto lo resuelva por ti también!

Acabo de tener este problema, después de leer algunas de las respuestas aquí, nada realmente resolvió mi problema y las soluciones aquí parecen locos en términos de complejidad.

Mi tarea de FTP estaba fallando ya que no permití que se sobrescribieran los archivos, digamos que el trabajo se inició dos veces seguidas, el primer pase será correcto, porque algunos archivos se transfieren pero fallarán si ya existe un archivo local.

Mi solución fue simple:

  1. Haga clic derecho en la tarea – Propiedades
  2. Establecer ForceExecutionResult = “Success”

(No puedo aceptar mi propia respuesta, pero esta fue la solución que funcionó para mí).

Puede que no sea la mejor solución, pero esto funciona.

Utilizo una tarea de script y tengo un conjunto de variables para la información de conexión ftp y directorios de origen y destino. (Porque vamos a cambiar el servidor en el que se ejecuta y será más fácil cambiarlo en un paquete de configuración).

Creo un archivo de texto sobre la marcha y escribo los comandos de 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() 

Luego, después de darle suficiente tiempo para realmente cerrar, comienzo un proceso para hacer el comando ftp:

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

Luego, después de darle más tiempo para que se ejecute el proceso ftp, elimino el archivo ftp temporal (¡que tiene información de conexión!).

Si los archivos no existen en el directorio de origen (la variable tiene la asignación \\ drive \ dir \ *. *), Entonces no hay ningún error. Si ocurre algún otro error, la tarea aún falla, como debería.

Soy nuevo en SSIS, y esto puede ser un error. Pero funciona por ahora. Supongo que pedí la mejor manera, y ciertamente no afirmaré que esto es todo.

Como señalé, no tengo manera de saber cómo se nombran los archivos, o incluso si hay algún archivo allí. Si están allí, quiero obtenerlos.

No tengo una respuesta empaquetada para usted, pero como nadie más ha publicado nada aún …

Debería poder establecer una variable en una tarea de script ActiveX y luego usarla para decidir si la tarea FTP debe ejecutarse o no. Aquí hay un ejemplo que funciona con rutas locales. Con suerte, puede adaptar el concepto (o si es posible, asignar el disco FTP y hacerlo de esa manera).

1) Establezca la propiedad Tarea FTP ForceExecutionResult = Success

2) Agregue este código al controlador de eventos 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; } 

Ponlo en un contenedor ForEach, que itera sobre los archivos para cargar. Sin archivos, sin FTP, sin falla.

Puede redirigir en caso de error, a otra tarea que no hace nada, es decir, un script que simplemente devuelve verdadero.

Para ello, agregue la nueva tarea de secuencia de comandos, resalte su tarea de FTP, aparecerá un segundo conector verde, arrástrelo a la tarea de secuencia de comandos y haga doble clic en ella. Seleccione Fallo en el menú desplegable Valor. Obviamente, tendrá que manejar las fallas reales en esta tarea de script para que se visualice correctamente en el historial de Job.

Aha, OK – Gracias por aclararme. Como la tarea FTP no puede devolver una lista de carpetas, no será posible utilizar ForEach como dije inicialmente: eso solo funciona si está cargando una cantidad X de archivos a una fuente remota.

Para descargar una cantidad X de archivos, puede ir de dos maneras, puede hacerlo completamente en .Net en una tarea de script, o puede llenar una ArrayList con los nombres de archivo desde una tarea de script .Net, luego ForEach sobre ArrayList , pasando el nombre del archivo a una variable y descargando ese nombre de variable en una tarea FTP estándar.

Ejemplo de código para adaptarse: http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=2472491&SiteID=1

Entonces, en lo anterior, obtendría los FileNames () y rellenaría ArrayList a partir de eso, luego asignaría ArrayList a una variable de tipo Object en Dts.Variables, y luego ForEach sobre esa variable Object (ArrayList) usando código algo así como: http : //www.sqlservercentral.com/articles/SSIS/64014/

Puede usar la Tarea FTP gratuita SSIS ++ de eaSkills. No arroja un error si el archivo o los archivos no existen, admite comodines y le ofrece la opción de descargar y eliminar si necesita hacerlo.

Aquí está el enlace a la página de características: http://www.easkills.com/ssis/ftptask

Esta es otra solución que funciona para mí, usa cosas integradas y así sin reescribir manualmente la lógica de FTP:

1) Crea una variable en tu paquete llamada FTP_Error

2) Haga clic en su tarea de FTP, luego haga clic en la pestaña “Controladores de eventos”

3) Haga clic dentro de la página para crear un controlador de eventos para “FTP Task / OnError”: se activará siempre que haya problemas con el FTP.

4) Desde la caja de herramientas, arrastre en un elemento Tarea de Script, y haga doble clic para abrirlo

5) En la primera ventana emergente, ReadOnlyVariables – agregar System :: ErrorCode, System :: ErrorDescription

6) En la primera ventana emergente, ReadWriteVariables: agregue su variable User :: FTP_Error

7) Editar guión

8) En el script configure su variable FTP_Error para contener los ReadOnlyVariables que teníamos arriba:

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

9) Guardar y cerrar script

10) Presiona “OK” para guiar la tarea

11) Regrese a la pestaña “Control de flujo”

12) Desde la tarea FTP, OnError ir a una nueva tarea de Script, y editar esa

13) ReadOnlyVariables: User :: FTP_Error desde antes

14) Ahora, cuando no se encuentran archivos en el FTP, el código de error es -1073573501 (aquí puede encontrar la lista de referencias del código de error: http://msdn.microsoft.com/en-us/library/ms345164.aspx )

15) En su secuencia de comandos, ingrese la lógica para hacer lo que quiera; si encuentra un código que dice “no se encontraron archivos”, entonces tal vez diga que la tarea fue exitosa. Si no, entonces la tarea falló. Y su flujo normal puede manejar esto como lo desee:

 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; } 

Y a partir de ahí, su flujo satisfactorio / fallido hará lo que quiera con él.

Una alternativa es usar este archivo FTP Enumerator enter image description here