Skip to content

Commit

Permalink
Merge branch 'hangfire_182'
Browse files Browse the repository at this point in the history
  • Loading branch information
r-win committed Jul 2, 2024
2 parents 76a1c8b + fd095a0 commit a1a2a93
Show file tree
Hide file tree
Showing 81 changed files with 1,809 additions and 631 deletions.
8 changes: 8 additions & 0 deletions Hangfire.Tags.sln
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HangfireServerTwo", "sample
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MultipleDashboards", "samples\MultipleDashboards\MultipleDashboards\MultipleDashboards.csproj", "{028B3A6D-A07D-482D-B1B3-9E00409F30D3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FaceIT.Hangfire.Tags.Mongo", "src\FaceIT.Hangfire.Tags.Mongo\FaceIT.Hangfire.Tags.Mongo.csproj", "{A8D87699-6234-417C-B60E-65121FCF2FE5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -129,6 +131,12 @@ Global
{028B3A6D-A07D-482D-B1B3-9E00409F30D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{028B3A6D-A07D-482D-B1B3-9E00409F30D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{028B3A6D-A07D-482D-B1B3-9E00409F30D3}.ReleasePro|Any CPU.ActiveCfg = Release|Any CPU
{A8D87699-6234-417C-B60E-65121FCF2FE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A8D87699-6234-417C-B60E-65121FCF2FE5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A8D87699-6234-417C-B60E-65121FCF2FE5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A8D87699-6234-417C-B60E-65121FCF2FE5}.Release|Any CPU.Build.0 = Release|Any CPU
{A8D87699-6234-417C-B60E-65121FCF2FE5}.ReleasePro|Any CPU.ActiveCfg = Debug|Any CPU
{A8D87699-6234-417C-B60E-65121FCF2FE5}.ReleasePro|Any CPU.Build.0 = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

Inspired by the lack of searching and grouping, Hangfire.Tags provides a way to search and group different jobs.

![sidemenu](https://raw.githubusercontent.com/face-it/Hangfire.Tags/master/Sidemenu.png)
![sidemenu](https://raw.githubusercontent.com/face-it/Hangfire.Tags/hangfire_182/Sidemenu-dark.png)
![dashboard](https://raw.githubusercontent.com/face-it/Hangfire.Tags/master/Dashboard.png)

## Contributers
Expand All @@ -24,6 +24,7 @@ Inspired by the lack of searching and grouping, Hangfire.Tags provides a way to
- **Filtering**: allows filtering of tags based on tags and states, this makes it easy to requeue failed jobs with a certain tag.
- **Searching**: allows you to search for tags
- **Storages**: has an storage for SQL Server, MySql, PostgreSql and initial Redis support
- **Dark and light mode**: supports the new dark and light mode support of Hangfire

## Setup

Expand Down Expand Up @@ -82,9 +83,10 @@ As usual, you may provide additional options for `UseTags()` method.

Here's what you can configure:

- **BackgroundColor** - default background color for the tags
- **TextColor** - default text color of the tags
- **Tags interface** - you can specify an autocomplete tags search (Yong Liu).
- **TagColor**/**DarkTagColor** - default background color for the tags
- **TextColor**/**TextColor** - default text color of the tags
- **Tags interface** - you can specify an autocomplete tags search (Yong Liu)
- **MaxLength** - the maximum length of the tags, automatically set to 100 for SQL Server

**NOTE**: After you initially add Hangfire.Tags (or change the options above) you may need to clear browser cache, as generated CSS/JS can be cached by browser.

Expand Down
Binary file added Sidemenu-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Sidemenu-light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed Sidemenu.png
Binary file not shown.
4 changes: 3 additions & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ environment:
branches:
only:
- master
- hangfire_182

pull_requests:
do_not_increment_build_number: true
Expand Down Expand Up @@ -41,8 +42,9 @@ artifacts:
deploy:
- provider: NuGet
api_key:
secure: y2ZAk4YAxwtybM9UoFQR3asz+EH5xfZX6nWgIvrqQ3tn1vRx8V6Pr2TPgubIfKGN
secure: Sv/gzOW796jlrE9VF/b/Lv0zKSCe2H3eXS1aFyl48p9jYrARL7S9Nlr5wioZ0kF5
skip_symbols: false
on:
branch:
- master
- hangfire_182
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Hangfire" Version="1.7.27" />
<PackageReference Include="Hangfire.Heartbeat" Version="0.5.0" />
<PackageReference Include="Hangfire" Version="1.8.2" />
<PackageReference Include="Hangfire.Heartbeat" Version="0.5.1" />
<PackageReference Include="Hangfire.Mongo" Version="1.9.6" />
<PackageReference Include="Hangfire.MySqlStorage" Version="2.0.3" />
<PackageReference Include="Hangfire.PostgreSql" Version="1.9.5" />
<PackageReference Include="Hangfire.PostgreSql" Version="1.20.0" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.1.1" />
</ItemGroup>

<ItemGroup>
Expand All @@ -20,6 +22,7 @@
<ProjectReference Include="..\..\src\FaceIT.Hangfire.Tags.SQLite\FaceIT.Hangfire.Tags.SQLite.csproj" />
<ProjectReference Include="..\..\src\FaceIT.Hangfire.Tags.SqlServer\FaceIT.Hangfire.Tags.SqlServer.csproj" />
<ProjectReference Include="..\..\src\FaceIT.Hangfire.Tags\FaceIT.Hangfire.Tags.csproj" />
<ProjectReference Include="..\..\src\FaceIT.Hangfire.Tags.Mongo\FaceIT.Hangfire.Tags.Mongo.csproj" />
</ItemGroup>

</Project>
200 changes: 125 additions & 75 deletions samples/Hangfire.Core.MvcApplication/Startup.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System;
using System.IO;
using Hangfire.Common;
using Hangfire.Dashboard;
using Hangfire.Heartbeat;
using Hangfire.MySql; //used with MySql Sample
using Hangfire.PostgreSql; //used with postgreSql Sample
Expand All @@ -13,20 +11,37 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System.Transactions;
using Hangfire.Core.MvcApplication.Jobs;
using Hangfire.SQLite;
using Hangfire.Tags.SQLite;
using Hangfire.Mongo;
using Hangfire.Mongo.Migration.Strategies;
using Hangfire.Mongo.Migration.Strategies.Backup;
using Microsoft.Extensions.Hosting;
using StackExchange.Redis;
using Hangfire.States;
using Hangfire.Storage;
using Hangfire.Storage.SQLite;
using Hangfire.Tags.Mongo;
using Hangfire.Tags.SQLite;
using Microsoft.Data.Sqlite;
using MongoDB.Driver;
using SQLite;

namespace Hangfire.Core.MvcApplication
{
internal enum Storage
{
SqlServer,
MySql,
PostgreSql,
RedisStack,
RedisPro,
Mongo,
Sqlite
}

public class ProlongExpirationTimeAttribute : JobFilterAttribute, IApplyStateFilter
{
public void OnStateApplied(ApplyStateContext context, IWriteOnlyTransaction transaction)
Expand All @@ -46,90 +61,125 @@ public Startup(IConfiguration configuration)
Configuration = configuration;
}

public IConfiguration Configuration { get; }
private IConfiguration Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
var storage = Configuration.GetValue<Storage>("Storage");

services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});

services.AddHangfireServer();
services.AddHangfire(config =>
{
//SqlServer Sample
config.UseSqlServerStorage(Configuration.GetConnectionString("DefaultConnection"), new SqlServerStorageOptions
{
JobExpirationCheckInterval = TimeSpan.FromSeconds(15),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5), // To enable Sliding invisibility fetching
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5), // To enable command pipelining
QueuePollInterval = TimeSpan.FromTicks(1) // To reduce processing delays to minimum
});
var options = new TagsOptions
var tagOptions = new TagsOptions
{
TagsListStyle = TagsListStyle.Dropdown
TagsListStyle = TagsListStyle.Dropdown,
Clean = Clean.None
};
config.UseTagsWithSql(options);
//end SqlServer Sample

//MySql Sample
// var mySqlOptions = new MySqlStorageOptions
// {
// TransactionIsolationLevel = IsolationLevel.ReadCommitted,
// QueuePollInterval = TimeSpan.FromSeconds(15),
// JobExpirationCheckInterval = TimeSpan.FromSeconds(15),
// CountersAggregateInterval = TimeSpan.FromMinutes(5),
// PrepareSchemaIfNecessary = true,
// DashboardJobListLimit = 50000,
// TransactionTimeout = TimeSpan.FromMinutes(1),
// TablesPrefix = "hangfire"
// };
// config.UseStorage(new MySqlStorage(Configuration.GetConnectionString("MySqlConnection"), mySqlOptions));
// var options = new TagsOptions
// {
// TagsListStyle = TagsListStyle.Dropdown
// };
// config.UseTagsWithMySql(options,mySqlOptions);
//end MySql Sample

//postgreSql Sample
// config.UsePostgreSqlStorage(Configuration.GetConnectionString("PostgreSqlConnection"), new PostgreSqlStorageOptions
// {
// JobExpirationCheckInterval = TimeSpan.FromSeconds(15),
// QueuePollInterval = TimeSpan.FromTicks(1) // To reduce processing delays to minimum
// });
// var options = new TagsOptions
// {
// TagsListStyle = TagsListStyle.Dropdown
// };
// config.UseTagsWithPostgreSql(options);
//end postgreSql Sample

//redis sample
// var redis = ConnectionMultiplexer.Connect(Configuration.GetConnectionString("RedisConnection"));
// Tags.Redis.StackExchange.GlobalConfigurationExtensions.UseTagsWithRedis(
// Hangfire.RedisStorageExtensions.UseRedisStorage(config, redis),
// new TagsOptions {TagsListStyle = TagsListStyle.Dropdown}
// );

// redis pro sample
// Tags.Pro.Redis.GlobalConfigurationExtensions.UseTagsWithRedis(
// Hangfire.RedisStorageGlobalConfigurationExtensions.UseRedisStorage(config, Configuration.GetConnectionString("RedisConnection")),
// new TagsOptions {TagsListStyle = TagsListStyle.Dropdown}
// );

// config.UseSQLiteStorage(Configuration.GetConnectionString("SQLiteConnection")).UseTagsWithSQLite(
// new TagsOptions
// {
// TagsListStyle = TagsListStyle.Dropdown
// });

//config.UseNLogLogProvider();

switch (storage)
{
case Storage.SqlServer:
{
//SqlServer Sample
config.UseSqlServerStorage(Configuration.GetConnectionString("DefaultConnection"),
new SqlServerStorageOptions
{
JobExpirationCheckInterval = TimeSpan.FromSeconds(15),
SlidingInvisibilityTimeout =
TimeSpan.FromMinutes(5), // To enable Sliding invisibility fetching
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5), // To enable command pipelining
QueuePollInterval = TimeSpan.FromTicks(1) // To reduce processing delays to minimum
});
config.UseTagsWithSql(tagOptions);
//end SqlServer Sample
break;
}
case Storage.MySql:
{
//MySql Sample
var mySqlOptions = new MySqlStorageOptions
{
TransactionIsolationLevel = IsolationLevel.ReadCommitted,
QueuePollInterval = TimeSpan.FromSeconds(15),
JobExpirationCheckInterval = TimeSpan.FromSeconds(15),
CountersAggregateInterval = TimeSpan.FromMinutes(5),
PrepareSchemaIfNecessary = true,
DashboardJobListLimit = 50000,
TransactionTimeout = TimeSpan.FromMinutes(1),
TablesPrefix = "hangfire"
};
config.UseStorage(new MySqlStorage(Configuration.GetConnectionString("MySqlConnection"),
mySqlOptions));
config.UseTagsWithMySql(tagOptions, mySqlOptions);
//end MySql Sample
break;
}
case Storage.PostgreSql:
{
//postgreSql Sample
config.UsePostgreSqlStorage(Configuration.GetConnectionString("PostgreSqlConnection"), new PostgreSqlStorageOptions
{
JobExpirationCheckInterval = TimeSpan.FromSeconds(15),
QueuePollInterval = TimeSpan.FromTicks(1) // To reduce processing delays to minimum
});
config.UseTagsWithPostgreSql(tagOptions);
//end postgreSql Sample
break;
}
case Storage.RedisStack:
{
//redis sample
var redis = ConnectionMultiplexer.Connect(Configuration.GetConnectionString("RedisConnection"));
Tags.Redis.StackExchange.GlobalConfigurationExtensions.UseTagsWithRedis(
Redis.StackExchange.RedisStorageExtensions.UseRedisStorage(config, redis),
tagOptions
);
break;
}
case Storage.RedisPro:
// redis pro sample
Tags.Pro.Redis.GlobalConfigurationExtensions.UseTagsWithRedis(
config.UseRedisStorage(Configuration.GetConnectionString("RedisConnection")),
tagOptions
);
break;
case Storage.Sqlite:
config.UseSQLiteStorage(Configuration.GetConnectionString("SQLiteConnection"))
.UseTagsWithSQLite(tagOptions);
break;
case Storage.Mongo:
{
// mongo sample
var mongoUrlBuilder = new MongoUrlBuilder(Configuration.GetConnectionString("MongoConnection"));
var mongoClient = new MongoClient(mongoUrlBuilder.ToMongoUrl());

var mongoStorageOptions = new MongoStorageOptions
{
MigrationOptions = new MongoMigrationOptions
{
MigrationStrategy = new MigrateMongoMigrationStrategy(),
BackupStrategy = new CollectionMongoBackupStrategy()
},
Prefix = "hangfire.mongo",
CheckConnection = true
};
config.UseMongoStorage(mongoClient, mongoUrlBuilder.DatabaseName, mongoStorageOptions)
.UseTagsWithMongo(tagOptions, mongoStorageOptions);
break;
}
}

config.UseHeartbeatPage(checkInterval: TimeSpan.FromSeconds(5));
});
services.AddHangfireServer();

services.AddMvc();
}
Expand All @@ -146,7 +196,6 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseExceptionHandler("/Home/Error");
}

app.UseHangfireServer();
app.UseHangfireDashboard();

app.UseStaticFiles();
Expand All @@ -157,9 +206,10 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

var recurringJobs = new RecurringJobManager();

RecurringJob.AddOrUpdate<Tasks>(x => x.SuccessTask(null, null), Cron.Minutely);
RecurringJob.AddOrUpdate<Tasks>("Success Task", x => x.SuccessTask(null, null), Cron.Minutely);
// RecurringJob.AddOrUpdate<Tasks>(x => x.FailedTask(null, null), "*/2 * * * *");
recurringJobs.AddOrUpdate("Failed Task", Job.FromExpression<Tasks>(x => x.FailedTask(null)), "*/2 * * * *", TimeZoneInfo.Local);
recurringJobs.AddOrUpdate("Failed Task", Job.FromExpression<Tasks>(x => x.FailedTask(null)), "*/2 * * * *",
new RecurringJobOptions { TimeZone = TimeZoneInfo.Local });

BackgroundJob.Enqueue<BaseJob>(x => x.Run());
BackgroundJob.Enqueue<DerivedJob>(x => x.Run());
Expand Down
5 changes: 3 additions & 2 deletions samples/Hangfire.Core.MvcApplication/Tasks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ namespace Hangfire.Core.MvcApplication
[Tag("task")]
internal class Tasks
{
[Tag("success", "This is a really long tag, in order to create a tag which has more than the specified amount of characters. Tags longer than a specific amount of characters won't fit in the key column of table HangFire.Set.")]
[Tag("Success", "This is a really long tag, in order to create a tag which has more than the specified amount of characters. Tags longer than a specific amount of characters won't fit in the key column of table HangFire.Set.")]
public void SuccessTask(PerformContext context, IJobCancellationToken token)
{
TextBuffer.WriteLine("Recurring Job completed successfully!");
context.AddTags("finished", context.BackgroundJob.Id);
context.AddTags("Background job id: " + context.BackgroundJob.Id);
}

[Tag("fail")]
[Tag("Fail")]
[AutomaticRetry(Attempts = 0)] // Disable retry
public void FailedTask(PerformContext context)
{
Expand Down
Loading

0 comments on commit a1a2a93

Please sign in to comment.