Skip to content

Commit 103830f

Browse files
authored
Simplify servicecollection extensions (#3)
- Breaking change: removes DI builder pattern - Breaking change: drop netcoreapp3.1 support Other: - Update to C# 10 features and use of .NET 6 SDK +semver:major
1 parent 13dcea4 commit 103830f

14 files changed

Lines changed: 197 additions & 248 deletions

.editorconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# Remove the line below if you want to inherit .editorconfig settings from higher directories
22
root = true
33

4+
[*]
5+
charset = utf-8
6+
47
# C# files
58
[*.cs]
69

.github/workflows/CI.yml

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,30 @@ name: CI
22

33
on:
44
push:
5-
branches: [main]
5+
branches:
6+
- "*"
67
pull_request:
78
branches: [main]
89

910
jobs:
1011
ci-build:
1112
runs-on: ${{ matrix.os }}
1213
strategy:
14+
fail-fast: false
1315
matrix:
1416
os: [ubuntu-latest, windows-latest]
1517
steps:
1618
- uses: actions/checkout@v2
1719
- uses: actions/setup-dotnet@v1
1820
with:
19-
dotnet-version: "3.1.x"
20-
- uses: actions/setup-dotnet@v1
21-
with:
22-
dotnet-version: "5.0.x"
23-
- uses: actions/setup-dotnet@v1
24-
with:
25-
dotnet-version: "6.0.x"
21+
dotnet-version: "6.0.100-rc.2.21458.9"
2622
include-prerelease: true
23+
- run: dotnet --info
2724
- name: Restore dependencies
2825
run: dotnet restore
2926
- name: Build
3027
run: dotnet build --no-restore
3128
- name: Test
3229
run: dotnet test --no-build --verbosity normal
30+
- name: PackTest
31+
run: dotnet pack

.github/workflows/PreRelease.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,12 @@ jobs:
1111
- uses: actions/checkout@v2
1212
with:
1313
fetch-depth: 0
14-
- uses: actions/setup-dotnet@v1
15-
with:
16-
dotnet-version: "3.1.x"
1714
- uses: actions/setup-dotnet@v1
1815
with:
1916
dotnet-version: "5.0.x"
2017
- uses: actions/setup-dotnet@v1
2118
with:
22-
dotnet-version: "6.0.x"
19+
dotnet-version: "6.0.100-rc.2.21458.9"
2320
include-prerelease: true
2421
- name: Restore dependencies
2522
run: dotnet restore

.github/workflows/Release.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,12 @@ jobs:
1111
- uses: actions/checkout@v2
1212
with:
1313
fetch-depth: 0
14-
- uses: actions/setup-dotnet@v1
15-
with:
16-
dotnet-version: "3.1.x"
1714
- uses: actions/setup-dotnet@v1
1815
with:
1916
dotnet-version: "5.0.x"
2017
- uses: actions/setup-dotnet@v1
2118
with:
22-
dotnet-version: "6.0.x"
19+
dotnet-version: "6.0.100-rc.2.21458.9"
2320
include-prerelease: true
2421
- name: Restore dependencies
2522
run: dotnet restore

README.md

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
[![main](https://github.com/slackbot-net/CronBackgroundServices/workflows/CI/badge.svg)](https://github.com/slackbot-net/CronBackgroundServices/actions) [![NuGet](https://img.shields.io/nuget/v/CronBackgroundServices.svg)](https://www.nuget.org/packages/CronBackgroundServices/)
22
[![NuGet](https://img.shields.io/nuget/vpre/CronBackgroundServices.svg)](https://www.nuget.org/packages/CronBackgroundServices/)
33

4-
5-
64
### CronBackgroundServices
75

86
.NET BackgroundService jobs triggered by configured Cron Expressions
97

10-
118
### Installation
129

1310
```bash
@@ -18,20 +15,43 @@ $ dotnet add package CronBackgroundServices
1815
Jobs are configured during DI registration:
1916

2017
```csharp
21-
services.AddRecurringActions()
18+
services
2219
.AddRecurrer<MyCustomRecurringJob>()
2320
.AddRecurrer<MySecondJob>()
24-
.Build();
2521
```
2622

2723
Each job has to implement `IRecurringAction`. If you want a different TimeZone than UTC you have to override the default interface method `GetTimeZoneId`.
2824

2925
```csharp
3026
public interface IRecurringAction
3127
{
32-
28+
29+
/// <summary>
30+
/// The job to be executed at intervals defined by the Cron expression
31+
/// </summary>
32+
/// <returns></returns>
3333
Task Process(CancellationToken stoppingToken);
34+
35+
/// <summary>
36+
/// The cron expression (including seconds) as defined by the Cronos library:
37+
/// See https://github.com/HangfireIO/Cronos#cron-format
38+
/// Ex: Every second: */1 * * * * *
39+
/// Ex: Every minute: 0 */1 * * * *
40+
/// Ex: Every midnight: 0 0 */1 * * *
41+
/// Ex: First of every month 0 0 0 1 * *
42+
/// </summary>
43+
/// <returns>A valid Cron Expression</returns>
3444
string Cron { get; }
45+
46+
/// <summary>
47+
/// Optional: The TimeZone in which the Cron expression should be based on.
48+
/// Defaults to UTC (Europe/London or GMT Standard Time)
49+
///
50+
/// NB! When overriding this and targeting versions below .NET 6, use platform specific identifiers
51+
/// If your runtime is .NET 6 or above, it's not required. It will handles the conversion:
52+
/// See https://github.com/dotnet/runtime/pull/49412
53+
/// </summary>
54+
/// <returns>timezoneId</returns>
3555
string GetTimeZoneId()
3656
{
3757
return !RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "Europe/London" : "GMT Standard Time";

Samples/ConsoleApp/ConsoleApp.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
<PropertyGroup>
44
<TargetFramework>net6.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<LangVersion>preview</LangVersion>
57
</PropertyGroup>
68

79
<ItemGroup>

Samples/ConsoleApp/Program.cs

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,32 @@
1-
using System;
2-
using System.Threading;
3-
using System.Threading.Tasks;
4-
using CronBackgroundServices;
5-
using Microsoft.Extensions.DependencyInjection;
61
using Microsoft.Extensions.Hosting;
7-
using Microsoft.Extensions.Logging;
2+
using CronBackgroundServices;
83

94
Host.CreateDefaultBuilder(args)
10-
.ConfigureLogging(logging => logging.SetMinimumLevel(LogLevel.Trace))
11-
.ConfigureServices((_, services) => services.AddRecurringActions().AddRecurrer<MyCustomRecurringJob>().Build())
5+
.ConfigureServices(services => services
6+
.AddRecurrer<EveryThreeSeconds>()
7+
.AddRecurrer<EveryFiveSeconds>())
128
.Build()
139
.Run();
1410

15-
public class MyCustomRecurringJob : IRecurringAction
11+
public class EveryFiveSeconds : IRecurringAction
1612
{
17-
private readonly ILogger<MyCustomRecurringJob> _logger;
13+
public string Cron => "*/5 * * * * *";
1814

19-
public MyCustomRecurringJob(ILogger<MyCustomRecurringJob> logger)
20-
{
21-
_logger = logger;
22-
}
23-
public Task Process(CancellationToken stoppingToken)
15+
public Task Process(CancellationToken stoppingToken) => Logger.Log("🕔 Tick 5th second 5️⃣ 🖐");
16+
}
17+
18+
public class EveryThreeSeconds : IRecurringAction
19+
{
20+
public string Cron => "*/3 * * * * *";
21+
22+
public Task Process(CancellationToken stoppingToken) => Logger.Log("🕒 Tick 3rd second 3️⃣ 🥉");
23+
}
24+
25+
static class Logger
26+
{
27+
public static Task Log(string msg)
2428
{
25-
_logger.LogInformation("Tick");
29+
Console.WriteLine(msg);
2630
return Task.CompletedTask;
2731
}
28-
29-
public string Cron => "* * * * * *"; // Every 30 seconds, in the zero-th minute, every hour, https://github.com/HangfireIO/Cronos#usage
3032
}
31-
Lines changed: 43 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,63 @@
1-
using System;
2-
using System.Linq;
3-
using System.Threading;
4-
using System.Threading.Tasks;
51
using Microsoft.Extensions.Hosting;
62
using Microsoft.Extensions.Logging;
73

8-
namespace CronBackgroundServices
4+
namespace CronBackgroundServices;
5+
6+
internal class CronBackgroundService : BackgroundService
97
{
10-
internal class CronBackgroundService : BackgroundService
8+
protected readonly IRecurringAction Action;
9+
private readonly ILogger _logger;
10+
private readonly Timing _timing;
11+
12+
public CronBackgroundService(IRecurringAction action, ILogger logger)
1113
{
12-
protected readonly IRecurringAction Action;
13-
private readonly ILogger _logger;
14-
private readonly Timing _timing;
14+
_timing = new Timing(action.GetTimeZoneId());
15+
Action = action;
16+
_logger = logger;
17+
Cron = action.Cron;
18+
_logger.LogTrace($"Using {Cron} and timezone '{_timing.TimeZoneInfo.Id}. The time in this timezone: {_timing.RelativeNow()}'");
19+
}
1520

16-
public CronBackgroundService(IRecurringAction action, ILogger logger)
17-
{
18-
_timing = new Timing(action.GetTimeZoneId());
19-
Action = action;
20-
_logger = logger;
21-
Cron = action.Cron;
22-
_logger.LogTrace($"Using {Cron} and timezone '{_timing.TimeZoneInfo.Id}. The time in this timezone: {_timing.RelativeNow()}'");
23-
}
21+
private string Cron { get; }
2422

25-
private string Cron { get; }
23+
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
24+
{
25+
DateTimeOffset? next = null;
2626

27-
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
27+
do
2828
{
29-
DateTimeOffset? next = null;
29+
var now = _timing.RelativeNow();
3030

31-
do
31+
if (next == null)
3232
{
33-
var now = _timing.RelativeNow();
33+
next = _timing.GetNextOccurenceInRelativeTime(Cron);
34+
var uText = _timing.Get10NextOccurrences(Cron);
35+
var logText = $"Ten next occurrences :\n{uText.Aggregate((x, y) => x + "\n" + y)}";
36+
_logger.LogTrace(logText);
37+
}
3438

35-
if (next == null)
36-
{
37-
next = _timing.GetNextOccurenceInRelativeTime(Cron);
38-
var uText = _timing.Get10NextOccurrences(Cron);
39-
var logText = $"Ten next occurrences :\n{uText.Aggregate((x, y) => x + "\n" + y)}";
40-
_logger.LogTrace(logText);
41-
}
42-
43-
if (now > next)
39+
if (now > next)
40+
{
41+
try
4442
{
45-
try
46-
{
47-
await Action.Process(stoppingToken);
48-
}
49-
catch (Exception e)
50-
{
51-
_logger.LogError(e, e.Message);
52-
}
53-
54-
next = _timing.GetNextOccurenceInRelativeTime(Cron);
55-
_logger.LogTrace($"Next at {next.Value.DateTime.ToLongDateString()} {next.Value.DateTime.ToLongTimeString()}");
43+
await Action.Process(stoppingToken);
5644
}
57-
else
45+
catch (Exception e)
5846
{
59-
// needed for graceful shutdown for some reason.
60-
// 100ms chosen so it doesn't affect calculating the next
61-
// cron occurence (lowest possible: every second)
62-
await Task.Delay(100);
47+
_logger.LogError(e, e.Message);
6348
}
6449

65-
} while (!stoppingToken.IsCancellationRequested);
66-
}
50+
next = _timing.GetNextOccurenceInRelativeTime(Cron);
51+
_logger.LogTrace($"Next at {next.Value.DateTime.ToLongDateString()} {next.Value.DateTime.ToLongTimeString()}");
52+
}
53+
else
54+
{
55+
// needed for graceful shutdown for some reason.
56+
// 100ms chosen so it doesn't affect calculating the next
57+
// cron occurence (lowest possible: every second)
58+
await Task.Delay(100);
59+
}
6760

61+
} while (!stoppingToken.IsCancellationRequested);
6862
}
6963
}

src/CronBackgroundServices/CronBackgroundServices.csproj

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFrameworks>netcoreapp3.1;net5.0;net6.0</TargetFrameworks>
4+
<TargetFrameworks>net5.0;net6.0</TargetFrameworks>
55
<RootNamespace>CronBackgroundServices</RootNamespace>
66
<PackageId>CronBackgroundServices</PackageId>
77
<Authors>John Korsnes</Authors>
@@ -16,26 +16,21 @@
1616
<PackageIconUrl>images/cron.png</PackageIconUrl>
1717
<PackageIcon>cron.png</PackageIcon>
1818
<RepositoryType>git</RepositoryType>
19-
<DotNet6Version>6.0.0-preview.4.21253.7</DotNet6Version>
19+
<ImplicitUsings>enable</ImplicitUsings>
20+
<LangVersion>latest</LangVersion>
2021
</PropertyGroup>
2122

2223
<ItemGroup>
23-
<PackageReference Include="Cronos" Version="0.7.0" />
24+
<PackageReference Include="Cronos" Version="0.7.1" />
2425
</ItemGroup>
2526
<ItemGroup Condition="'$(TargetFramework)' == 'net6.0'">
26-
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="$(DotNet6Version)" />
27-
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="$(DotNet6Version)" />
27+
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0-*" />
28+
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0-*" />
2829
</ItemGroup>
2930
<ItemGroup Condition="'$(TargetFramework)' == 'net5.0'">
3031
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0" />
3132
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
3233
</ItemGroup>
33-
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
34-
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.0" />
35-
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.0" />
36-
</ItemGroup>
37-
38-
3934

4035
<ItemGroup>
4136
<None Include="images/cron.png" Pack="true" PackagePath="" />

0 commit comments

Comments
 (0)