diff --git a/src/Runly/JobHost.cs b/src/Runly/JobHost.cs
index aff2587..9a87a9c 100644
--- a/src/Runly/JobHost.cs
+++ b/src/Runly/JobHost.cs
@@ -133,7 +133,10 @@ public static Task RunJobAsync(this IHost host)
/// The that represents the asynchronous operation.
public static Task RunJobAsync(this IHost host, CancellationToken cancellationToken)
{
- var action = host.Services.GetService();
+ using var scope = host.Services.CreateAsyncScope();
+
+ var action = scope.ServiceProvider.GetRequiredService();
+
return action?.RunAsync(cancellationToken) ?? Task.CompletedTask;
}
}
diff --git a/src/Runly/Processing/ExecutionBase.cs b/src/Runly/Processing/ExecutionBase.cs
index 4d1c99b..c367d58 100644
--- a/src/Runly/Processing/ExecutionBase.cs
+++ b/src/Runly/Processing/ExecutionBase.cs
@@ -256,7 +256,9 @@ async Task ExecuteParallelTasksAsync()
{
try
{
- await ProcessScopeAsync(provider.CreateScope());
+ using var scope = provider.CreateAsyncScope();
+
+ await ProcessScopeAsync(scope);
}
catch (Exception ex) when (Job.Config.Execution.HandleExceptions)
{
@@ -275,7 +277,7 @@ async Task ExecuteParallelTasksAsync()
///
/// The containing a scoped to get services from.
/// A representing the asynchronous execution of this method.
- async Task ProcessScopeAsync(IServiceScope scope)
+ async Task ProcessScopeAsync(AsyncServiceScope scope)
{
bool @continue = true;
var stopwatch = new Stopwatch();
diff --git a/src/Runly/ServiceExtensions.cs b/src/Runly/ServiceExtensions.cs
index 4237abd..c0ce20b 100644
--- a/src/Runly/ServiceExtensions.cs
+++ b/src/Runly/ServiceExtensions.cs
@@ -340,7 +340,7 @@ static void AddRunAction(this IServiceCollection services, JobCache cache, Confi
));
}
- services.AddSingleton(s =>
+ services.AddScoped(s =>
{
var cache = s.GetRequiredService();
@@ -369,7 +369,7 @@ public static IServiceCollection AddJob(this IServiceCollection services, JobCac
{
var info = cache.Get(config.Job.Type);
- services.AddTransient(info.JobType);
+ services.AddScoped(info.JobType);
var type = config.GetType();
diff --git a/test/Runly.Tests/Dependencies.cs b/test/Runly.Tests/Dependencies.cs
index 8e51cf4..3075af8 100644
--- a/test/Runly.Tests/Dependencies.cs
+++ b/test/Runly.Tests/Dependencies.cs
@@ -1,7 +1,9 @@
namespace Runly.Tests
{
- public class Dep1 { }
- public class Dep2 { }
+ public interface IDep1 { }
+ public class Dep1 : IDep1 { }
+ public interface IDep2 { }
+ public class Dep2 : IDep2 { }
public class Dep3 { }
public class Dep4 { }
public class Dep5 { }
diff --git a/test/Runly.Tests/Jobs.cs b/test/Runly.Tests/Jobs.cs
index ebddeb5..48d90a7 100644
--- a/test/Runly.Tests/Jobs.cs
+++ b/test/Runly.Tests/Jobs.cs
@@ -46,7 +46,22 @@ public override Task ProcessAsync(int item, Dep1 arg1)
}
}
- public class Job2 : Job
+ public class Job1WithConstructorDep : Job
+ {
+ public Job1WithConstructorDep(IDep1 dep1) : base(new Config()) { }
+
+ public override IAsyncEnumerable GetItemsAsync()
+ {
+ throw new NotImplementedException();
+ }
+
+ public override Task ProcessAsync(int item)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public class Job2 : Job
{
public Job2() : base(new Config()) { }
@@ -61,7 +76,22 @@ public override Task ProcessAsync(int item, Dep1 arg1, Dep2 arg2)
}
}
- public class Job3 : Job
+ public class Job2WithConstructorDep : Job
+ {
+ public Job2WithConstructorDep(IDep1 dep1, IDep2 dep2) : base(new Config()) { }
+
+ public override IAsyncEnumerable GetItemsAsync()
+ {
+ throw new NotImplementedException();
+ }
+
+ public override Task ProcessAsync(int item)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public class Job3 : Job
{
public Job3() : base(new Config()) { }
diff --git a/test/Runly.Tests/Scenarios/Running/Running_a_job.cs b/test/Runly.Tests/Scenarios/Running/Running_a_job.cs
index 988cd8c..a90251e 100644
--- a/test/Runly.Tests/Scenarios/Running/Running_a_job.cs
+++ b/test/Runly.Tests/Scenarios/Running/Running_a_job.cs
@@ -1,5 +1,8 @@
using FluentAssertions;
+using Microsoft.Extensions.DependencyInjection;
+using Runly.Hosting;
using Runly.Testing;
+using System;
using System.Threading.Tasks;
using Xunit;
@@ -28,5 +31,22 @@ public async Task should_run_a_single_item_job()
runner.Execution.IsComplete.Should().BeTrue();
runner.Execution.Disposition.Should().Be(Disposition.Successful);
}
- }
+
+ [Fact]
+ public async Task should_run_a_job_with_scoped_dependency_in_constructor()
+ {
+ // CreateDefaultBuilder is more strict with Environment = Dev
+ Environment.SetEnvironmentVariable("DOTNET_ENVIRONMENT", "Development");
+
+ var action = JobHost.CreateDefaultBuilder(["Job1WithConstructorDep"], typeof(UnitTest).Assembly)
+ .ConfigureServices((context, services) =>
+ {
+ services.AddScoped(s => new Dep1());
+ services.AddSingleton(s => new Dep2());
+ })
+ .Build();
+
+ await action.RunJobAsync();
+ }
+ }
}