gpt4 book ai didi

关于 SlidingInvisibilityTimeout 的 Hangfire 澄清

转载 作者:行者123 更新时间:2023-12-03 17:32:45 24 4
gpt4 key购买 nike

hangfire 文档指出:

One of the main disadvantage of raw SQL Server job storage implementation – it uses the polling technique to fetch new jobs. Starting from Hangfire 1.7.0 it’s possible to use TimeSpan.Zero as a polling interval, when SlidingInvisibilityTimeout option is set.


我按照建议使用这些 SqlServerStorageOptions:
var options = new SqlServerStorageOptions
{
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero
};
它没有说明 SlidingInvisibilityTimeout 的实际含义,谁能澄清一下?
我的情况是,我每天早上有大约 1000 封电子邮件要发送,而且我一直在突破每分钟 30 封邮件的 Office365 限制并被拒绝,所以我使用 Hangfire 将它们排在一个工作线程中,并添加了一个每个任务结束时 2 秒 Thread.Sleep。这很好用,但由于hangfire( as reported here )导致CPU使用率增加了约20%,并且在服务器繁忙时导致频繁超时。
我试图实现的行为是:
  • 在每项工作结束时,立即检查是否还有另一项工作并进行下一项任务。
  • 如果队列中没有作业,请在 5 分钟后回来检查,直到那时才接触 SQL 服务器。

  • 感谢您的帮助。

    最佳答案

    最后,我编写了一个轻量级的替代方法,在 while 循环中使用线程来监视包含带有电子邮件参数的序列化对象的文本文件的文件夹。它几乎没有开销并符合 office365 限制策略。在这里发布以防对其他人有用,为asp.net构建并且应该很容易适应其他场景。

    using Newtonsoft.Json;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Threading;
    using System.Web.Hosting;

    namespace Whatever
    {
    public class EmailerThread
    {
    public delegate void Worker();
    private static Thread worker; // one worker thread for this application // https://stackoverflow.com/questions/1824933/right-way-to-create-thread-in-asp-net-web-application
    public static string emailFolder;
    public static int ScanIntervalMS = 2000; // office365 allows for 30 messages in a 60 second window, a 2 second delay plus the processing time required to connect & send each message should safely avoid the throttling restrictions.

    /// <summary>
    /// Must be invoked from Application_Start to ensure the thread is always running, if the applicationpool recycles etc
    /// </summary>
    public static void Init()
    {
    // create the folder used to store serialized files for each email to be sent
    emailFolder = Path.Combine(HostingEnvironment.ApplicationPhysicalPath, "App_Data", "_EmailOutbox");
    Directory.CreateDirectory(emailFolder);

    worker = new Thread(new ThreadStart(new Worker(ScanForEmails)));
    worker.Start();
    }

    /// <summary>
    /// Serialize an object containing all the email parameters to a text file
    /// Call this object
    /// </summary>
    /// <param name="e"></param>
    public static void QueueEmail(EmailParametersContainer e)
    {
    string filename = Guid.NewGuid().ToString() + ".txt";
    File.WriteAllText(Path.Combine(emailFolder, filename), JsonConvert.SerializeObject(e));
    }

    public static void ScanForEmails()
    {
    var client = new System.Net.Mail.SmtpClient(Settings.SmtpServer, 587);
    client.EnableSsl = true;
    client.UseDefaultCredentials = false;
    client.DeliveryMethod = SmtpDeliveryMethod.Network;
    client.Credentials = new System.Net.NetworkCredential(Settings.smtpUser, Settings.smtpPass);
    client.Timeout = 5 * 60 * 1000; // 5 minutes

    // infinite loop to keep scanning for files
    while (true)
    {
    // take the oldest file in the folder and process it for sending
    var nextFile = new DirectoryInfo(emailFolder).GetFiles("*.txt", SearchOption.TopDirectoryOnly).OrderBy(z => z.CreationTime).FirstOrDefault();
    if (nextFile != null)
    {
    // deserialize the file
    EmailParametersContainer e = JsonConvert.DeserializeObject<EmailParametersContainer>(File.ReadAllText(nextFile.FullName));
    if (e != null)
    {
    try
    {
    MailMessage msg = new MailMessage();
    AddEmailRecipients(msg, e.To, e.CC, e.BCC);
    msg.From = new MailAddress(smtpUser);
    msg.Subject = e.Subject;
    msg.IsBodyHtml = e.HtmlFormat;
    msg.Body = e.MessageText;

    if (e.FilePaths != null && e.FilePaths.Count > 0)
    foreach (string file in e.FilePaths)
    if (!String.IsNullOrEmpty(file) && File.Exists(file))
    msg.Attachments.Add(new Attachment(file));

    client.Send(msg);
    msg.Dispose();

    // delete the text file now that the job has successfully completed
    nextFile.Delete();
    }
    catch (Exception ex)
    {
    // Log the error however suits...

    // rename the .txt file to a .fail file so that it stays in the folder but will not keep trying to send a problematic email (e.g. bad recipients or attachment size rejected)
    nextFile.MoveTo(nextFile.FullName.Replace(".txt", ".fail"));
    }
    }
    }
    Thread.Sleep(ScanIntervalMS); // wait for the required time before looking for another job
    }
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="msg"></param>
    /// <param name="Recipients">Separated by ; or , or \n or space</param>
    public static void AddEmailRecipients(MailMessage msg, string To, string CC, string BCC)
    {
    string[] list;
    if (!String.IsNullOrEmpty(To))
    {
    list = To.Split(";, \n".ToCharArray());
    foreach (string email in list)
    if (email.Trim() != "" && ValidateEmail(email.Trim()))
    msg.To.Add(new MailAddress(email.Trim()));
    }
    if (!String.IsNullOrEmpty(CC))
    {
    list = CC.Split(";, \n".ToCharArray());
    foreach (string email in list)
    if (email.Trim() != "" && ValidateEmail(email.Trim()))
    msg.CC.Add(new MailAddress(email.Trim()));
    }
    if (!String.IsNullOrEmpty(BCC))
    {
    list = BCC.Split(";, \n".ToCharArray());
    foreach (string email in list)
    if (email.Trim() != "" && ValidateEmail(email.Trim()))
    msg.Bcc.Add(new MailAddress(email.Trim()));
    }
    }


    public static bool ValidateEmail(string email)
    {
    if (email.Contains(" ")) { return false; }

    try
    {
    // rely on the .Net framework to validate the email address, rather than attempting some crazy regex
    var m = new MailAddress(email);
    return true;
    }
    catch
    {
    return false;
    }
    }
    }

    public class EmailParametersContainer
    {
    public string To { get; set; }
    public string Cc { get; set; }
    public string Bcc { get; set; }
    public string Subject { get; set; }
    public string MessageText { get; set; }
    public List<string> FilePaths { get; set; }
    public bool HtmlFormat { get; set; }
    }
    }

    关于关于 SlidingInvisibilityTimeout 的 Hangfire 澄清,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59073676/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com