1
1
using System ;
2
2
using System . Data ;
3
+ using System . Diagnostics ;
3
4
using System . Threading ;
4
5
using System . Threading . Tasks ;
5
6
using Hangfire ;
6
7
using Hangfire . Annotations ;
7
8
using Hangfire . Client ;
8
9
using Hangfire . Common ;
10
+ using Hangfire . InMemory ;
9
11
using Hangfire . Server ;
10
12
using Hangfire . SqlServer ;
11
13
using Hangfire . States ;
14
+ using Microsoft . AspNetCore . Mvc . Infrastructure ;
15
+ using Microsoft . Extensions . Configuration ;
12
16
using Microsoft . Extensions . DependencyInjection ;
13
17
using Microsoft . Extensions . DependencyInjection . Extensions ;
14
18
using Microsoft . Extensions . Hosting ;
15
19
using Microsoft . Extensions . Logging ;
20
+ using OpenTelemetry . Trace ;
16
21
17
22
namespace NetCoreSample
18
23
{
19
24
class Program
20
25
{
26
+ // To use in-memory store instead of database:
27
+ // dotnet run -- --UseInMemory true
28
+
29
+ // To show trace console exporter output:
30
+ // dotnet run -- --TraceConsoleExporter true
31
+
32
+ public static readonly ActivitySource ActivitySource = new ActivitySource ( nameof ( NetCoreSample ) ) ;
33
+
21
34
static async Task Main ( string [ ] args )
22
35
{
23
- var host = new HostBuilder ( )
24
- . ConfigureLogging ( x => x . AddConsole ( ) . SetMinimumLevel ( LogLevel . Information ) )
36
+ var host = Host . CreateDefaultBuilder ( args )
37
+ . ConfigureLogging ( x => x
38
+ . AddSimpleConsole ( )
39
+ . SetMinimumLevel ( LogLevel . Information ) )
25
40
. ConfigureServices ( ( hostContext , services ) =>
26
41
{
27
42
services . Configure < HostOptions > ( option =>
@@ -49,19 +64,40 @@ static async Task Main(string[] args)
49
64
services . TryAddSingleton < IBackgroundJobStateChanger > ( x => new CustomBackgroundJobStateChanger (
50
65
new BackgroundJobStateChanger ( x . GetRequiredService < IJobFilterProvider > ( ) ) ) ) ;
51
66
52
- services . AddHangfire ( ( provider , configuration ) => configuration
67
+ var useInMemory = hostContext . Configuration . GetValue < bool > ( "UseInMemory" ) ;
68
+ services . AddHangfire ( ( provider , configuration ) => {
69
+ configuration
53
70
. SetDataCompatibilityLevel ( CompatibilityLevel . Version_170 )
54
- . UseSimpleAssemblyNameTypeSerializer ( )
55
- . UseSqlServerStorage (
56
- @"Server=.\;Database=Hangfire.Sample;Trusted_Connection=True;" ,
57
- provider . GetRequiredService < SqlServerStorageOptions > ( ) ) ) ;
71
+ . UseSimpleAssemblyNameTypeSerializer ( ) ;
72
+ if ( useInMemory ) {
73
+ configuration . UseInMemoryStorage ( ) ;
74
+ }
75
+ else
76
+ {
77
+ configuration . UseSqlServerStorage (
78
+ @"Server=.\;Database=Hangfire.Sample;Trusted_Connection=True;" ,
79
+ provider . GetRequiredService < SqlServerStorageOptions > ( ) ) ;
80
+ }
81
+ } ) ;
58
82
59
83
services . AddHostedService < RecurringJobsService > ( ) ;
84
+ services . AddHostedService < BackgroundJobsService > ( ) ;
60
85
services . AddHangfireServer ( options =>
61
86
{
62
87
options . StopTimeout = TimeSpan . FromSeconds ( 15 ) ;
63
88
options . ShutdownTimeout = TimeSpan . FromSeconds ( 30 ) ;
64
89
} ) ;
90
+
91
+ var traceConsoleExporter = hostContext . Configuration . GetValue < bool > ( "TraceConsoleExporter" ) ;
92
+ services . AddOpenTelemetry ( )
93
+ . WithTracing ( tracing => {
94
+ tracing . AddSource ( DiagnosticsActivityFilter . DefaultListenerName ) ;
95
+ tracing . AddSource ( nameof ( NetCoreSample ) ) ;
96
+ if ( traceConsoleExporter )
97
+ {
98
+ tracing . AddConsoleExporter ( ) ;
99
+ }
100
+ } ) ;
65
101
} )
66
102
. Build ( ) ;
67
103
@@ -123,24 +159,39 @@ internal class RecurringJobsService : BackgroundService
123
159
{
124
160
private readonly IBackgroundJobClient _backgroundJobs ;
125
161
private readonly IRecurringJobManager _recurringJobs ;
126
- private readonly ILogger < RecurringJobScheduler > _logger ;
162
+ private readonly ILogger < RecurringJobsService > _logger ;
163
+ private readonly ILoggerFactory _loggerFactory ;
127
164
128
165
public RecurringJobsService (
129
166
[ NotNull ] IBackgroundJobClient backgroundJobs ,
130
167
[ NotNull ] IRecurringJobManager recurringJobs ,
131
- [ NotNull ] ILogger < RecurringJobScheduler > logger )
168
+ [ NotNull ] ILogger < RecurringJobsService > logger ,
169
+ ILoggerFactory loggerFactory )
132
170
{
133
171
_backgroundJobs = backgroundJobs ?? throw new ArgumentNullException ( nameof ( backgroundJobs ) ) ;
134
172
_recurringJobs = recurringJobs ?? throw new ArgumentNullException ( nameof ( recurringJobs ) ) ;
135
173
_logger = logger ?? throw new ArgumentNullException ( nameof ( logger ) ) ;
174
+ _loggerFactory = loggerFactory ;
136
175
}
137
176
138
177
protected override Task ExecuteAsync ( CancellationToken stoppingToken )
139
178
{
140
179
try
141
180
{
142
- _recurringJobs . AddOrUpdate ( "seconds" , ( ) => Console . WriteLine ( "Hello, seconds!" ) , "*/15 * * * * *" ) ;
143
- _recurringJobs . AddOrUpdate ( "minutely" , ( ) => Console . WriteLine ( "Hello, world!" ) , Cron . Minutely ) ;
181
+ _logger . LogInformation ( "Creating recurring jobs" ) ;
182
+
183
+ using ( var activity = Program . ActivitySource . StartActivity ( "enqueue seconds" ) )
184
+ {
185
+ _logger . LogInformation ( "Creating job seconds, trace_id={ActivityTraceId}" , activity . TraceId ) ;
186
+ _recurringJobs . AddOrUpdate ( "seconds" , ( ) => Hello ( "seconds" ) , "*/15 * * * * *" ) ;
187
+ }
188
+
189
+ using ( var activity = Program . ActivitySource . StartActivity ( "enqueue minutely" ) )
190
+ {
191
+ _logger . LogInformation ( "Creating job minutely (hello world), trace_id={ActivityTraceId}" , activity . TraceId ) ;
192
+ _recurringJobs . AddOrUpdate ( "minutely" , ( ) => Hello ( "world" ) , Cron . Minutely ) ;
193
+ }
194
+
144
195
_recurringJobs . AddOrUpdate ( "hourly" , ( ) => Console . WriteLine ( "Hello" ) , "25 15 * * *" ) ;
145
196
_recurringJobs . AddOrUpdate ( "neverfires" , ( ) => Console . WriteLine ( "Can only be triggered" ) , "0 0 31 2 *" ) ;
146
197
@@ -161,5 +212,71 @@ protected override Task ExecuteAsync(CancellationToken stoppingToken)
161
212
162
213
return Task . CompletedTask ;
163
214
}
215
+
216
+ public void Hello ( string name )
217
+ {
218
+ Console . WriteLine ( $ "Hello, { name } !") ;
219
+ var logger = _loggerFactory . CreateLogger < RecurringJobsService > ( ) ;
220
+ logger . LogInformation ( "Hello, {Name}! trace_id={ActivityTraceId}" , name , Activity . Current ? . TraceId ) ;
221
+ }
164
222
}
223
+
224
+ internal class BackgroundJobsService : BackgroundService
225
+ {
226
+ private readonly IBackgroundJobClient _backgroundJobs ;
227
+ private readonly ILogger _logger ;
228
+ private readonly ILoggerFactory _loggerFactory ;
229
+
230
+ public BackgroundJobsService (
231
+ [ NotNull ] IBackgroundJobClient backgroundJobs ,
232
+ [ NotNull ] ILogger < BackgroundJobsService > logger ,
233
+ ILoggerFactory loggerFactory )
234
+ {
235
+ _backgroundJobs = backgroundJobs ?? throw new ArgumentNullException ( nameof ( backgroundJobs ) ) ;
236
+ _logger = logger ?? throw new ArgumentNullException ( nameof ( logger ) ) ;
237
+ _loggerFactory = loggerFactory ;
238
+ }
239
+
240
+ protected override Task ExecuteAsync ( CancellationToken stoppingToken )
241
+ {
242
+ try
243
+ {
244
+ _logger . LogInformation ( "Creating backgriound jobs" ) ;
245
+
246
+ using ( var activity = Program . ActivitySource . StartActivity ( "enqueue" ) )
247
+ {
248
+ _logger . LogInformation ( "Creating job 10, trace_id={ActivityTraceId}" , activity . TraceId ) ;
249
+ var jobId1 = _backgroundJobs . Enqueue ( ( ) => Job ( 10 ) ) ;
250
+ }
251
+ using ( var activity = Program . ActivitySource . StartActivity ( "schedule" ) )
252
+ {
253
+ _logger . LogInformation ( "Scheduling job 20, continue with 30, trace_id={ActivityTraceId}" , activity . TraceId ) ;
254
+ var jobId2 = _backgroundJobs . Schedule ( ( ) => Job ( 20 ) , TimeSpan . FromSeconds ( 30 ) ) ;
255
+ var jobId3 = _backgroundJobs . ContinueJobWith ( jobId2 , ( ) => Job ( 30 ) ) ;
256
+ }
257
+ using ( var activity = Program . ActivitySource . StartActivity ( "error" ) )
258
+ {
259
+ _logger . LogInformation ( "Scheduling error job 40, trace_id={ActivityTraceId}" , activity . TraceId ) ;
260
+ var jobId4 = _backgroundJobs . Schedule ( ( ) => Job ( 40 ) , TimeSpan . FromSeconds ( 60 ) ) ;
261
+ }
262
+ }
263
+ catch ( Exception e )
264
+ {
265
+ _logger . LogError ( e , "An exception occurred while creating recurring jobs." ) ;
266
+ }
267
+
268
+ return Task . CompletedTask ;
269
+ }
270
+
271
+ public void Job ( int counter ) {
272
+ Console . WriteLine ( "Hello, job {0}!" , counter ) ;
273
+ var logger = _loggerFactory . CreateLogger < BackgroundJobsService > ( ) ;
274
+ logger . LogInformation ( "Hello, job {Counter} trace_id={ActivityTraceId}" , counter , Activity . Current ? . TraceId ) ;
275
+ if ( counter == 40 )
276
+ {
277
+ throw new InvalidOperationException ( "Counter 40 is invalid." ) ;
278
+ }
279
+ }
280
+ }
281
+
165
282
}
0 commit comments