/// <summary> /// 加载应用程序域 /// </summary> /// <param name="assemblyName"></param> /// <returns></returns> public static PluginLoadContext LoadAssemblyContext(Guid sid, string assemblyName) { try { string pluginLocation = GetTaskAssemblyPath(sid, assemblyName); PluginLoadContext loadContext = new PluginLoadContext(pluginLocation); return(loadContext); //AppDomainSetup setup = new AppDomainSetup(); //setup.ApplicationName = assemblyName; //setup.ApplicationBase = Path.GetDirectoryName(dllPath); //if (File.Exists(dllPath + ".config")) //{ // setup.ConfigurationFile = dllPath + ".config"; //} ////setup.ShadowCopyFiles = "true"; //启用影像复制程序集 ////setup.ShadowCopyDirectories = setup.ApplicationBase; ////AppDomain.CurrentDomain.SetShadowCopyFiles(); //Assembly assembly = Assembly.Load(File.ReadAllBytes(dllPath)); //AssemblyLoadContext context = new AssemblyLoadContext(""); //AppDomain domain = AppDomain.CreateDomain(assemblyName, null, setup); ////AppDomain.MonitoringIsEnabled = true; //return domain; } catch (Exception exp) { LogHelper.Error($"加载应用程序域{assemblyName}失败!", exp); throw exp; } }
/// <summary> /// 加载应用程序域 /// </summary> /// <param name="assemblyName"></param> /// <returns></returns> public static PluginLoadContext LoadAssemblyContext(Guid sid, string assemblyName) { string pluginLocation = GetTaskAssemblyPath(sid, assemblyName); PluginLoadContext loadContext = new PluginLoadContext(pluginLocation); return(loadContext); }
/// <summary> /// 卸载应用程序域 /// </summary> /// <param name="context"></param> public static void UnLoadAssemblyLoadContext(PluginLoadContext context) { if (context != null) { context.Unload(); GC.Collect(); GC.WaitForPendingFinalizers(); } }
/// <summary> /// 卸载应用程序域 /// </summary> /// <param name="context"></param> public static void UnLoadAssemblyLoadContext(PluginLoadContext context) { if (context != null) { context.Unload(); //for (int i = 0; context.weakReference.IsAlive && (i < 10); i++) { GC.Collect(); GC.WaitForPendingFinalizers(); } } }
public static TaskBase CreateTaskInstance(PluginLoadContext context, Guid sid, string assemblyName, string className) { try { string pluginLocation = GetTaskAssemblyPath(sid, assemblyName); var assembly = context.LoadFromAssemblyName(new AssemblyName(Path.GetFileNameWithoutExtension(pluginLocation))); Type type = assembly.GetType(className, true, true); return(Activator.CreateInstance(type) as TaskBase); } catch (Exception ex) { throw ex; } }
/// <summary> /// 启动一个任务,带重试机制 /// </summary> /// <param name="task"></param> /// <returns></returns> public static async Task <bool> StartWithRetry(Guid sid) { var jk = new JobKey(sid.ToString().ToLower()); if (await _scheduler.CheckExists(jk)) { return(true); } ScheduleView view = await GetScheduleView(sid); PluginLoadContext lc = null; try { lc = AssemblyHelper.LoadAssemblyContext(view.Schedule.Id, view.Schedule.AssemblyName); for (int i = 0; i < 3; i++) { try { await Start(view, lc); return(true); } catch (SchedulerException sexp) { LogHelper.Error($"任务启动失败!开始第{i + 1}次重试...", sexp, view.Schedule.Id); } } //最后一次尝试 await Start(view, lc); return(true); } catch (SchedulerException sexp) { AssemblyHelper.UnLoadAssemblyLoadContext(lc); LogHelper.Error($"任务所有重试都失败了,已放弃启动!", sexp, view.Schedule.Id); return(false); } catch (Exception exp) { AssemblyHelper.UnLoadAssemblyLoadContext(lc); LogHelper.Error($"任务启动失败!", exp, view.Schedule.Id); return(false); } }
/// <summary> /// 启动一个任务,带重试机制 /// </summary> /// <param name="task"></param> /// <param name="callBack"></param> /// <returns></returns> public static async Task <bool> StartWithRetry(ScheduleView view, Action <Guid, DateTime?> callBack) { PluginLoadContext lc = null; try { lc = AssemblyHelper.LoadAssemblyContext(view.Schedule.Id, view.Schedule.AssemblyName); for (int i = 0; i < 3; i++) { try { await Start(view, lc, callBack); return(true); } catch (SchedulerException sexp) { LogHelper.Error($"任务启动失败!开始第{i + 1}次重试...", sexp, view.Schedule.Id); } } //最后一次尝试 await Start(view, lc, callBack); return(true); } catch (SchedulerException sexp) { AssemblyHelper.UnLoadAssemblyLoadContext(lc); LogHelper.Error($"任务所有重试都失败了,已放弃启动!", sexp, view.Schedule.Id); return(false); } catch (Exception exp) { AssemblyHelper.UnLoadAssemblyLoadContext(lc); LogHelper.Error($"任务启动失败!", exp, view.Schedule.Id); return(false); } }
private static async Task Start(ScheduleView view, PluginLoadContext lc) { //throw //在应用程序域中创建实例返回并保存在job中,这是最终调用任务执行的实例 TaskBase instance = AssemblyHelper.CreateTaskInstance(lc, view.Schedule.Id, view.Schedule.AssemblyName, view.Schedule.ClassName); if (instance == null) { throw new InvalidCastException($"任务实例创建失败,请确认目标任务是否派生自TaskBase类型。程序集:{view.Schedule.AssemblyName},类型:{view.Schedule.ClassName}"); } // instance.logger = new LogWriter(); ; JobDataMap map = new JobDataMap { new KeyValuePair <string, object> ("domain", lc), new KeyValuePair <string, object> ("instance", instance), new KeyValuePair <string, object> ("name", view.Schedule.Title), new KeyValuePair <string, object> ("params", ConvertParamsJson(view.Schedule.CustomParamsJson)), new KeyValuePair <string, object> ("keepers", view.Keepers), new KeyValuePair <string, object> ("children", view.Children) }; try { IJobDetail job = JobBuilder.Create <RootJob>() .WithIdentity(view.Schedule.Id.ToString()) .UsingJobData(map) .Build(); //添加触发器 var listener = new JobRunListener(view.Schedule.Id.ToString()); listener.OnSuccess += StartedEvent; _scheduler.ListenerManager.AddJobListener(listener, KeyMatcher <JobKey> .KeyEquals(new JobKey(view.Schedule.Id.ToString()))); if (view.Schedule.RunLoop) { if (!CronExpression.IsValidExpression(view.Schedule.CronExpression)) { throw new Exception("cron表达式验证失败"); } CronTriggerImpl trigger = new CronTriggerImpl { CronExpressionString = view.Schedule.CronExpression, Name = view.Schedule.Title, Key = new TriggerKey(view.Schedule.Id.ToString()), Description = view.Schedule.Remark }; if (view.Schedule.StartDate.HasValue) { trigger.StartTimeUtc = TimeZoneInfo.ConvertTimeToUtc(view.Schedule.StartDate.Value); } if (view.Schedule.EndDate.HasValue) { trigger.EndTimeUtc = TimeZoneInfo.ConvertTimeToUtc(view.Schedule.EndDate.Value); } await _scheduler.ScheduleJob(job, trigger); } else { DateTimeOffset start = TimeZoneInfo.ConvertTimeToUtc(DateTime.Now); if (view.Schedule.StartDate.HasValue) { start = TimeZoneInfo.ConvertTimeToUtc(view.Schedule.StartDate.Value); } DateTimeOffset end = start.AddMinutes(1); if (view.Schedule.EndDate.HasValue) { end = TimeZoneInfo.ConvertTimeToUtc(view.Schedule.EndDate.Value); } ITrigger trigger = TriggerBuilder.Create() .WithIdentity(view.Schedule.Id.ToString()) .StartAt(start) .WithSimpleSchedule(x => x .WithRepeatCount(1).WithIntervalInMinutes(1)) .EndAt(end) .Build(); await _scheduler.ScheduleJob(job, trigger); } } catch (Exception ex) { throw new SchedulerException(ex); } LogHelper.Info($"任务[{view.Schedule.Title}]启动成功!", view.Schedule.Id); _ = Task.Run(() => { while (true) { var log = instance.ReadLog(); if (log != null) { LogManager.Queue.Write(new SystemLogEntity { Category = log.Category, Message = log.Message, ScheduleId = log.ScheduleId, Node = log.Node, StackTrace = log.StackTrace, TraceId = log.TraceId, CreateTime = log.CreateTime }); } else { Thread.Sleep(3000); } } }); }