Skip to content

Commit fc5fd58

Browse files
authored
Make IApplicationTask async, registered as keyed service (#1331)
* Rename project Steeltoe.Management.Task to Steeltoe.Management.Tasks, to avoid naming clash with System.Threading.Task. * Make IApplicationTask async, registered as keyed service * Fixed: dispose the host after running the application task, because host.RunAsync does that too.
1 parent 66741c0 commit fc5fd58

25 files changed

+677
-411
lines changed

src/Common/src/Common/IApplicationTask.cs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,10 @@ namespace Steeltoe.Common;
1010
public interface IApplicationTask
1111
{
1212
/// <summary>
13-
/// Gets globally unique name for the task.
13+
/// Executes this task.
1414
/// </summary>
15-
string Name { get; }
16-
17-
/// <summary>
18-
/// Action which to run.
19-
/// </summary>
20-
void Run();
15+
/// <param name="cancellationToken">
16+
/// The token to monitor for cancellation requests.
17+
/// </param>
18+
Task RunAsync(CancellationToken cancellationToken);
2119
}

src/Common/src/Common/Properties/AssemblyInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
[assembly: InternalsVisibleTo("Steeltoe.Management.Endpoint")]
2929
[assembly: InternalsVisibleTo("Steeltoe.Management.Endpoint.Test")]
3030
[assembly: InternalsVisibleTo("Steeltoe.Management.Prometheus")]
31-
[assembly: InternalsVisibleTo("Steeltoe.Management.Task")]
31+
[assembly: InternalsVisibleTo("Steeltoe.Management.Tasks")]
3232
[assembly: InternalsVisibleTo("Steeltoe.Management.Tracing")]
3333
[assembly: InternalsVisibleTo("Steeltoe.Management.Tracing.Test")]
3434
[assembly: InternalsVisibleTo("Steeltoe.Management.Wavefront")]

src/Connectors/src/EntityFrameworkCore/MigrateDbContextTask.cs

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,54 +9,56 @@
99
namespace Steeltoe.Connectors.EntityFrameworkCore;
1010

1111
/// <summary>
12-
/// Applies code first migrations for the specified Entity Framework DB Context This task name is "migrate".
12+
/// Applies code-first database migrations for the specified Entity Framework Core <see cref="DbContext" />.
1313
/// </summary>
14-
/// <example>
15-
/// dotnet run runtask=migrate.
14+
/// <example><![CDATA[
15+
/// dotnet run RunTask=migrate
16+
/// ]]>
1617
/// </example>
17-
/// <typeparam name="T">
18-
/// The DBContext which to migrate.
18+
/// <typeparam name="TDbContext">
19+
/// The <see cref="DbContext" /> to run migrations from.
1920
/// </typeparam>
20-
public class MigrateDbContextTask<T> : IApplicationTask
21-
where T : DbContext
21+
public sealed class MigrateDbContextTask<TDbContext> : IApplicationTask
22+
where TDbContext : DbContext
2223
{
23-
private readonly T _db;
24-
private readonly ILogger _logger;
24+
public const string Name = "migrate";
2525

26-
public string Name => "migrate";
26+
private readonly TDbContext _dbContext;
27+
private readonly ILogger _logger;
2728

28-
public MigrateDbContextTask(T db, ILogger<MigrateDbContextTask<T>> logger)
29+
public MigrateDbContextTask(TDbContext dbContext, ILogger<MigrateDbContextTask<TDbContext>> logger)
2930
{
30-
ArgumentGuard.NotNull(db);
31+
ArgumentGuard.NotNull(dbContext);
3132
ArgumentGuard.NotNull(logger);
3233

33-
_db = db;
34+
_dbContext = dbContext;
3435
_logger = logger;
3536
}
3637

37-
public void Run()
38+
public async Task RunAsync(CancellationToken cancellationToken)
3839
{
39-
bool isNewDb = false;
40+
bool isNewDatabase = false;
4041
var migrations = new List<string>();
4142

4243
try
4344
{
44-
migrations = _db.Database.GetPendingMigrations().ToList();
45+
migrations = (await _dbContext.Database.GetPendingMigrationsAsync(cancellationToken)).ToList();
4546
}
4647
catch
4748
{
48-
isNewDb = true; // might not be true source of the error, but we'll catch real cause as part of Migrate call
49+
// This might not be the true source of the error, but we'll catch the real cause as part of the MigrateAsync call.
50+
isNewDatabase = true;
4951
}
5052

5153
_logger.LogInformation("Starting database migration...");
52-
_db.Database.Migrate();
54+
await _dbContext.Database.MigrateAsync(cancellationToken);
5355

54-
if (isNewDb)
56+
if (isNewDatabase)
5557
{
56-
migrations = _db.Database.GetAppliedMigrations().ToList();
58+
migrations = (await _dbContext.Database.GetAppliedMigrationsAsync(cancellationToken)).ToList();
5759
}
5860

59-
if (migrations.Any())
61+
if (migrations.Count > 0)
6062
{
6163
_logger.LogInformation("The following migrations have been successfully applied:");
6264

@@ -67,7 +69,7 @@ public void Run()
6769
}
6870
else
6971
{
70-
_logger.LogInformation("Database is already up to date");
72+
_logger.LogInformation("Database is already up to date.");
7173
}
7274
}
7375
}
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#nullable enable
2+
const Steeltoe.Connectors.EntityFrameworkCore.MigrateDbContextTask<TDbContext>.Name = "migrate" -> string!
23
static Steeltoe.Connectors.EntityFrameworkCore.MySql.MySqlDbContextOptionsBuilderExtensions.UseMySql(this Microsoft.EntityFrameworkCore.DbContextOptionsBuilder! optionsBuilder, System.IServiceProvider! serviceProvider) -> Microsoft.EntityFrameworkCore.DbContextOptionsBuilder!
34
static Steeltoe.Connectors.EntityFrameworkCore.MySql.MySqlDbContextOptionsBuilderExtensions.UseMySql(this Microsoft.EntityFrameworkCore.DbContextOptionsBuilder! optionsBuilder, System.IServiceProvider! serviceProvider, string? serviceBindingName) -> Microsoft.EntityFrameworkCore.DbContextOptionsBuilder!
45
static Steeltoe.Connectors.EntityFrameworkCore.MySql.MySqlDbContextOptionsBuilderExtensions.UseMySql(this Microsoft.EntityFrameworkCore.DbContextOptionsBuilder! optionsBuilder, System.IServiceProvider! serviceProvider, string? serviceBindingName, object? serverVersion, System.Action<object!>? mySqlOptionsAction) -> Microsoft.EntityFrameworkCore.DbContextOptionsBuilder!
@@ -8,10 +9,9 @@ static Steeltoe.Connectors.EntityFrameworkCore.PostgreSql.PostgreSqlDbContextOpt
89
static Steeltoe.Connectors.EntityFrameworkCore.SqlServer.SqlServerDbContextOptionsBuilderExtensions.UseSqlServer(this Microsoft.EntityFrameworkCore.DbContextOptionsBuilder! optionsBuilder, System.IServiceProvider! serviceProvider) -> Microsoft.EntityFrameworkCore.DbContextOptionsBuilder!
910
static Steeltoe.Connectors.EntityFrameworkCore.SqlServer.SqlServerDbContextOptionsBuilderExtensions.UseSqlServer(this Microsoft.EntityFrameworkCore.DbContextOptionsBuilder! optionsBuilder, System.IServiceProvider! serviceProvider, string? serviceBindingName) -> Microsoft.EntityFrameworkCore.DbContextOptionsBuilder!
1011
static Steeltoe.Connectors.EntityFrameworkCore.SqlServer.SqlServerDbContextOptionsBuilderExtensions.UseSqlServer(this Microsoft.EntityFrameworkCore.DbContextOptionsBuilder! optionsBuilder, System.IServiceProvider! serviceProvider, string? serviceBindingName, System.Action<object!>? sqlServerOptionsAction) -> Microsoft.EntityFrameworkCore.DbContextOptionsBuilder!
11-
Steeltoe.Connectors.EntityFrameworkCore.MigrateDbContextTask<T>
12-
Steeltoe.Connectors.EntityFrameworkCore.MigrateDbContextTask<T>.MigrateDbContextTask(T! db, Microsoft.Extensions.Logging.ILogger<Steeltoe.Connectors.EntityFrameworkCore.MigrateDbContextTask<T!>!>! logger) -> void
13-
Steeltoe.Connectors.EntityFrameworkCore.MigrateDbContextTask<T>.Name.get -> string!
14-
Steeltoe.Connectors.EntityFrameworkCore.MigrateDbContextTask<T>.Run() -> void
12+
Steeltoe.Connectors.EntityFrameworkCore.MigrateDbContextTask<TDbContext>
13+
Steeltoe.Connectors.EntityFrameworkCore.MigrateDbContextTask<TDbContext>.MigrateDbContextTask(TDbContext! dbContext, Microsoft.Extensions.Logging.ILogger<Steeltoe.Connectors.EntityFrameworkCore.MigrateDbContextTask<TDbContext!>!>! logger) -> void
14+
Steeltoe.Connectors.EntityFrameworkCore.MigrateDbContextTask<TDbContext>.RunAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task!
1515
Steeltoe.Connectors.EntityFrameworkCore.MySql.MySqlDbContextOptionsBuilderExtensions
1616
Steeltoe.Connectors.EntityFrameworkCore.PostgreSql.PostgreSqlDbContextOptionsBuilderExtensions
1717
Steeltoe.Connectors.EntityFrameworkCore.SqlServer.SqlServerDbContextOptionsBuilderExtensions
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using Microsoft.AspNetCore.Builder;
6+
using Microsoft.AspNetCore.Hosting;
7+
using Microsoft.EntityFrameworkCore;
8+
using Microsoft.EntityFrameworkCore.Migrations;
9+
using Microsoft.Extensions.DependencyInjection;
10+
using Steeltoe.Management.Tasks;
11+
12+
namespace Steeltoe.Connectors.EntityFrameworkCore.Test;
13+
14+
public sealed class MigrateDbContextTaskTest
15+
{
16+
[Fact]
17+
public async Task WebApplication_ExecutesMigrateTask()
18+
{
19+
const string taskName = MigrateDbContextTask<TestMigrateDbContext>.Name;
20+
string[] args = [$"RunTask={taskName}"];
21+
22+
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
23+
builder.WebHost.UseDefaultServiceProvider(options => options.ValidateScopes = true);
24+
25+
builder.Services.AddDbContext<TestMigrateDbContext>(options => options.UseSqlite("Data Source=Test.db"));
26+
builder.Services.AddTask<MigrateDbContextTask<TestMigrateDbContext>>(taskName);
27+
28+
WebApplication app = builder.Build();
29+
30+
await app.RunWithTasksAsync(CancellationToken.None);
31+
32+
TestMigrator.HasMigrated.Should().BeTrue();
33+
}
34+
35+
private sealed class TestMigrateDbContext(DbContextOptions options) : DbContext(options)
36+
{
37+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
38+
{
39+
optionsBuilder.ReplaceService<IMigrator, TestMigrator>();
40+
}
41+
}
42+
43+
private sealed class TestMigrator : IMigrator
44+
{
45+
public static bool HasMigrated { get; private set; }
46+
47+
public void Migrate(string? targetMigration = null)
48+
{
49+
throw new NotImplementedException();
50+
}
51+
52+
public Task MigrateAsync(string? targetMigration = null, CancellationToken cancellationToken = default)
53+
{
54+
HasMigrated = true;
55+
return Task.CompletedTask;
56+
}
57+
58+
public string GenerateScript(string? fromMigration = null, string? toMigration = null,
59+
MigrationsSqlGenerationOptions options = MigrationsSqlGenerationOptions.Default)
60+
{
61+
throw new NotImplementedException();
62+
}
63+
}
64+
}

src/Connectors/test/EntityFrameworkCore.Test/Steeltoe.Connectors.EntityFrameworkCore.Test.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@
77
<Import Project="..\..\..\..\shared.props" />
88

99
<ItemGroup>
10+
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="$(EntityFrameworkCoreTestVersion)" />
1011
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="$(EntityFrameworkCoreTestVersion)" />
1112
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="$(EntityFrameworkCoreTestVersion)" />
1213
<PackageReference Include="MySql.EntityFrameworkCore" Version="$(EntityFrameworkCoreTestVersion)" />
1314
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="$(EntityFrameworkCoreTestVersion)" />
1415
</ItemGroup>
1516

1617
<ItemGroup>
18+
<ProjectReference Include="..\..\..\Management\src\Tasks\Steeltoe.Management.Tasks.csproj" />
1719
<ProjectReference Include="..\..\src\EntityFrameworkCore\Steeltoe.Connectors.EntityFrameworkCore.csproj" />
1820
</ItemGroup>
1921
</Project>

src/Management/src/Task/DelegatingTask.cs

Lines changed: 0 additions & 28 deletions
This file was deleted.

src/Management/src/Task/PublicAPI.Unshipped.txt

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/Management/src/Task/TaskServiceCollectionExtensions.cs

Lines changed: 0 additions & 138 deletions
This file was deleted.

0 commit comments

Comments
 (0)