Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 'Clock' for UtcNow injection #1638

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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