public override string CreateExpiredJob(Common.Job job, IDictionary <string, string> parameters, DateTime createdAt, TimeSpan expireIn) { if (job == null) { throw new ArgumentNullException(nameof(job)); } if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } InvocationData invocationData = InvocationData.Serialize(job); PushResponse response = Client.Push("jobs", new Entities.Job { InvocationData = invocationData, Arguments = invocationData.Arguments, CreatedOn = createdAt, ExpireOn = createdAt.Add(expireIn), Parameters = parameters.Select(p => new Parameter { Name = p.Key, Value = p.Value }).ToArray() }); if (response.StatusCode == HttpStatusCode.OK) { return(response.Result.name); } return(string.Empty); }
public override string CreateExpiredJob(Common.Job job, IDictionary <string, string> parameters, DateTime createdAt, TimeSpan expireIn) { if (job == null) { throw new ArgumentNullException(nameof(job)); } if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } InvocationData invocationData = InvocationData.Serialize(job); Documents.Job entityJob = new Documents.Job { InvocationData = invocationData, Arguments = invocationData.Arguments, CreatedOn = createdAt, ExpireOn = createdAt.Add(expireIn).ToEpoch(), Parameters = parameters }; IOperationResult <Documents.Job> response = bucket.Insert(entityJob.Id, entityJob); if (response.Success) { return(entityJob.Id); } return(string.Empty); }
public static NonEscapedString Render(Common.Job job) { //if (job == null) { return new NonEscapedString("<em>" + Hangfire.Dashboard.Resources.Strings.Common_CannotFindTargetMethod + "</em>"); } var type = Type.GetType("Hangfire.Dashboard.JobMethodCallRenderer,Hangfire.Core"); var render = type.GetMethod("Render"); return(render.Invoke(null, new[] { job }) as NonEscapedString); }
public override JobData GetJobData(string jobId) { if (jobId == null) { throw new ArgumentNullException(nameof(jobId)); } Uri uri = UriFactory.CreateDocumentUri(Storage.Options.DatabaseName, Storage.Options.CollectionName, jobId); Task <DocumentResponse <Documents.Job> > task = Storage.Client.ReadDocumentWithRetriesAsync <Documents.Job>(uri, new RequestOptions { PartitionKey = new PartitionKey((int)DocumentTypes.Job) }); task.Wait(); if (task.Result.Document != null) { Documents.Job data = task.Result; InvocationData invocationData = data.InvocationData; invocationData.Arguments = data.Arguments; Common.Job job = null; JobLoadException loadException = null; try { job = invocationData.DeserializeJob(); } catch (JobLoadException ex) { loadException = ex; } return(new JobData { Job = job, State = data.StateName, CreatedAt = data.CreatedOn, LoadException = loadException }); } return(null); }
public override JobData GetJobData(string jobId) { if (jobId == null) { throw new ArgumentNullException(nameof(jobId)); } Entities.Job data = Storage.Client.CreateDocumentQuery <Entities.Job>(Storage.Collections.JobDocumentCollectionUri, QueryOptions) .Where(j => j.Id == jobId) .AsEnumerable() .FirstOrDefault(); if (data != null) { InvocationData invocationData = data.InvocationData; invocationData.Arguments = data.Arguments; Common.Job job = null; JobLoadException loadException = null; try { job = invocationData.Deserialize(); } catch (JobLoadException ex) { loadException = ex; } return(new JobData { Job = job, State = data.StateName, CreatedAt = data.CreatedOn, LoadException = loadException }); } return(null); }
public override string CreateExpiredJob(Common.Job job, IDictionary <string, string> parameters, DateTime createdAt, TimeSpan expireIn) { if (job == null) { throw new ArgumentNullException(nameof(job)); } if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } InvocationData invocationData = InvocationData.SerializeJob(job); Documents.Job entityJob = new Documents.Job { InvocationData = invocationData, Arguments = invocationData.Arguments, CreatedOn = createdAt, ExpireOn = createdAt.Add(expireIn), Parameters = parameters.Select(p => new Parameter { Name = p.Key, Value = p.Value }).ToArray() }; Task <ResourceResponse <Document> > task = Storage.Client.CreateDocumentWithRetriesAsync(Storage.CollectionUri, entityJob, new RequestOptions { PartitionKey = new PartitionKey((int)DocumentTypes.Job) }); task.Wait(); if (task.Result.StatusCode == HttpStatusCode.Created || task.Result.StatusCode == HttpStatusCode.OK) { return(entityJob.Id); } return(string.Empty); }
public override JobData GetJobData(string jobId) { if (jobId == null) { throw new ArgumentNullException(nameof(jobId)); } Task <ItemResponse <Documents.Job> > task = Storage.Container.ReadItemWithRetriesAsync <Documents.Job>(jobId, new PartitionKey((int)DocumentTypes.Job)); task.Wait(); if (task.Result.Resource != null) { Documents.Job data = task.Result; InvocationData invocationData = data.InvocationData; invocationData.Arguments = data.Arguments; Common.Job job = null; JobLoadException loadException = null; try { job = invocationData.DeserializeJob(); } catch (JobLoadException ex) { loadException = ex; } return(new JobData { Job = job, State = data.StateName, CreatedAt = data.CreatedOn, LoadException = loadException }); } return(null); }
public override JobData GetJobData(string jobId) { if (jobId == null) { throw new ArgumentNullException(nameof(jobId)); } Uri uri = UriFactory.CreateDocumentUri(Storage.Options.DatabaseName, Storage.Options.CollectionName, jobId); Task <DocumentResponse <Documents.Job> > task = Storage.Client.ReadDocumentAsync <Documents.Job>(uri); Documents.Job data = task.Result; if (data != null) { InvocationData invocationData = data.InvocationData; invocationData.Arguments = data.Arguments; Common.Job job = null; JobLoadException loadException = null; try { job = invocationData.Deserialize(); } catch (JobLoadException ex) { loadException = ex; } return(new JobData { Job = job, State = data.StateName, CreatedAt = data.CreatedOn, LoadException = loadException }); } return(null); }
public override JobData GetJobData(string jobId) { if (jobId == null) { throw new ArgumentNullException(nameof(jobId)); } IDocumentResult <Documents.Job> result = bucket.GetDocument <Documents.Job>(jobId); if (result.Success && result.Content != null) { Documents.Job data = result.Content; InvocationData invocationData = data.InvocationData; invocationData.Arguments = data.Arguments; Common.Job job = null; JobLoadException loadException = null; try { job = invocationData.Deserialize(); } catch (JobLoadException ex) { loadException = ex; } return(new JobData { Job = job, State = data.StateName, CreatedAt = data.CreatedOn, LoadException = loadException }); } return(null); }
public override JobData GetJobData(string jobId) { if (jobId == null) { throw new ArgumentNullException(nameof(jobId)); } FirebaseResponse response = Client.Get($"jobs/{jobId}"); if (response.StatusCode == HttpStatusCode.OK && !response.IsNull()) { Entities.Job data = response.ResultAs <Entities.Job>(); InvocationData invocationData = data.InvocationData; invocationData.Arguments = data.Arguments; Common.Job job = null; JobLoadException loadException = null; try { job = invocationData.Deserialize(); } catch (JobLoadException ex) { loadException = ex; } return(new JobData { Job = job, State = data.StateName, CreatedAt = data.CreatedOn, LoadException = loadException }); } return(null); }
public override string CreateExpiredJob(Common.Job job, IDictionary <string, string> parameters, DateTime createdAt, TimeSpan expireIn) { if (job == null) { throw new ArgumentNullException(nameof(job)); } if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } InvocationData invocationData = InvocationData.Serialize(job); Entities.Job entityJob = new Entities.Job { InvocationData = invocationData, Arguments = invocationData.Arguments, CreatedOn = createdAt, ExpireOn = createdAt.Add(expireIn), Parameters = parameters.Select(p => new Parameter { Name = p.Key, Value = p.Value }).ToArray() }; ResourceResponse <Document> response = Storage.Client.CreateDocumentWithRetriesAsync(Storage.Collections.JobDocumentCollectionUri, entityJob).GetAwaiter().GetResult(); if (response.StatusCode == HttpStatusCode.Created || response.StatusCode == HttpStatusCode.OK) { return(entityJob.Id); } return(string.Empty); }
private static void CreateManagement(ManagementPagesOptions options = null) { #region 翻译 var resourceManager = Hangfire.Dashboard.Resources.Strings.ResourceManager; var resourceManField = typeof(Hangfire.Dashboard.Resources.Strings).GetField("resourceMan", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); var customHangfireLanguage = new CustomHangfireLanguage(resourceManager, options.translateFunc, options.culture); resourceManField.SetValue(null, customHangfireLanguage /*_customHangfireLanguage*/); JobHistoryRenderer.Register(customHangfireLanguage); //翻译时间脚本 var jsPath = Hangfire.Dashboard.DashboardRoutes.Routes.Contains("/js[0-9]+") ? "/js[0-9]+" : "/js[0-9]{3}"; //DashboardRoutes.Routes.Append(jsPath, new DynamicJsDispatcher()); DashboardRoutes.Routes.Append(jsPath, new EmbeddedResourceDispatcher("application/javascript", Assembly.GetExecutingAssembly(), $"{typeof(GlobalConfigurationExtension).Namespace}.Content.momentLocale.js")); // #endregion 翻译 //Cron最近5次运行时间 //cron?cron=0+0+0+*+*+%3F+ DashboardRoutes.Routes.Add("/cron", new CommandDispatcher(async context => { var cron = context.Request.GetQuery("cron"); //var result = CronExpressionDescriptor.ExpressionDescriptor.GetDescription(cron, new Options //{ // ThrowExceptionOnParseError = false, // Verbose = false, // DayOfWeekStartIndexZero = true, // Locale = (locale ?? "en-US") //}); //var cronDescription = Hangfire.Cron.GetDescription(cron); var cronDescription = CronExpressionDescriptor.ExpressionDescriptor.GetDescription(cron); var cronSchedule = Cronos.CronExpression.Parse(cron); var example = cronSchedule.GetOccurrences(System.DateTime.UtcNow, System.DateTime.Now.AddYears(5)).Take(5).ToArray(); //var cronSchedule = NCrontab.CrontabSchedule.Parse(cron); //var example = cronSchedule.GetNextOccurrences(System.DateTime.UtcNow, System.DateTime.Now.AddYears(5)).Take(5).ToArray(); var str = Newtonsoft.Json.JsonConvert.SerializeObject(new { Description = cronDescription, Example = example }); await context.Response.WriteAsync(str); return(true); })); var pages = options.GetPages(); #region 任务 ManagementSidebarMenu.Items.Clear(); foreach (var pageInfo in pages) { //添加命令 //ManagementBasePage.AddCommands(pageInfo.Queue); //添加菜单连接 var path = $"{ManagementPage.UrlRoute}/{pageInfo.Title.ToBase64Url()}"; ManagementSidebarMenu.Items.Add(p => new MenuItem(pageInfo.Title, path) { Active = p.RequestPath.StartsWith(path), Metric = new DashboardMetric( "metrics:count", "Metrics_Count", page => new Metric(pageInfo.Metadatas.Length) { //Style = pageInfo.Metadatas.Length > 0 ? MetricStyle.Info : MetricStyle.Default, //Highlighted = pageInfo.Metadatas.Length > 0 }) }); ////添加页面 DashboardRoutes.Routes.AddRazorPage(path, x => new ManagementBasePage(pageInfo.Title, pageInfo.Title, pageInfo.Metadatas)); } #endregion 任务 //暂停取消功能 GlobalJobFilters.Filters.Add(new PauseStateAttribute()); DashboardRoutes.Routes.AddRazorPage(ManagementPage.UrlRoute, x => new ManagementPage()); //DashboardRoutes.Routes.AddRazorPage("/recurring/addJobs", x => new ManagementPage()); // can't use the method of Hangfire.Console as it's usage overrides any similar usage here. Thus // we have to add our own endpoint to load it and call it from our code. Actually is a lot less work //DashboardRoutes.Routes.Add("/jsm", new EmbeddedResourceDispatcher("application/javascript", Assembly.GetExecutingAssembly(), $"{typeof(GlobalConfigurationExtension).Namespace}.Content.management.js")); //DashboardRoutes.Routes.Add("/jsm", new CombinedResourceDispatcher("application/javascript", Assembly.GetExecutingAssembly(), $"{typeof(GlobalConfigurationExtension).Namespace}.Content", new[] { "management.js", "cron.js" })); DashboardRoutes.Routes.Append(jsPath, new CombinedResourceDispatcher("application/javascript", Assembly.GetExecutingAssembly(), $"{typeof(GlobalConfigurationExtension).Namespace}.Content", new[] { "management.js", "cron.js" })); //NavigationMenu.Items.Add(page => new MenuItem(ManagementPage.Title, page.Url.To(ManagementPage.UrlRoute)) //{ // Active = page.RequestPath.StartsWith(ManagementPage.UrlRoute) //}); //执行暂停命令 DashboardRoutes.Routes.AddBatchCommand("/recurring/pause", (context, jobId) => { if (context.IsReadOnly) { return; } using (var connection = context.Storage.GetConnection()) { connection.SetPauseState(jobId, true); } }); //执行恢复命令 DashboardRoutes.Routes.AddBatchCommand("/recurring/repeat", (context, jobId) => { if (context.IsReadOnly) { return; } using (var connection = context.Storage.GetConnection()) { connection.SetPauseState(jobId, false); } }); //执行添加任务 DashboardRoutes.Routes.AddCommand($"{ManagementPage.UrlRoute}/addJob", context => { if (context.IsReadOnly) { return(false); } if (context.Request.Method == "POST") { //Hangfire官方在Owin模式获取参数会有问题,只能获取一次,第二次会是空值 var getFormValue = new Func <string, IList <string> >(key => { ////Owin模式 //var environment = context.GetOwinEnvironment(); //var _context = new Microsoft.Owin.OwinContext(environment); //var form = _context.Request.ReadFormSafeAsync().Result; //var r = form.GetValues(_key); ////aspnet模式 //var r = context.Request.GetFormValuesAsync(key)?.Result; //return r.Select(f => string.IsNullOrWhiteSpace(f) ? null : f).ToArray(); //通用模式 IList <string> getValue(string _key) { #if NETFULL //Owin模式 var environment = context.GetOwinEnvironment(); var _context = new Microsoft.Owin.OwinContext(environment); var form = _context.Request?.ReadFormAsync()?.Result; return(form?.GetValues(_key)); #else return(context.Request.GetFormValuesAsync(_key)?.Result); #endif } var r = getValue(key); return(r.Select(f => string.IsNullOrWhiteSpace(f) ? null : f).ToArray()); }); var jobtype = getFormValue("type")?.FirstOrDefault(); var id = getFormValue("id")?.FirstOrDefault(); var jobMetadata = pages.SelectMany(f => f.Metadatas.Where(fff => fff.GetId() == id)).FirstOrDefault(); var par = new List <object>(); foreach (var parameterInfo in jobMetadata.Parameters) { if (parameterInfo.ParameterType == typeof(Server.PerformContext) || parameterInfo.ParameterType == typeof(IJobCancellationToken)) { par.Add(null); continue; } ; var variable = $"{id}_{parameterInfo.Name}"; if (parameterInfo.ParameterType == typeof(DateTime)) { variable = $"{variable}_datetimepicker"; } var t = getFormValue(variable); object item = null; var formInput = t?.FirstOrDefault(); if (parameterInfo.ParameterType == typeof(string) || parameterInfo.ParameterType == typeof(Uri) || parameterInfo.ParameterType.IsEnum) { item = formInput; } else if (parameterInfo.ParameterType == typeof(int)) { if (formInput != null) { item = int.Parse(formInput); } } else if (parameterInfo.ParameterType == typeof(DateTime)) { item = formInput == null ? DateTime.MinValue : DateTime.Parse(formInput); } else if (parameterInfo.ParameterType == typeof(bool)) { item = formInput == "on"; } else { throw new NotImplementedException(); } par.Add(item); } var job = new Common.Job(jobMetadata.Type, jobMetadata.MethodInfo, par.ToArray()); var client = new BackgroundJobClient(context.Storage); switch (jobtype) { case "CronExpression": { var manager = new RecurringJobManager(context.Storage); try { var queue = getFormValue($"{id}_sys_queue")?.FirstOrDefault(); var timeZone = getFormValue($"{id}_sys_timeZone")?.FirstOrDefault() ?? "Utc"; var displayName = getFormValue($"{id}_sys_displayName")?.FirstOrDefault(); var jobQueue = (queue?.Trim().Replace("-", "_").Replace(" ", "_") ?? jobMetadata.Queue)?.ToLower(); var jobTimeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZone?.Trim()) ?? TimeZoneInfo.Utc; var jobDisplayName = string.IsNullOrWhiteSpace(displayName) ? jobMetadata.DisplayName : displayName; var schedule = getFormValue("schedule")?.FirstOrDefault(); var cron = getFormValue($"{id}_sys_cron")?.FirstOrDefault(); if (string.IsNullOrWhiteSpace(schedule ?? cron)) { throw new Exception("请填写 Cron 表达式"); } manager.AddOrUpdate(jobDisplayName, job, schedule ?? cron, jobTimeZone, jobQueue); } catch (Exception) { return(false); } return(true); //break; } case "ScheduleDateTime": { var datetime = getFormValue($"{id}_sys_datetime")?.FirstOrDefault(); if (string.IsNullOrWhiteSpace(datetime)) { //context.Response.StatusCode = 400; ////Hangfire.Dashboard.AspNetCoreDashboardResponse context.Response.WriteAsync("请填写 执行时间 表达式"); throw new Exception("请填写 执行时间 表达式"); } var jobId = client.Create(job, new States.ScheduledState(DateTime.Parse(datetime).ToUniversalTime())); //Queue return(jobId != string.Empty); //break; } case "ScheduleTimeSpan": { var schedule = getFormValue("schedule")?.FirstOrDefault(); var timeSpan = getFormValue($"{id}_sys_timespan")?.FirstOrDefault(); if (string.IsNullOrWhiteSpace(schedule ?? timeSpan)) { throw new Exception("请填写 延迟时间 表达式"); } var jobId = client.Create(job, new States.ScheduledState(TimeSpan.Parse(schedule ?? timeSpan))); //Queue return(jobId != string.Empty); //break; } //case "ContinueWith": // { // var parentId = getValue("{id}_sys_parentId")?.FirstOrDefault(); // var optionsStr = getValue($"{id}_sys_JobContinuationOptions")?.FirstOrDefault(); // var jobContinuationOptions = JobContinuationOptions.OnlyOnSucceededState; // Enum.TryParse<JobContinuationOptions>(optionsStr, out jobContinuationOptions); // var jobId = client.Create(job, new States.AwaitingState(parentId, null, jobContinuationOptions)); // return jobId != string.Empty; // //break; // } case "Enqueue": default: { var queue = getFormValue($"{id}_sys_queue")?.FirstOrDefault(); var jobQueue = (queue?.Trim().Replace("-", "_").Replace(" ", "_") ?? jobMetadata.Queue)?.ToLower(); var jobId = client.Create(job, new States.EnqueuedState(jobQueue)); return(jobId != string.Empty); //break; } //break; } /* * EnqueuedState * Queue * ScheduledState * AddOrUpdate * DisplayName * TimeZone * Queue * ContinueWith * parentId * jobContinuationOptions */ //if (!string.IsNullOrEmpty(schedule)) //{ // var minutes = int.Parse(schedule); // return client.Create(job, new ScheduledState(new TimeSpan(0, 0, minutes, 0))) != string.Empty; //} //else if (!string.IsNullOrEmpty(cron)) //{ // var manager = new RecurringJobManager(context.Storage); // try // { // manager.AddOrUpdate(jobMetadata.DisplayName, job, cron, TimeZoneInfo.Utc, queue); // } // catch (Exception) // { // return false; // } // return true; //} } return(false); }); //替换页面 if (options.OverrideDefaultHangfirePages) { var type = Type.GetType("Hangfire.Dashboard.RazorPageDispatcher," + typeof(IGlobalConfiguration).Assembly.FullName); if (type != null) { object obj = Activator.CreateInstance(type, new object[] { new Func <System.Text.RegularExpressions.Match, RazorPage>(x => new Hangfire.Dashboard.Management.Pages.RecurringJobsPage()) }); var dispatcher = obj as IDashboardDispatcher;//new RazorPageDispatcher( ) Hangfire.Dashboard.DashboardRoutes.Routes.Replace("/recurring", dispatcher); object obj2 = Activator.CreateInstance(type, new object[] { new Func <System.Text.RegularExpressions.Match, RazorPage>(x => new Hangfire.Dashboard.Management.Pages.JobDetailsPage(x.Groups["JobId"].Value)) }); var dispatcher2 = obj2 as IDashboardDispatcher;//new RazorPageDispatcher( ) Hangfire.Dashboard.DashboardRoutes.Routes.Replace("/jobs/details/(?<JobId>.+)", dispatcher2); object obj3 = Activator.CreateInstance(type, new object[] { new Func <System.Text.RegularExpressions.Match, RazorPage>(x => new Hangfire.Dashboard.Management.Pages.RetriesPage()) }); var dispatcher3 = obj3 as IDashboardDispatcher;//new RazorPageDispatcher( ) Hangfire.Dashboard.DashboardRoutes.Routes.Replace("/retries", dispatcher3); object obj4 = Activator.CreateInstance(type, new object[] { new Func <System.Text.RegularExpressions.Match, RazorPage>(x => new Hangfire.Dashboard.Management.Pages.SucceededJobs()) }); var dispatcher4 = obj4 as IDashboardDispatcher;//new RazorPageDispatcher( ) Hangfire.Dashboard.DashboardRoutes.Routes.Replace("/jobs/succeeded", dispatcher4); } } }