public Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken) { IJobDetail job = context.JobDetail; var instance = job.JobDataMap["instance"] as IHosSchedule; if (jobException == null) { var utcDate = context.Trigger.GetNextFireTimeUtc(); DateTime?nextTime = utcDate.HasValue ? TimeZoneInfo.ConvertTimeFromUtc(utcDate.Value.DateTime, TimeZoneInfo.Local) : new DateTime?(); OnSuccess(Guid.Parse(job.Key.Name), nextTime); //子任务触发 Task.Run(async() => { foreach (var item in instance.Children) { var jobkey = new JobKey(item.Key.ToString()); if (await context.Scheduler.CheckExists(jobkey)) { JobDataMap map = new JobDataMap { new KeyValuePair <string, object>("PreviousResult", context.Result) }; await context.Scheduler.TriggerJob(jobkey, map); } } }); } else if (jobException is BusinessRunException) { Task.Run(() => { if (instance.Keepers != null && instance.Keepers.Any()) { MailKitHelper.SendMail( instance.Keepers, $"任务运行异常 — {instance.Main.Title}", QuartzManager.GetErrorEmailContent(instance.Main.Title, (jobException as BusinessRunException).Detail) ); } }); } return(Task.FromResult(0)); }
static void Main(string[] args) { try { FileLog.WriteLog("启动邮件任务..."); //EmailHelper email = new EmailHelper("smtphm.qiye.163.com", 25, "*****@*****.**", "Xinyun2020"); //string recevicer = "*****@*****.**"; //string[] recevicerList = recevicer.Split(';'); //email.SendEmail(recevicerList, "标题", "内容", "<b>这是html标记的文本</b>", ""); MailKitHelper mailkit = new MailKitHelper(); ////MailSender mail = new MailSender(); string recevicer = "*****@*****.**"; string[] recevicerList = recevicer.Split(';'); mailkit.Send(recevicerList, "mailkit邮件测试", "mailkit邮件测试"); ////mail.AddTo(recevicerList); //try //{ // mailkit.Send(recevicerList, "mailkit邮件测试", "mailkit邮件测试"); //} //catch (Exception ex) //{ // FileLog.WriteLog("mailkit邮件测试" + ex.Message); //} //try //{ // mail.Send("mailsender邮件测试", "mailsender邮件测试"); //} //catch (Exception ex) //{ // FileLog.WriteLog("mailsender邮件测试" + ex.Message); //} } catch (Exception ex) { FileLog.WriteLog("邮件发送异常:" + ex.Message.ToString()); FileLog.WriteLog("邮件发送失败!"); } }
public async Task TestAsync() { var mailKitHelper = new MailKitHelper(); var fileStream = FileToStream(@"D:\test_attachment.txt"); var mail = new Mail(); mail.From("From email") .Subject($"email test({DateTime.Now}+{Guid.NewGuid()})") .Body(@"Across the Great Wall we can reach every corner in the world.") .To(new List <string> { "*****@*****.**", "*****@*****.**" }) .Cc("*****@*****.**") .Bcc("*****@*****.**") .Attachment(fileStream, "test_attachment.txt"); await mailKitHelper.Host("Your SMTP server's IP.") .Port(587) .UserName("The user name for NetworkCredential") .Password("The password for NetworkCredential") .Ssl(true) .SendAsync(mail); }
private static async Task NotifyRequest(NotifyPlan plan) { Guid sid = Guid.Parse(plan.Key); Guid traceId = Guid.NewGuid(); using (var scope = new ScopeDbContext()) { var db = scope.GetDbContext(); var tracer = scope.GetService <Common.RunTracer>(); var entity = await db.ScheduleDelayeds.FirstOrDefaultAsync(x => x.Id == sid); if (entity == null) { LogHelper.Info($"不存在的任务ID。", sid, traceId); return; } entity.ExecuteTime = DateTime.Now; Exception failedException = null; try { //创建一条trace await tracer.Begin(traceId, plan.Key); var httpClient = scope.GetService <IHttpClientFactory>().CreateClient(); plan.NotifyBody = plan.NotifyBody.Replace("\r\n", ""); HttpContent reqContent = new StringContent(plan.NotifyBody, System.Text.Encoding.UTF8, "application/json"); if (plan.NotifyDataType == "application/x-www-form-urlencoded") { //任务创建时要确保参数是键值对的json格式 reqContent = new FormUrlEncodedContent(Newtonsoft.Json.JsonConvert.DeserializeObject <IEnumerable <KeyValuePair <string, string> > >(plan.NotifyBody)); } LogHelper.Info($"即将请求:{entity.NotifyUrl}", sid, traceId); var response = await httpClient.PostAsync(plan.NotifyUrl, reqContent); var content = await response.Content.ReadAsStringAsync(); LogHelper.Info($"请求结束,响应码:{response.StatusCode.GetHashCode().ToString()},响应内容:{(response.Content.Headers.GetValues("Content-Type").Any(x => x.Contains("text/html")) ? "html文档" : content)}", sid, traceId); if (response.IsSuccessStatusCode && content.Contains("success")) { await tracer.Complete(ScheduleRunResult.Success); //更新结果字段 entity.FinishTime = DateTime.Now; entity.Status = (int)ScheduleDelayStatus.Successed; //更新日志 LogHelper.Info($"延时任务[{entity.Topic}:{entity.ContentKey}]执行成功。", sid, traceId); } else { failedException = new Exception("异常的返回结果。"); } } catch (Exception ex) { failedException = ex; } // 对异常进行处理 if (failedException != null) { //更新trace await tracer.Complete(ScheduleRunResult.Failed); //失败重试策略 int maxRetry = ConfigurationCache.GetField <int>("DelayTask_RetryTimes"); if (entity.FailedRetrys < (maxRetry > 0 ? maxRetry : 3)) { //更新结果字段 entity.FailedRetrys++; //计算下次延时间隔 int timespan = ConfigurationCache.GetField <int>("DelayTask_RetrySpans"); int delay = (timespan > 0 ? timespan : 10) * entity.FailedRetrys; //重新进入延时队列 Insert(plan, delay); //更新日志 LogHelper.Error($"延时任务[{entity.Topic}:{entity.ContentKey}]执行失败,将在{delay.ToString()}秒后开始第{entity.FailedRetrys.ToString()}次重试。", failedException, sid, traceId); } else { entity.Status = (int)ScheduleDelayStatus.Failed; entity.Remark = $"重试{entity.FailedRetrys}次后失败结束"; //更新日志 LogHelper.Error($"延时任务[{entity.Topic}:{entity.ContentKey}]重试{entity.FailedRetrys}次后失败结束。", failedException, sid, traceId); //邮件通知 var user = await db.SystemUsers.FirstOrDefaultAsync(x => x.UserName == entity.CreateUserName && !string.IsNullOrEmpty(x.Email)); if (user != null) { var keeper = new List <KeyValuePair <string, string> >() { new KeyValuePair <string, string>(user.RealName, user.Email) }; MailKitHelper.SendMail(keeper, $"延时任务异常 — {entity.Topic}:{entity.ContentKey}", Common.QuartzManager.GetErrorEmailContent($"{entity.Topic}:{entity.ContentKey}", failedException) , sid: sid, traceId: traceId); } else { LogHelper.Error($"用户无邮箱,无法发送邮件:{entity.CreateUserName}", new Exception("用户无邮箱"), sid, traceId); } } // ..... // 其实这个重试策略稍微有点问题,只能在抢锁成功的节点上进行重试,如果遭遇单点故障会导致任务丢失 // 严格来说应该通知到master让其对所有节点执行重试策略,但考虑到master也会有单点问题,综合考虑后还是放到当前worker中重试,若worker节点异常可以在控制台中人工干预进行重置或立即执行 } db.Update(entity); await db.SaveChangesAsync(); } }