yuzd / Hangfire.HttpJob

httpjob for Hangfire,restful api for Hangfire,job调度与业务分离
https://github.com/yuzd/Hangfire.HttpJob/wiki
MIT License
634 stars 186 forks source link

更新 EmailService.cs #206

Closed 1257960069 closed 10 months ago

1257960069 commented 10 months ago

1.using (var client = SmtpOptions.InitSmtpClient()) 如果InitSmtpClient的内部Connect()方法失败时,由于client的赋值操作还未完成,即使在using()内,也会导致无法被dispose. 2.dispose方法中已经显式调用Disconnect

yuzd commented 10 months ago

我之前的逻辑是想要共用Client来着 你是发现共用Client是存在线程安全问题吗

1257960069 commented 10 months ago

2024-01-10 05:09:41 [ERROR] (Hangfire.HttpJob.Support.SmtpOptions) HttpJobDispatcher.InitSmtpClient System.TimeoutException 操作已超时。 在 MailKit.Net.SocketUtils.Connect(String host, Int32 port, IPEndPoint localEndPoint, Int32 timeout, CancellationToken cancellationToken) 在 MailKit.MailService.ConnectNetwork(String host, Int32 port, CancellationToken cancellationToken) 在 MailKit.Net.Smtp.SmtpClient.Connect(String host, Int32 port, SecureSocketOptions options, CancellationToken cancellationToken) 在 Hangfire.HttpJob.Support.SmtpOptions.InitSmtpClient()

1257960069 commented 10 months ago

我自己写代码测试了下,发现了问题的根本不是是 client.Timeout = 5000; 时间不够. 27秒才连接上,后来才发现,由于自己电脑连接了vpn,导致5秒不够.不连接vpn,2秒就可以了.哎,,,,,,,,,,

yuzd commented 10 months ago

尴尬了。。。。那我rollback下

1257960069 commented 10 months ago

不用rollback,因为我的pr确实修复了你连接失败时未dispose的问题。而我的问题是网络连接超时问题,这种情况下你的代码确实没有释放

yuzd commented 10 months ago

我也发现了


 using (var client = SmtpOptions.SmtpClient) // 这里有点问题 相当于把单利的SmtpClient给dispose了
            {
                try
                {
                    client?.Send(mimeMessage);
                }
                catch (Exception ex)
                {
                    Logger.ErrorException("SmtpClient.SendEmail", ex);
                }
                finally
                {
                    client?.Disconnect(true);
                }
            }
yuzd commented 10 months ago

那我以你最新的代码为准了哈

1257960069 commented 10 months ago

一般情况下是不需要共用smtpclient的,只有在短时间发送大量邮件,或发送邮件十分频繁时才需要考虑复用smtpclient。比如blockcollection或channel来实现生产者和消费者解耦,消费者可以多线程

1257960069 commented 10 months ago

你的旧代码根本不是单例的,因为lazy对象没有被缓存,每次new lazy 在访问value时会调用lazy的初始化工厂方法,方法被多次调用,相当于还是多例

yuzd commented 10 months ago

了解了