- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
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.
var options = new SqlServerStorageOptions
{
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero
};
它没有说明 SlidingInvisibilityTimeout 的实际含义,谁能澄清一下?
最佳答案
最后,我编写了一个轻量级的替代方法,在 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/
我有一个非常复杂的 sql 脚本来清理我的数据库,并且会不时手动运行。脚本运行后,我必须立即启动一个经常性的 hangfire 作业,该作业通常每天只执行一次。 为了不忘记运行脚本,我想直接从sql脚
我有 2 个 hangfire 实例/服务器在运行。两者都指向同一个 hangfire 数据库。如何限制其中一个 hangfire 实例仅从特定队列中获取作业并忽略其他队列? 谢谢 最佳答案 启动实例
我有 2 个 hangfire 实例/服务器在运行。两者都指向同一个 hangfire 数据库。如何限制其中一个 hangfire 实例仅从特定队列中获取作业并忽略其他队列? 谢谢 最佳答案 启动实例
我在使用相同数据库的两台服务器上运行了几个 Hangfire 实例。每个实例根据基于服务器名称的某些标准提交要运行的作业,以便没有两个实例运行相同的作业。我注意到它们正在运行相同的作业,这意味着当一个
nuget 包之间有什么区别 HangFire.AspNetCore和 HangFire和 HangFire.core ? 看来我可以将 hangfire 与 ASP .NET MVC Core 项目
我是 hangfire 的新手,我正在尝试设置一种方法来使用我现有的 serilog 记录器在 asp.net web api 中记录事件。这是我的记录器类: public static class
出于冗余原因,我需要使用相同的数据库运行同一服务的多个实例。 我发现了一些关于“Hangfire 多个实例”的问题,但出于不同的目的,然后是我的:通常是关于在同一数据库上为不同的任务运行多个实例,或与
此 documentation说你可以使用 Queue 指定一个队列要调用的方法的属性。这假设您总是希望在同一个队列上执行一个方法。调用 Enqueue 的进程有没有办法指定将作业放入的队列名称(有效
我有一个现有的 api,它按线程存储数据,并使用 HttpContext.Current 进行检索。 . 我正在尝试重构这个类以从 hangfire 作业中调用——我想知道是否有一个等效的静态方法来检
迁移到 asp.net core 2.1 破坏了我们的 Hangfire 作业设置。 在 Program.cs 的 Main 方法中,我们有类似的内容 var webHost = BuildWebHo
根据 hangfire documentation Starting from Hangfire 1.3.0, you are not required to do anything, if your
我刚刚开始使用Hangfire,现在我很喜欢它。 我了解到,Hangfire将成功工作的历史记录保留了1天,之后将其清除。 有没有一种方法可以自定义此默认行为并将历史记录保留任何持续时间(例如7天)?
我们的网络应用程序允许最终用户在 UI 上设置重复作业的队列。 (我们为每个服务器创建一个队列(使用服务器名称)并允许用户选择要运行的服务器)作业的注册方式: RecurringJob.AddOrUp
我有一个应用程序,具有 Multi-Tenancy 。我想在用户上下文下创建后台作业,但我找不到实现它的好方法。 我将解释一下我的架构。我正在使用包含 UserID 的接口(interface) IC
我想将 QUARTZ 作业转换为 hangfire 我有一个带有 Execute 方法的类。 如何在Hangfire中调用该方法。我尝试类似的事情 public static string CRON_
当使用 Hangfire 排队和处理后台作业时,我能够导致发生可重现的内存不足异常。 . 这些作业是简单的 Console.WriteLine 调用,因此我不希望堆内存以这种方式增加。 我的配置是否不
我有 ASP.NET Web API 应用程序。该应用程序使用 Unity 作为 IoC 容器。该应用程序也在使用 Hangfire,我正在尝试配置 Hangfire 以使用 Unity。 所以基于d
从 1.7.8 版本开始,可以将结果从父作业传递到 Hangfire 中的延续作业。但是没有提供文档或示例。在浏览代码时,我意识到我需要使用带有 pushResults: true 参数的 Conti
有没有人使用过 Hangfire 的多个实例? (在不同的应用程序中)使用相同的 SQL DB 进行配置。因此,我不想为每个 hangfire 实例创建新的 SQL 数据库,而是想与多个实例共享同一个
从 1.7.8 版本开始,可以将结果从父作业传递到 Hangfire 中的延续作业。但是没有提供文档或示例。在浏览代码时,我意识到我需要使用带有 pushResults: true 参数的 Conti
我是一名优秀的程序员,十分优秀!