Skip to content

Commit

Permalink
- add ability to inject clock for 'UtcNow' resolving
Browse files Browse the repository at this point in the history
  • Loading branch information
NooNameR committed Apr 3, 2020
1 parent ba2de54 commit 7a84bc1
Show file tree
Hide file tree
Showing 57 changed files with 894 additions and 702 deletions.
10 changes: 7 additions & 3 deletions src/Hangfire.AspNetCore/BackgroundJobServerHostedService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class BackgroundJobServerHostedService : IHostedService, IDisposable
{
private readonly BackgroundJobServerOptions _options;
private readonly JobStorage _storage;
private readonly IClock _clock;
private readonly IEnumerable<IBackgroundProcess> _additionalProcesses;
private readonly IBackgroundJobFactory _factory;
private readonly IBackgroundJobPerformer _performer;
Expand All @@ -24,17 +25,19 @@ public class BackgroundJobServerHostedService : IHostedService, IDisposable

public BackgroundJobServerHostedService(
[NotNull] JobStorage storage,
[NotNull] IClock clock,
[NotNull] BackgroundJobServerOptions options,
[NotNull] IEnumerable<IBackgroundProcess> additionalProcesses)
#pragma warning disable 618
: this(storage, options, additionalProcesses, null, null, null)
: this(storage, clock, options, additionalProcesses, null, null, null)
#pragma warning restore 618
{
}

[Obsolete("This constructor uses an obsolete constructor overload of the BackgroundJobServer type that will be removed in 2.0.0.")]
public BackgroundJobServerHostedService(
[NotNull] JobStorage storage,
[NotNull] IClock clock,
[NotNull] BackgroundJobServerOptions options,
[NotNull] IEnumerable<IBackgroundProcess> additionalProcesses,
[CanBeNull] IBackgroundJobFactory factory,
Expand All @@ -43,6 +46,7 @@ public BackgroundJobServerHostedService(
{
_options = options ?? throw new ArgumentNullException(nameof(options));
_storage = storage ?? throw new ArgumentNullException(nameof(storage));
_clock = clock ?? throw new ArgumentNullException(nameof(clock));

_additionalProcesses = additionalProcesses;

Expand All @@ -55,9 +59,9 @@ public Task StartAsync(CancellationToken cancellationToken)
{
_processingServer = _factory != null && _performer != null && _stateChanger != null
#pragma warning disable 618
? new BackgroundJobServer(_options, _storage, _additionalProcesses, null, null, _factory, _performer, _stateChanger)
? new BackgroundJobServer(_options, _storage, _clock, _additionalProcesses, null, null, _factory, _performer, _stateChanger)
#pragma warning restore 618
: new BackgroundJobServer(_options, _storage, _additionalProcesses);
: new BackgroundJobServer(_options, _storage, _clock, _additionalProcesses);

return Task.CompletedTask;
}
Expand Down
17 changes: 9 additions & 8 deletions src/Hangfire.AspNetCore/Dashboard/AspNetCoreDashboardContext.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
// This file is part of Hangfire.
// Copyright © 2016 Sergey Odinokov.
//
//
// Hangfire is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3
// of the License, or any later version.
//
//
// Hangfire is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
//
// You should have received a copy of the GNU Lesser General Public
// License along with Hangfire. If not, see <http://www.gnu.org/licenses/>.

using System;
Expand All @@ -26,9 +26,10 @@ public sealed class AspNetCoreDashboardContext : DashboardContext
{
public AspNetCoreDashboardContext(
[NotNull] JobStorage storage,
[NotNull] IClock clock,
[NotNull] DashboardOptions options,
[NotNull] HttpContext httpContext)
: base(storage, options)
[NotNull] HttpContext httpContext)
: base(storage, clock, options)
{
if (httpContext == null) throw new ArgumentNullException(nameof(httpContext));

Expand Down
24 changes: 14 additions & 10 deletions src/Hangfire.AspNetCore/Dashboard/AspNetCoreDashboardMiddleware.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
// This file is part of Hangfire.
// Copyright © 2016 Sergey Odinokov.
//
// Copyright 2016 Sergey Odinokov.
//
// Hangfire is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3
// of the License, or any later version.
//
//
// Hangfire is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
//
// You should have received a copy of the GNU Lesser General Public
// License along with Hangfire. If not, see <http://www.gnu.org/licenses/>.

using System;
Expand All @@ -28,31 +28,35 @@ public class AspNetCoreDashboardMiddleware
{
private readonly RequestDelegate _next;
private readonly JobStorage _storage;
private readonly IClock _clock;
private readonly DashboardOptions _options;
private readonly RouteCollection _routes;

public AspNetCoreDashboardMiddleware(
[NotNull] RequestDelegate next,
[NotNull] JobStorage storage,
[NotNull] IClock clock,
[NotNull] DashboardOptions options,
[NotNull] RouteCollection routes)
{
if (next == null) throw new ArgumentNullException(nameof(next));
if (storage == null) throw new ArgumentNullException(nameof(storage));
if (clock == null) throw new ArgumentNullException(nameof(clock));
if (options == null) throw new ArgumentNullException(nameof(options));
if (routes == null) throw new ArgumentNullException(nameof(routes));

_next = next;
_storage = storage;
_clock = clock;
_options = options;
_routes = routes;
}

public async Task Invoke(HttpContext httpContext)
{
var context = new AspNetCoreDashboardContext(_storage, _options, httpContext);
var context = new AspNetCoreDashboardContext(_storage, _clock, _options, httpContext);
var findResult = _routes.FindDispatcher(httpContext.Request.Path.Value);

if (findResult == null)
{
await _next.Invoke(httpContext);
Expand Down Expand Up @@ -96,4 +100,4 @@ public async Task Invoke(HttpContext httpContext)
await findResult.Item1.Dispatch(context);
}
}
}
}
28 changes: 16 additions & 12 deletions src/Hangfire.AspNetCore/HangfireApplicationBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
// This file is part of Hangfire.
// Copyright © 2016 Sergey Odinokov.
//
//
// Hangfire is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3
// of the License, or any later version.
//
//
// Hangfire is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
//
// You should have received a copy of the GNU Lesser General Public
// License along with Hangfire. If not, see <http://www.gnu.org/licenses/>.

using System;
Expand All @@ -33,7 +33,8 @@ public static IApplicationBuilder UseHangfireDashboard(
[NotNull] this IApplicationBuilder app,
[NotNull] string pathMatch = "/hangfire",
[CanBeNull] DashboardOptions options = null,
[CanBeNull] JobStorage storage = null)
[CanBeNull] JobStorage storage = null,
[CanBeNull] IClock clock = null)
{
if (app == null) throw new ArgumentNullException(nameof(app));
if (pathMatch == null) throw new ArgumentNullException(nameof(pathMatch));
Expand All @@ -43,12 +44,13 @@ public static IApplicationBuilder UseHangfireDashboard(
var services = app.ApplicationServices;

storage = storage ?? services.GetRequiredService<JobStorage>();
clock = clock ?? services.GetRequiredService<IClock>();
options = options ?? services.GetService<DashboardOptions>() ?? new DashboardOptions();
options.TimeZoneResolver = options.TimeZoneResolver ?? services.GetService<ITimeZoneResolver>();

var routes = app.ApplicationServices.GetRequiredService<RouteCollection>();

app.Map(new PathString(pathMatch), x => x.UseMiddleware<AspNetCoreDashboardMiddleware>(storage, options, routes));
app.Map(new PathString(pathMatch), x => x.UseMiddleware<AspNetCoreDashboardMiddleware>(storage, clock, options, routes));

return app;
}
Expand All @@ -57,16 +59,18 @@ public static IApplicationBuilder UseHangfireServer(
[NotNull] this IApplicationBuilder app,
[CanBeNull] BackgroundJobServerOptions options = null,
[CanBeNull] IEnumerable<IBackgroundProcess> additionalProcesses = null,
[CanBeNull] JobStorage storage = null)
[CanBeNull] JobStorage storage = null,
[CanBeNull] IClock clock = null)
{
if (app == null) throw new ArgumentNullException(nameof(app));

HangfireServiceCollectionExtensions.ThrowIfNotConfigured(app.ApplicationServices);

var services = app.ApplicationServices;
var lifetime = services.GetRequiredService<IApplicationLifetime>();

storage = storage ?? services.GetRequiredService<JobStorage>();
clock = clock ?? services.GetRequiredService<IClock>();
options = options ?? services.GetService<BackgroundJobServerOptions>() ?? new BackgroundJobServerOptions();
additionalProcesses = additionalProcesses ?? services.GetServices<IBackgroundProcess>();

Expand All @@ -76,9 +80,9 @@ public static IApplicationBuilder UseHangfireServer(

var server = HangfireServiceCollectionExtensions.GetInternalServices(services, out var factory, out var stateChanger, out var performer)
#pragma warning disable 618
? new BackgroundJobServer(options, storage, additionalProcesses, null, null, factory, performer, stateChanger)
? new BackgroundJobServer(options, storage, clock, additionalProcesses, null, null, factory, performer, stateChanger)
#pragma warning restore 618
: new BackgroundJobServer(options, storage, additionalProcesses);
: new BackgroundJobServer(options, storage, clock, additionalProcesses);

lifetime.ApplicationStopping.Register(() => server.SendStop());
lifetime.ApplicationStopped.Register(() => server.Dispose());
Expand Down
42 changes: 24 additions & 18 deletions src/Hangfire.AspNetCore/HangfireServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
// This file is part of Hangfire.
// Copyright © 2016 Sergey Odinokov.
//
//
// Hangfire is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3
// of the License, or any later version.
//
//
// Hangfire is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
//
// You should have received a copy of the GNU Lesser General Public
// License along with Hangfire. If not, see <http://www.gnu.org/licenses/>.

using System;
Expand All @@ -27,6 +27,7 @@
using Microsoft.Extensions.Logging;
#if NETSTANDARD2_0
using Microsoft.Extensions.Hosting;

#endif

namespace Hangfire
Expand All @@ -46,10 +47,11 @@ public static IServiceCollection AddHangfire(
{
if (services == null) throw new ArgumentNullException(nameof(services));
if (configuration == null) throw new ArgumentNullException(nameof(configuration));

// ===== Configurable services =====

services.TryAddSingletonChecked(_ => JobStorage.Current);
services.TryAddSingletonChecked(_ => SystemClock.Current);
services.TryAddSingletonChecked(_ => JobActivator.Current);
services.TryAddSingletonChecked(_ => DashboardRoutes.Routes);
services.TryAddSingletonChecked<IJobFilterProvider>(_ => JobFilterProviders.Providers);
Expand All @@ -64,18 +66,19 @@ public static IServiceCollection AddHangfire(

// ===== Client services =====

// NOTE: these, on the other hand, need to be double-checked to be sure configuration block was executed,
// NOTE: these, on the other hand, need to be double-checked to be sure configuration block was executed,
// in case of a client-only scenario with all configurables above replaced with custom implementations.

services.TryAddSingletonChecked<IBackgroundJobClient>(x =>
{
if (GetInternalServices(x, out var factory, out var stateChanger, out _))
{
return new BackgroundJobClient(x.GetRequiredService<JobStorage>(), factory, stateChanger);
return new BackgroundJobClient(x.GetRequiredService<JobStorage>(), x.GetRequiredService<IClock>(), factory, stateChanger);
}
return new BackgroundJobClient(
x.GetRequiredService<JobStorage>(),
x.GetRequiredService<IClock>(),
x.GetRequiredService<IJobFilterProvider>());
});

Expand All @@ -85,23 +88,25 @@ public static IServiceCollection AddHangfire(
{
return new RecurringJobManager(
x.GetRequiredService<JobStorage>(),
x.GetRequiredService<IClock>(),
factory,
x.GetRequiredService<ITimeZoneResolver>());
}
return new RecurringJobManager(
x.GetRequiredService<JobStorage>(),
x.GetRequiredService<IClock>(),
x.GetRequiredService<IJobFilterProvider>(),
x.GetRequiredService<ITimeZoneResolver>());
});


// IGlobalConfiguration serves as a marker indicating that Hangfire's services
// IGlobalConfiguration serves as a marker indicating that Hangfire's services
// were added to the service container (checked by IApplicationBuilder extensions).
//
// Being a singleton, it also guarantees that the configuration callback will be
//
// Being a singleton, it also guarantees that the configuration callback will be
// executed just once upon initialization, so there's no need to double-check that.
//
//
// It should never be replaced by another implementation !!!
// AddSingleton() will throw an exception if it was already registered

Expand All @@ -127,10 +132,10 @@ public static IServiceCollection AddHangfire(
// do configuration inside callback
configuration(serviceProvider, configurationInstance);
return configurationInstance;
});

return services;
}

Expand All @@ -145,6 +150,7 @@ public static IServiceCollection AddHangfireServer([NotNull] this IServiceCollec
var options = provider.GetService<BackgroundJobServerOptions>() ?? new BackgroundJobServerOptions();
var storage = provider.GetService<JobStorage>() ?? JobStorage.Current;
var clock = provider.GetService<IClock>() ?? SystemClock.Current;
var additionalProcesses = provider.GetServices<IBackgroundProcess>();
options.Activator = options.Activator ?? provider.GetService<JobActivator>();
Expand All @@ -156,7 +162,7 @@ public static IServiceCollection AddHangfireServer([NotNull] this IServiceCollec
#pragma warning disable 618
return new BackgroundJobServerHostedService(
#pragma warning restore 618
storage, options, additionalProcesses, factory, performer, stateChanger);
storage, clock, options, additionalProcesses, factory, performer, stateChanger);
});

return services;
Expand Down Expand Up @@ -186,7 +192,7 @@ internal static bool GetInternalServices(
}

private static void TryAddSingletonChecked<T>(
[NotNull] this IServiceCollection serviceCollection,
[NotNull] this IServiceCollection serviceCollection,
[NotNull] Func<IServiceProvider, T> implementationFactory)
where T : class
{
Expand All @@ -211,4 +217,4 @@ internal static void ThrowIfNotConfigured(IServiceProvider serviceProvider)
}
}
}
}
}
Loading

0 comments on commit 7a84bc1

Please sign in to comment.