Hangfire 在 dotnet core 中的 應(yīng)用及部署

第一步: 創(chuàng)建.net core mvc 應(yīng)用? ?

為什么要?jiǎng)?chuàng)建MVC 呢?? 因?yàn)?可以 采用登錄進(jìn)行控制hangfire 的權(quán)限控制,如果 不需要權(quán)限的話 api 應(yīng)用也是可以的


第二步: 下載相關(guān)的hangfire? dll? ?(采用的是sqlserver 進(jìn)行管理任務(wù))

Hangfire.AspNetCore 、Hangfire.RecurringJobExtension、Hangfire.Sqlserver

第三步: 配置Hangfire

1.ConfigureServices

```

public void ConfigureServices(IServiceCollection services)

? ? ? ? {

//配置啟用cookie

? ? ? ? ? ? services.Configure<CookiePolicyOptions>(options =>

? ? ? ? ? ? {

? ? ? ? ? ? ? ? // This lambda determines whether user consent for non-essential cookies is needed for a given request.

? ? ? ? ? ? ? ? options.CheckConsentNeeded = context => false;

? ? ? ? ? ? ? ? options.MinimumSameSitePolicy = SameSiteMode.None;

? ? ? ? ? ? });

//配置權(quán)限

? ? ? ? ? ? services.AddMvc(opt =>

? ? ? ? ? ? {

? ? ? ? ? ? ? ? opt.Filters.Add<AdminAuthFilter>();

? ? ? ? ? ? }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

? ? ? ? ? ? services.AddScoped<IMessageService, MessageService>();

? ? ? ? ? ? //注入hangfire 服務(wù)

? ? ? ? ? ? services.AddHangfire(x =>

? ? ? ? ? ? {

? ? ? ? ? ? ? ? x.UseSqlServerStorage(Configuration.GetConnectionString("DefaultConnection"));

? ? ? ? ? ? ? ? x.UseRecurringJob(new JobProvider());

? ? ? ? ? ? ? ? x.UseConsole();

? ? ? ? ? ? ? ? x.UseFilter(new LogEverythingAttribute());

? ? ? ? ? ? });

? ? ? ? ? ? ApiConfig.HangfireLogUrl = Configuration["HangfireLogFileUrl"];

? ? ? ? ? ? //GlobalJobFilters.Filters.Add(new LogEverythingAttribute());

? ? ? ? ? ? //GlobalConfiguration.Configuration.UseAutofacActivator(container);

? ? ? ? ? ? //add dbcontext

? ? ? ? ? ? services.AddDbContextPool<JobsDbContext>(options =>

? ? ? ? ? ? ? ? options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

? ? ? ? ? ? services.AddAuthentication(o =>

? ? ? ? ? ? {

? ? ? ? ? ? ? ? o.DefaultAuthenticateScheme = CookieJobsAuthInfo.AdminAuthCookieScheme;

? ? ? ? ? ? ? ? o.DefaultChallengeScheme = CookieJobsAuthInfo.AdminAuthCookieScheme;

? ? ? ? ? ? ? ? o.DefaultSignInScheme = CookieJobsAuthInfo.AdminAuthCookieScheme;

? ? ? ? ? ? ? ? o.DefaultSignOutScheme = CookieJobsAuthInfo.AdminAuthCookieScheme;

? ? ? ? ? ? }).AddCookie(CookieJobsAuthInfo.AdminAuthCookieScheme, o =>

? ? ? ? ? ? {

? ? ? ? ? ? ? ? o.LoginPath = "/Login";

? ? ? ? ? ? });

? ? ? ? ? ? //泛型注入到di

? ? ? ? ? ? services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));

? ? ? ? ? ? services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

? ? ? ? ? ? services.AddSession();

? ? ? ? ? ? services.AddScoped<IUserService, UserService>();

? ? ? ? ? ? services.AddScoped<IAuthService, AuthService>();

? ? ? ? }

```

其中

JobProvider:

public class JobProvider : IConfigurationProvider

? ? {

? ? ? ? public IEnumerable<RecurringJobInfo> Load()

? ? ? ? {

? ? ? ? ? ? var result = new List<RecurringJobInfo>();

? ? ? ? ? ? var assembly = Assembly.GetEntryAssembly();

? ? ? ? ? ? if (assembly == null) return result;

? ? ? ? ? ? foreach (var type in assembly.GetTypes())

? ? ? ? ? ? {

? ? ? ? ? ? ? ? foreach (var method in type.GetTypeInfo().DeclaredMethods)

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? //if(!method.IsDefined(typeof(RecurringJobInfo),false))

? ? ? ? ? ? ? ? ? ? //? ? continue;

? ? ? ? ? ? ? ? ? ? var attribute = method.GetCustomAttribute<RecurringJobAttribute>(false);

? ? ? ? ? ? ? ? ? ? if (attribute == null) continue;

? ? ? ? ? ? ? ? ? ? if (string.IsNullOrWhiteSpace(attribute.RecurringJobId))

? ? ? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? ? ? attribute.RecurringJobId =method.GetRecurringJobId();

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? result.Add(new RecurringJobInfo()

? ? ? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? ? ? RecurringJobId = attribute.RecurringJobId,

? ? ? ? ? ? ? ? ? ? ? ? Cron = attribute.Cron,

? ? ? ? ? ? ? ? ? ? ? ? Queue = attribute.Queue,

? ? ? ? ? ? ? ? ? ? ? ? Enable = attribute.Enabled,

? ? ? ? ? ? ? ? ? ? ? ? Method = method,

? ? ? ? ? ? ? ? ? ? ? ? TimeZone = TimeZoneInfo.Local

? ? ? ? ? ? ? ? ? ? });

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? ? ? return result;

? ? ? ? }


? ? }

LogEverythingAttribute:

public class LogEverythingAttribute : JobFilterAttribute, IClientFilter, IServerFilter, IElectStateFilter, IApplyStateFilter

? ? {

? ? ? ? private static readonly ILog Logger = LogProvider.GetCurrentClassLogger();

? ? ? ? public void OnCreating(CreatingContext filterContext)

? ? ? ? {

? ? ? ? ? ? Logger.InfoFormat("Creating a job based on method `{0}`...", filterContext.Job.Method.Name);

? ? ? ? ? ? WriteLog(

? ? ? ? ? ? ? ? $"{ApiConfig.HangfireLogUrl}\\OnCreating-{(filterContext.Job.Method.Name)}-{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.txt",

? ? ? ? ? ? ? ? $"Creating a job based on method `{filterContext.Job.Method.Name}`... . 時(shí)間為:{DateTime.Now:yyyy-MM-dd-HH-mm-ss}");

? ? ? ? }

? ? ? ? public void OnCreated(CreatedContext filterContext)

? ? ? ? {

? ? ? ? ? ? WriteLog(

? ? ? ? ? ? ? ? $"{ApiConfig.HangfireLogUrl}\\OnCreated-{(filterContext.BackgroundJob?.Id ?? "0")}-{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.txt",

? ? ? ? ? ? ? ? $"Job that is based on method `{filterContext.Job.Method.Name}` has been created with id `{filterContext.BackgroundJob?.Id}` . 時(shí)間為:{DateTime.Now:yyyy-MM-dd-HH-mm-ss} \r\n");

? ? ? ? ? ? Logger.InfoFormat(

? ? ? ? ? ? ? ? "Job that is based on method `{0}` has been created with id `{1}`",

? ? ? ? ? ? ? ? filterContext.Job.Method.Name,

? ? ? ? ? ? ? ? filterContext.BackgroundJob?.Id);

? ? ? ? }

? ? ? ? public void OnPerforming(PerformingContext filterContext)

? ? ? ? {

? ? ? ? ? ? Logger.InfoFormat("Starting to perform job `{0}`", filterContext.BackgroundJob.Id);

? ? ? ? ? ? WriteLog(

? ? ? ? ? ? ? ? $"{ApiConfig.HangfireLogUrl}\\OnPerforming-{(filterContext.BackgroundJob?.Id ?? "0")}-{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.txt",

? ? ? ? ? ? ? ? $"Starting to perform job `{filterContext.BackgroundJob.Id}` . 時(shí)間為:{DateTime.Now:yyyy-MM-dd-HH-mm-ss} \r\n");

? ? ? ? }

? ? ? ? public void OnPerformed(PerformedContext filterContext)

? ? ? ? {

? ? ? ? ? ? Logger.InfoFormat("Job `{0}` has been performed", filterContext.BackgroundJob.Id);

? ? ? ? ? ? WriteLog(

? ? ? ? ? ? ? ? $"{ApiConfig.HangfireLogUrl}\\OnPerformed-{(filterContext.BackgroundJob?.Id ?? "0")}-{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.txt",

? ? ? ? ? ? ? ? $"Job `{ filterContext.BackgroundJob.Id}` has been performed . 時(shí)間為:{DateTime.Now:yyyy-MM-dd-HH-mm-ss} \r\n");

? ? ? ? }

? ? ? ? public void OnStateElection(ElectStateContext context)

? ? ? ? {

? ? ? ? ? ? var failedState = context.CandidateState as FailedState;

? ? ? ? ? ? if (failedState != null)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? Logger.WarnFormat(

? ? ? ? ? ? ? ? ? ? "Job `{0}` has been failed due to an exception `{1}`",

? ? ? ? ? ? ? ? ? ? context.BackgroundJob.Id,

? ? ? ? ? ? ? ? ? ? failedState.Exception);

? ? ? ? ? ? ? ? WriteLog(

? ? ? ? ? ? ? ? ? ? $"{ApiConfig.HangfireLogUrl}\\OnStateElection-{(context.BackgroundJob?.Id ?? "0")}-{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.txt",

? ? ? ? ? ? ? ? ? ? $"Job `{context.BackgroundJob.Id}` has been failed due to an exception `{(JsonConvert.SerializeObject(failedState.Exception))}` . 時(shí)間為:{DateTime.Now:yyyy-MM-dd-HH-mm-ss} \r\n");

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? public void OnStateApplied(ApplyStateContext context, IWriteOnlyTransaction transaction)

? ? ? ? {

? ? ? ? ? ? Logger.InfoFormat(

? ? ? ? ? ? ? ? "Job `{0}` state was changed from `{1}` to `{2}`",

? ? ? ? ? ? ? ? context.BackgroundJob.Id,

? ? ? ? ? ? ? ? context.OldStateName,

? ? ? ? ? ? ? ? context.NewState.Name);

? ? ? ? ? ? WriteLog(

? ? ? ? ? ? ? ? $"{ApiConfig.HangfireLogUrl}\\OnStateApplied-{(context.BackgroundJob?.Id ?? "0")}-{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.txt",

? ? ? ? ? ? ? ? $"Job `{context.BackgroundJob.Id}` state was changed from `{context.OldStateName}` to `{context.NewState.Name}` . 時(shí)間為:{DateTime.Now:yyyy-MM-dd-HH-mm-ss} \r\n");

? ? ? ? }

? ? ? ? public void OnStateUnapplied(ApplyStateContext context, IWriteOnlyTransaction transaction)

? ? ? ? {

? ? ? ? ? ? Logger.InfoFormat(

? ? ? ? ? ? ? ? "Job `{0}` state `{1}` was unapplied.",

? ? ? ? ? ? ? ? context.BackgroundJob.Id,

? ? ? ? ? ? ? ? context.OldStateName);

? ? ? ? ? ? WriteLog(

? ? ? ? ? ? ? ? $"{ApiConfig.HangfireLogUrl}\\OnStateUnapplied-{(context.BackgroundJob?.Id ?? "0")}-{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.txt",

? ? ? ? ? ? ? ? $"Job `{context.BackgroundJob.Id}` state `{context.OldStateName}` was unapplied . 時(shí)間為:{DateTime.Now:yyyy-MM-dd-HH-mm-ss} \r\n");

? ? ? ? }

? ? ? ? /// <summary>

? ? ? ? /// 寫入文本

? ? ? ? /// </summary>

? ? ? ? /// <param name="path">路徑</param>

? ? ? ? /// <param name="message"></param>

? ? ? ? public void WriteLog(string path,string message)

? ? ? ? {

? ? ? ? ? ? var fileUrl = path;

? ? ? ? ? ? if (!File.Exists(fileUrl))

? ? ? ? ? ? {

? ? ? ? ? ? ? ? File.Create(fileUrl).Close();

? ? ? ? ? ? }

? ? ? ? ? ? FileStream fs = new FileStream(fileUrl, FileMode.Append);

? ? ? ? ? ? byte[] data = System.Text.Encoding.Default.GetBytes(message??"");

? ? ? ? ? ? fs.Write(data, 0, data.Length);

? ? ? ? ? ? fs.Close();

? ? ? ? }

? ? }


2.?Configure 配置

public void Configure(IApplicationBuilder app, IHostingEnvironment env)

? ? ? ? {

? ? ? ? ? ? if (env.IsDevelopment())

? ? ? ? ? ? {

? ? ? ? ? ? ? ? app.UseDeveloperExceptionPage();

? ? ? ? ? ? }

? ? ? ? ? ? else

? ? ? ? ? ? {

? ? ? ? ? ? ? ? // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.

? ? ? ? ? ? ? ? app.UseHsts();

? ? ? ? ? ? }

? ? ? ? ? ? //app.UseHttpsRedirection();

? ? ? ? ? ? //app.UseMvc();

? ? ? ? ? ? app.UseStaticFiles();

? ? ? ? ? ? //app.UseHangfireServer();//啟動(dòng)hangfire 服務(wù)

? ? ? ? ? ? app.UseAuthentication();

? ? ? ? ? ? app.UseSession();

? ? ? ? ? ? app.UseMvc(routes =>

? ? ? ? ? ? {

? ? ? ? ? ? ? ? routes.MapRoute(

? ? ? ? ? ? ? ? ? ? name: "default",

? ? ? ? ? ? ? ? ? ? template: "{controller=Login}/{action=Index}");

? ? ? ? ? ? ? ? routes.MapRoute(

? ? ? ? ? ? ? ? ? ? name: "areas",

? ? ? ? ? ? ? ? ? ? template: "{area:exists}/{controller=Login}/{action=Index}/{id?}");

? ? ? ? ? ? });

? ? ? ? ? ? //配置任務(wù)屬性

? ? ? ? ? ? var jobOptions = new BackgroundJobServerOptions()

? ? ? ? ? ? {

? ? ? ? ? ? ? ? Queues = new[] { "default", "apis", "job" },//隊(duì)列名稱,只能小寫

? ? ? ? ? ? ? ? WorkerCount = Environment.ProcessorCount * 5,//并發(fā)任務(wù)數(shù)

? ? ? ? ? ? ? ? ServerName = "hangfire"http://服務(wù)器名稱

? ? ? ? ? ? };

? ? ? ? ? ? app.UseHangfireServer(jobOptions);

? ? ? ? ? ? //配置hangfire訪問(wèn)權(quán)限

? ? ? ? ? ? var options = new DashboardOptions()

? ? ? ? ? ? {

? ? ? ? ? ? ? ? Authorization = new[] { new HangfireAuthorizationFilter() },


? ? ? ? ? ? };

? ? ? ? ? ? app.UseHangfireDashboard("/hangfire", options);//啟動(dòng)hangfire 面板

? ? ? ? ? ? //HandfireExtension.Register();

? ? ? ? ? ? //app.Run(ctx =>

? ? ? ? ? ? //{

? ? ? ? ? ? //? ? ctx.Response.Redirect($"{Configuration["WebRootUrl"]}/hangfire"); //可以支持虛擬路徑或者index.html這類起始頁(yè).

? ? ? ? ? ? //? ? return Task.FromResult(0);

? ? ? ? ? ? //});

? ? ? ? }


第四步:

具體樣例

第五步:

dotnet core 部署在 iis 上,如果不設(shè)置 閑置超時(shí)的話? iis 會(huì) 自動(dòng)閑置

可根據(jù)項(xiàng)目情況 調(diào)整 或? 轉(zhuǎn)換成 windows service 或計(jì)劃任務(wù)

結(jié)尾:

github demo 地址:https://github.com/xiehanbing/JobHangfire

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容