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