简体   繁体   English

SSIS package 在使用 SQL 服务器代理启动时无法使用 C# 脚本任务处理所有行

[英]SSIS package fails to process all rows with C# Script task when started with SQL Server Agent

I have a requirement to build a SSIS package that sends HTML formatted emails and then saves the emails as tiff files.我需要构建一个 SSIS package 发送 HTML 格式的电子邮件,然后将电子邮件保存为 tiff 文件。 I have created a script task that processes the necessary records and then coverts the HTML code to the tiff.我创建了一个脚本任务来处理必要的记录,然后将 HTML 代码转换为 tiff。 I have split the process into separate packages, the email send works fine the converting HTML to tiff is causing the issue.我已将该过程拆分为单独的包,email 发送工作正常,将 HTML 转换为 tiff 是导致问题的原因。

When running the package manually it will process all files without any issues.手动运行 package 时,它将毫无问题地处理所有文件。 my test currently is about 315 files this needs to be able to process at least 1,000 when finished with the ability to send up to 10,000 at one time.我的测试目前大约有 315 个文件,这需要能够处理至少 1,000 个,同时能够一次发送多达 10,000 个。 The problem is when I set the package to execute using SQL Server Agent it stops at 207 files.问题是当我将 package 设置为使用 SQL 服务器代理执行时,它在 207 个文件处停止。 The package is deployed to SQL Server 2019 in the SSIS Catalog package部署到SSIS Catalog中的SQL Server 2019

服务器版本和资源

What I have tried so far到目前为止我尝试了什么

I started with the script being placed in a SSIS package and deployed to the server and calling the package from a step (works 99.999999% of the time with all packages) tried both 32 and 64 bit runtime.我开始将脚本放置在 SSIS package 中并部署到服务器并从一个步骤调用 package(99.999999% 的时间适用于所有包)尝试了 32 位和 64 位运行时。 Never any error messages just Unexpected Termination when looking at the execution reports.在查看执行报告时,从来没有任何错误消息只是意外终止。 When clicking in the catalog and executing package it will process all the files.单击目录并执行 package 时,它将处理所有文件。 The SQL Server Agent is using a proxy and I also created another proxy account with my admin credentials to test for any issues with the account. SQL 服务器代理正在使用代理,我还使用我的管理员凭据创建了另一个代理帐户来测试该帐户是否存在任何问题。

Created another package to call the package and used the Execute Package Task to call the first package, same result 207 files.创建另一个 package 调用 package 并使用执行 Package 任务调用第一个 package,结果相同 207 个文件。 Changed the execute Process task to an Execute SQL Task and tried the script that is created to manually start a package in the catalog 207 files.将执行进程任务更改为执行 SQL 任务,并尝试创建用于手动启动目录 207 文件中的 package 的脚本。 Tried executing the script from the command line both through the other SSIS package and the SQL Server Agent directly same results 207 files.尝试通过其他 SSIS package 和 SQL 服务器代理直接从命令行执行脚本,结果相同 207 个文件。 If I try any of those methods directly outside SQL Server Agent the process runs no issues.如果我直接在 SQL Server Agent 之外尝试这些方法中的任何一种,该过程运行没有问题。

I converted the script task to a console application and it works processing all the files.我将脚本任务转换为控制台应用程序,它可以处理所有文件。 When calling the executable file from any method from the SQL Server Agent it once again stops at the 207 files.当从 SQL 服务器代理的任何方法调用可执行文件时,它再次停止在 207 个文件处。

I have consulted with the companies DBA and Systems teams and they have not found anything that could be causing this error.我咨询了公司的 DBA 和系统团队,他们没有发现任何可能导致此错误的原因。 There seems to be some type of limit that no matter the method of execution SQL Server Agent will not allow.似乎有某种类型的限制,无论执行方法如何 SQL 服务器代理都不允许。 I have mentioned looking at third-party applications but have been told no.我提到过查看第三方应用程序,但被告知不行。

I have included the code below that I have been able to piece together.我在下面包含了我能够拼凑的代码。 I am a SQL developer so C# is outside my knowledge base.我是 SQL 开发人员,所以 C# 不在我的知识库之内。 Is there a way to optimize the code so it only uses one thread or does a cleanup between each letter.有没有一种方法可以优化代码,使其只使用一个线程或在每个字母之间进行清理。 There may be a need for this to create over ten thousand letters at certain times.在某些时候可能需要创建超过一万个字母。

Update更新

I have replaced the code with the new updated code.我已经用新的更新代码替换了代码。 The email and image creation are all included as this is what the final product must do. email 和图像创建都包含在内,因为这是最终产品必须做的。 When sending the emails there is a primary and secondary email address and depending on what email address is used it will change what the body of the email contains.发送电子邮件时,有一个主要和次要的 email 地址,根据使用的 email 地址,它会更改 email 的正文包含的内容。 When looking at the code there is a section of try catch that sends to primary when indicated to and if that fails it send to secondary instead.在查看代码时,有一段 try catch 会在指示时发送到主节点,如果失败则发送到辅助节点。 I am guessing there is a much cleaner way of doing that section but this is my first program as I work in SQL for everything else.我猜想有一种更简洁的方法来完成该部分,但这是我的第一个程序,因为我在 SQL 中处理其他所有内容。

Thank You for all the suggestions and help.感谢您的所有建议和帮助。

Updated Code更新代码

using System;
using System.Data;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.Threading;
using System.Threading.Tasks;
using System.Drawing;
using System.IO;
using System.Net.Mail;
using System.Configuration;
using System.Diagnostics;

namespace DocCreator
{

    class Program
    {
        static void Main(string[] args)
        {
            var connSSIS = ConfigurationManager.ConnectionStrings["ssis_ssrs"].ConnectionString;
            int logid = 0;
            int count = 0;
            string previous = "";
            try
            {
                var connDataExtract = ConfigurationManager.ConnectionStrings["dataExtract"].ConnectionString;
                string archiveFolder = @"Folder Path";
                string project = "Mobile Pay";
                string logProc = "[dbo].[usp_EmailSentandError]";
                int rowCount = 0;
                DataTable dt = new DataTable();
                using (SqlConnection connLog = new SqlConnection(connDataExtract))
                {
                    connLog.Open();
                    SqlCommand command = new SqlCommand("etl.usp_GetEmailListID", connLog)
                    {
                        CommandType = CommandType.StoredProcedure
                    };
                    command.Parameters.Add("@Project", SqlDbType.NText).Value = project;
                    command.Parameters.Add("@NullValue", SqlDbType.Int).Value = 0;
                    using (SqlDataReader dr = command.ExecuteReader())
                    {
                        dt.Load(dr);
                    }
                    connLog.Close();
                }
               foreach (DataRow dr in dt.Rows)
                //Parallel.ForEach(dt.AsEnumerable(), dr =>
                {

                    try
                    {
                        var emailID = dr["Email_ID"];
                        var usePrimary = dr["UsePrimaryEmail"];
                        try
                        {
                            if ((bool)usePrimary)
                            {
                                try
                                {
                                    var dp = GetDataPoints(connDataExtract, (int)emailID, (bool)usePrimary);
                                    string indexfqdn = Path.Combine(archiveFolder, dp.IndexFile);
                                    string filefqdn = Path.Combine(archiveFolder, dp.ArchiveFileName);
                                    string mailBody = GetEmailBody(connDataExtract, dp.SqlProc, (int)emailID, dp.EmailBody_id);
                                    SendEmail(dp.EmailFrom, dp.EmailSubject, dp.Email, mailBody);
                                    Archive(mailBody, filefqdn, dp.FileWidth, dp.FileHeight, dp.IndexFileInsert, indexfqdn, dp.ArchiveFile);
                                    LogEmail(connDataExtract, logProc, (int)emailID, dp.EmailBody_id, 1, 1, "", 0);
                                    rowCount++;
                                }
                                catch (Exception e)
                                {
                                    try
                                    {
                                        var dp = GetDataPoints(connDataExtract, (int)emailID, false);
                                        string indexfqdn = Path.Combine(archiveFolder, dp.IndexFile);
                                        string filefqdn = Path.Combine(archiveFolder, dp.ArchiveFileName);
                                        string mailBody = GetEmailBody(connDataExtract, dp.SqlProc, (int)emailID, dp.EmailBody_id);
                                        SendEmail(dp.EmailFrom, dp.EmailSubject, dp.Email, mailBody);
                                        Archive(mailBody, filefqdn, dp.FileWidth, dp.FileHeight, dp.IndexFileInsert, indexfqdn, dp.ArchiveFile);
                                        LogEmail(connDataExtract, logProc, (int)emailID, dp.EmailBody_id, 0, 1, e.Message.ToString(), 1);
                                        rowCount++;
                                    }
                                    catch (Exception e2)
                                    {
                                        LogEmail(connDataExtract, logProc, (int)emailID, 0, 0, 0, e2.Message.ToString(), 1);
                                        Console.Clear();
                                        Console.WriteLine(e2.Message);
                                        Console.ReadLine();
                                    }
                                }
                            }
                            else
                            {
                                try
                                {
                                    var dp = GetDataPoints(connDataExtract, (int)emailID, (bool)usePrimary);
                                    string indexfqdn = Path.Combine(archiveFolder, dp.IndexFile);
                                    string filefqdn = Path.Combine(archiveFolder, dp.ArchiveFileName);
                                    string mailBody = GetEmailBody(connDataExtract, dp.SqlProc, (int)emailID, dp.EmailBody_id);
                                    SendEmail(dp.EmailFrom, dp.EmailSubject, dp.Email, mailBody);
                                    Archive(mailBody, filefqdn, dp.FileWidth, dp.FileHeight, dp.IndexFileInsert, indexfqdn, dp.ArchiveFile);
                                    LogEmail(connDataExtract, logProc, (int)emailID, dp.EmailBody_id, 0, 1, "", 0);
                                    rowCount++;
                                }
                                catch (Exception e)
                                {
                                    LogEmail(connDataExtract, logProc, (int)emailID, 0, 0, 0, e.Message.ToString(), 1);
                                    Console.Clear();
                                    Console.WriteLine(e.Message);
                                    Console.ReadLine();
                                }
                            }
                        }
                        catch (Exception e)
                        {
                            LogEmail(connDataExtract, logProc, (int)emailID, 0, 0, 0, e.Message.ToString(), 1);
                            Console.Clear();
                            Console.WriteLine(e.Message);
                            Console.ReadLine();
                        }
                    }


                    catch (Exception e2)
                    {
                        //Console.WriteLine(e2.Message);
                        using (SqlConnection connLog2 = new SqlConnection(connSSIS))
                        {
                            connLog2.Open();
                            SqlCommand command2 = new SqlCommand("dbo.usp_InsertssisScriptTaskLog", connLog2)
                            {
                                CommandType = CommandType.StoredProcedure
                            };
                            command2.Parameters.Add("@PackageLogID", SqlDbType.Int).Value = ((ulong)logid);
                            command2.Parameters.Add("@ErrorMessage", SqlDbType.NText).Value = e2.Message.ToString();
                            command2.ExecuteNonQuery();
                            connLog2.Close();
                        }
                    }

                    count++;
                    int directThreadsCount = Process.GetCurrentProcess().Threads.Count;
                    Console.Clear();
                    Console.WriteLine(previous + Environment.NewLine+ count + "  Memory usage: " + GC.GetTotalMemory(false) + "     "  + GC.GetTotalMemory(true)  + "  Threads: " + directThreadsCount);
                    previous = count + "  Memory usage: " + GC.GetTotalMemory(false) + "     "  + GC.GetTotalMemory(true) + "  Threads: " + directThreadsCount;
                    GC.Collect(1);
                }
                Console.WriteLine("Files have been created");

            }
            catch (Exception e)
            {
                //Console.WriteLine(e.Message);
                using (SqlConnection connLog = new SqlConnection(connSSIS))
                {
                    connLog.Open();
                    SqlCommand command = new SqlCommand("dbo.usp_InsertssisScriptTaskLog", connLog)
                    {
                        CommandType = CommandType.StoredProcedure
                    };
                    command.Parameters.Add("@PackageLogID", SqlDbType.Int).Value = ((ulong)logid);
                    command.Parameters.Add("@ErrorMessage", SqlDbType.NText).Value = e.Message.ToString();
                    command.ExecuteNonQuery();
                    connLog.Close();
                }
            }
        }

        public static
        (int EmailBody_id, bool ArchiveFile, int FileHeight, int FileWidth, string IndexFile, string IndexFileInsert, string Email, string ArchiveFileName, string EmailFrom, string EmailSubject, string SqlProc)
            GetDataPoints(string connDataExtract, int Email_ID, bool UsePrimary)
        {
            string dataExtract = connDataExtract;
            int emailID = Email_ID;
            bool usePri = UsePrimary;
            using (SqlConnection connLog = new SqlConnection(dataExtract))
            {
                connLog.Open();
                SqlCommand command = new SqlCommand("etl.usp_EmailGetDataPoints", connLog)
                {
                    CommandType = CommandType.StoredProcedure
                };
                command.Parameters.Add("@Email_ID", SqlDbType.Int).Value = emailID;
                command.Parameters.Add("@UsePrimary", SqlDbType.Bit).Value = usePri;
                SqlDataReader sqlDataReader;
                int EmailBody_id = 0;
                bool ArchiveFile = true;
                int FileHeight = 0;
                int FileWidth = 0;
                string IndexFile = "";
                string IndexFileInsert = "";
                string Email = "";
                string ArchiveFileName = "";
                string EmailFrom = "";
                string EmailSubject = "";
                string SqlProc = "";
                sqlDataReader = command.ExecuteReader();
                while (sqlDataReader.Read())
                {
                    EmailBody_id = (int)sqlDataReader.GetValue(sqlDataReader.GetOrdinal("EmailBody_ID"));
                    ArchiveFile = (bool)sqlDataReader.GetValue(sqlDataReader.GetOrdinal("ArchiveFile"));
                    FileHeight = (int)sqlDataReader.GetValue(sqlDataReader.GetOrdinal("FileHeight"));
                    FileWidth = (int)sqlDataReader.GetValue(sqlDataReader.GetOrdinal("FileWidth"));
                    IndexFile = sqlDataReader.GetValue(sqlDataReader.GetOrdinal("IndexFile")).ToString();
                    IndexFileInsert = sqlDataReader.GetValue(sqlDataReader.GetOrdinal("IndexFileInsert")).ToString();
                    Email = sqlDataReader.GetValue(sqlDataReader.GetOrdinal("Email")).ToString();
                    ArchiveFileName = sqlDataReader.GetValue(sqlDataReader.GetOrdinal("ArchiveFileName")).ToString();
                    EmailFrom = sqlDataReader.GetValue(sqlDataReader.GetOrdinal("EmailFrom")).ToString();
                    EmailSubject = sqlDataReader.GetValue(sqlDataReader.GetOrdinal("EmailSubject")).ToString();
                    SqlProc = sqlDataReader.GetValue(sqlDataReader.GetOrdinal("SqlProc")).ToString();
                }
                connLog.Close();
                return (
                    EmailBody_id,
                    ArchiveFile,
                    FileHeight,
                    FileWidth,
                    IndexFile,
                    IndexFileInsert,
                    Email,
                    ArchiveFileName,
                    EmailFrom,
                    EmailSubject,
                    SqlProc);
            }
        }
        public static string GetEmailBody(string connDataExtract, string SQLProc, int Email_ID, int EmailBodyID)
        {
            string dataExtract = connDataExtract;
            string proc = SQLProc;
            int emailID = Email_ID;
            int bodyID = EmailBodyID;
            string MailBody;
            using (SqlConnection connLog = new SqlConnection(dataExtract))
            {
                connLog.Open();
                SqlCommand command = new SqlCommand(proc, connLog)
                {
                    CommandType = CommandType.StoredProcedure
                };
                command.Parameters.Add("@Email_ID", SqlDbType.Int).Value = ((ulong)emailID);
                command.Parameters.Add("@EmailBody_ID", SqlDbType.Int).Value = ((ulong)bodyID);
                SqlDataReader dataReader;
                string Output = "";
                dataReader = command.ExecuteReader();
                while (dataReader.Read())
                {
                    Output = dataReader.GetValue(0).ToString();
                }
                connLog.Close();
                MailBody = Output;
                return MailBody;
            }
        }
        public static void SendEmail(string emailFrom, string emailSubject, string emailTo, string mailBody)
        {
            string from = emailFrom;
            string subject = emailSubject;
            string to = emailTo;
            string source = mailBody;
            using (MailMessage myHtmlFormattedMail = new MailMessage())
            {
                MailAddress fromMail = new MailAddress(from);
                myHtmlFormattedMail.From = fromMail;
                myHtmlFormattedMail.Subject = subject;
                myHtmlFormattedMail.Body = source;
                foreach (var address in to.Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries))
                {
                    myHtmlFormattedMail.To.Add(address);
                }
                myHtmlFormattedMail.IsBodyHtml = true;
                SmtpClient mySmtpClient = new SmtpClient();
                mySmtpClient.Send(myHtmlFormattedMail);
            }
        }
        public static void IndexFile(string indexFileInsert, string indexfqdn)
        {
            string insert = indexFileInsert;
            string fqdn = indexfqdn;
            try
            {
                if (!File.Exists(fqdn))
                {
                    using (StreamWriter sw = File.CreateText(fqdn))
                    {
                        sw.WriteLine(insert);
                    }
                }
                using (StreamWriter sw = File.AppendText(fqdn))
                {
                    sw.WriteLine(insert);
                }
            }
            catch { }
        }
        public static void LogEmail(string databaseServer, string logProc, int email_ID, int emailBodyID, int primaryEmailUsed, int emailSent, string errorMessage, int errorExists)
        {
            string dataExtract = databaseServer;
            string proc = logProc;
            int emailID = email_ID;
            int bodyID = emailBodyID;
            int usePri = primaryEmailUsed;
            int sent = emailSent;
            string error = errorMessage;
            int exists = errorExists;
            using (SqlConnection connLog = new SqlConnection(dataExtract))
            {
                connLog.Open();
                SqlCommand command = new SqlCommand(proc, connLog)
                {
                    CommandType = CommandType.StoredProcedure
                };
                command.Parameters.Add("@Email_ID", SqlDbType.Int).Value = ((ulong)emailID);
                command.Parameters.Add("@EmailBody_ID", SqlDbType.Int).Value = ((ulong)bodyID);
                command.Parameters.Add("@PrimaryEmailUsed", SqlDbType.Int).Value = ((ulong)usePri);
                command.Parameters.Add("@EmailSent", SqlDbType.Int).Value = ((ulong)sent);
                command.Parameters.Add("@ErrorMessage", SqlDbType.NText).Value = error;
                command.Parameters.Add("@ErrorExists", SqlDbType.Int).Value = ((ulong)exists);
                command.ExecuteNonQuery();
                connLog.Close();
            }
        }
        public static void StartBrowser(string mailBody, string file, int width, int height, string fileInsert, string indexFile)
        {
            try
            {
                string source = mailBody;
                string fqdn = file;
                int w = width;
                int h = height;
                string insert = fileInsert;
                string indexFQDN = indexFile;
                IndexFile(insert, indexFQDN);
                using (WebBrowser wb = new WebBrowser())
                {
                    wb.ScrollBarsEnabled = false;
                    wb.Width = w;
                    wb.Height = h;
                    wb.Visible = false;
                    wb.DocumentCompleted +=
                         (sender, e) => WebBrowser_DocumentCompleted(sender, e, fqdn);
                    wb.DocumentText = source;
                    Application.Run();
                }
            }
            finally 
            {
                Application.Exit();
            }
        }
        public static void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e, string file)
        {
            string fqdn = file;
            var webBrowser = (WebBrowser)sender;
            using (Bitmap bitmap = new Bitmap(webBrowser.Width, webBrowser.Height))
            {
                webBrowser
                    .DrawToBitmap(bitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height));
                bitmap.Save(fqdn, System.Drawing.Imaging.ImageFormat.Jpeg);
            }
        }
        static void Wait(int milliseconds)
        {
            using (System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer())
            {
                if (milliseconds == 0 || milliseconds < 0) return;

                // Console.WriteLine("start wait timer");
                timer1.Interval = milliseconds;
                timer1.Enabled = true;
                timer1.Start();

                timer1.Tick += (s, e) =>
                {
                    timer1.Enabled = false;
                    timer1.Stop();
                // Console.WriteLine("stop wait timer");
            };

                while (timer1.Enabled)
                {
                    System.Windows.Forms.Application.DoEvents();
                }
            }
        }
        public static void Archive(string emailBody, string file, int width, int height, string fileInsert, string indexFile, bool archiveFile)
        {
            string source = emailBody;
            string fqdn = file;
            int w = width;
            int h = height;
            string insert = fileInsert;
            string indexFQDN = indexFile;
            bool archive = archiveFile;
            if (archive)
            {
                Thread tr = new Thread(() => StartBrowser(source, fqdn, w, h, insert, indexFQDN))
                    {
                        Name = "Fred",
                        IsBackground = true
                    };
                    tr.SetApartmentState(ApartmentState.STA);
                    tr.Start();

                int wc = 800;
                while (!File.Exists(file) || wc <= 0)
                {
                    Wait(50);
                    wc--;
                };
                tr.Abort();
            }
        }

    }
}

I have resolved the issue so it meets the needs of my project.我已经解决了这个问题,所以它满足了我的项目的需要。 There is probably a better solution but this does work.可能有更好的解决方案,但这确实有效。 Using the code above I created an executable file and limited the result set to top 100. Created a ssis package with a For Loop that does a record count from the staging table and kicks off the executable file.使用上面的代码,我创建了一个可执行文件并将结果集限制为前 100 个。创建了一个 ssis package 和一个 For 循环,该循环从暂存表中计算记录并启动可执行文件。 I performed several tests and was able to exceed the 10,000 limit that was a requirement to the project.我进行了几次测试,并且能够超过项目要求的 10,000 个限制。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从SQL Server代理作业调用的SSIS包的C#脚本组件上的错误 - Error on C# script component of an SSIS package callled from an SQL Server agent Job 通过SQL Server代理在SSIS包中运行的C#脚本有时会触发调用目标抛出的异常 - C# script run in SSIS package through SQL Server Agent sometimes triggers Exception has been thrown by the target of an invocation 以编程方式创建在C#中运行SSIS包的SQL代理作业 - Programmatically create SQL Agent Job running SSIS package in C# SQL Server代理作业 - SSIS - C# - “访问被拒绝。 “当试图删除文件时 - SQL Server Agent Job - SSIS - C# - “Access denied. ” when trying to delete files SSIS Package 脚本任务运行失败 - SSIS Package Fails To Run With Script Task SSIS 2012 C#脚本任务数据源-行无数据 - SSIS 2012 C# script task data source - No data for Rows SSIS:C#脚本任务:如何根据运行dtsx的服务器环境更改SQL连接字符串? - SSIS: C# Script task: How to change a SQL connection string based on server environment that the dtsx is running on? SSIS中的C#脚本任务 - C# script task in SSIS SSIS 包中的 C# 脚本在数据执行到 SQL Server 表的过程中挂起,没有明确的错误消息 - C# script in SSIS package hangs in the middle of data implementation to SQL Server table with no clear error message SSIS脚本任务和SQL批量插入的问题-C# - Issues with SSIS Script Task and SQL Bulk Insert - C#
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM