diff --git a/docs/guide/durability/leadership-and-troubleshooting.md b/docs/guide/durability/leadership-and-troubleshooting.md index 843eb9db9..7641d41cc 100644 --- a/docs/guide/durability/leadership-and-troubleshooting.md +++ b/docs/guide/durability/leadership-and-troubleshooting.md @@ -63,7 +63,7 @@ builder.UseWolverine(opts => } }); -using var host = builder.Build();~~~~ +using var host = builder.Build(); await host.StartAsync(); ``` snippet source | anchor diff --git a/docs/guide/durability/managing.md b/docs/guide/durability/managing.md index ffae4056c..f3adc5306 100644 --- a/docs/guide/durability/managing.md +++ b/docs/guide/durability/managing.md @@ -165,3 +165,25 @@ If you just want to export the SQL to create the necessary database objects, you dotnet run -- db-dump export.sql ``` where `export.sql` should be a file name. + +## Disabling All Persistence + +Let's say that you want to use the command line tooling to generate OpenAPI documentation, but do so +without Wolverine being able to connect to any external databases (or transports, and you'll have to disable both for this to work). +You can now do that with the option shown below as part of an [Alba](https://jasperfx.github.io/alba) test: + + + +```cs +using var host = await AlbaHost.For(builder => +{ + builder.ConfigureServices(services => + { + // You probably have to do both + services.DisableAllExternalWolverineTransports(); + services.DisableAllWolverineMessagePersistence(); + }); +}); +``` +snippet source | anchor + diff --git a/docs/guide/extensions.md b/docs/guide/extensions.md index 8b845e1e9..c81998ef5 100644 --- a/docs/guide/extensions.md +++ b/docs/guide/extensions.md @@ -109,7 +109,7 @@ internal class DisableExternalTransports : IWolverineExtension } } ``` -snippet source | anchor +snippet source | anchor And that extension is just added to the application's IoC container at test bootstrapping time like this: diff --git a/docs/guide/http/multi-tenancy.md b/docs/guide/http/multi-tenancy.md index add0bea40..222f40c9d 100644 --- a/docs/guide/http/multi-tenancy.md +++ b/docs/guide/http/multi-tenancy.md @@ -265,7 +265,7 @@ public static string NoTenantNoProblem() return "hey"; } ``` -snippet source | anchor +snippet source | anchor If the above usage completely disabled all tenant id detection or validation, in the case of an endpoint that *might* be @@ -283,7 +283,7 @@ public static string MaybeTenanted(IMessageBus bus) return bus.TenantId ?? "none"; } ``` -snippet source | anchor +snippet source | anchor diff --git a/src/Http/Wolverine.Http.Tests/Wolverine.Http.Tests.csproj b/src/Http/Wolverine.Http.Tests/Wolverine.Http.Tests.csproj index 72ff061ad..62205bf2b 100644 --- a/src/Http/Wolverine.Http.Tests/Wolverine.Http.Tests.csproj +++ b/src/Http/Wolverine.Http.Tests/Wolverine.Http.Tests.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/Http/Wolverine.Http.Tests/bootstrap_with_no_persistence.cs b/src/Http/Wolverine.Http.Tests/bootstrap_with_no_persistence.cs new file mode 100644 index 000000000..58cfa0842 --- /dev/null +++ b/src/Http/Wolverine.Http.Tests/bootstrap_with_no_persistence.cs @@ -0,0 +1,31 @@ +using Alba; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Wolverine.Persistence.Durability; +using Wolverine.Tracking; + +namespace Wolverine.Http.Tests; + +public class bootstrap_with_no_persistence +{ + [Fact] + public async Task start_up_with_no_persistence() + { + #region sample_bootstrap_with_no_persistence + + using var host = await AlbaHost.For(builder => + { + builder.ConfigureServices(services => + { + // You probably have to do both + services.DisableAllExternalWolverineTransports(); + services.DisableAllWolverineMessagePersistence(); + }); + }); + + #endregion + + host.Services.GetRequiredService().ShouldBeOfType(); + host.GetRuntime().Storage.ShouldBeOfType(); + } +} \ No newline at end of file diff --git a/src/Http/Wolverine.Http.Tests/multi_tenancy_detection_and_integration.cs b/src/Http/Wolverine.Http.Tests/multi_tenancy_detection_and_integration.cs index 72eb065c5..cfbd16c2f 100644 --- a/src/Http/Wolverine.Http.Tests/multi_tenancy_detection_and_integration.cs +++ b/src/Http/Wolverine.Http.Tests/multi_tenancy_detection_and_integration.cs @@ -5,6 +5,8 @@ using IntegrationTests; using Marten; using Marten.Metadata; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; @@ -41,6 +43,7 @@ public void Dispose() protected async Task configure(Action configure) { var builder = WebApplication.CreateBuilder([]); + builder.Services.AddScoped(); // Haven't gotten around to it yet, but there'll be some end to @@ -57,17 +60,21 @@ protected async Task configure(Action configure) }); builder.Services.AddWolverineHttp(); + builder.Services.AddAuthentication("test"); + builder.Services.AddAuthorization(); // Setting up Alba stubbed authentication so that we can fake // out ClaimsPrincipal data on requests later - var securityStub = new AuthenticationStub() + var securityStub = new AuthenticationStub("test") .With("foo", "bar") .With(JwtRegisteredClaimNames.Email, "guy@company.com") .WithName("jeremy"); - + // Spinning up a test application using Alba theHost = await AlbaHost.For(builder, app => { + app.UseAuthentication(); + app.UseAuthorization(); app.MapWolverineEndpoints(configure); }, securityStub); @@ -367,12 +374,14 @@ public async Task does_tag_current_activity_with_tenant_id() public static class TenantedEndpoints { + [Authorize] [WolverineGet("/tenant/route/{tenant}")] public static string GetTenantIdFromRoute(IMessageBus bus) { return bus.TenantId; } + [Authorize] [WolverineGet("/tenant")] public static string GetTenantIdFromWhatever(IMessageBus bus, HttpContext httpContext) { @@ -470,4 +479,12 @@ public static CustomActivityFeature FromHttpContext(HttpContext httpContext) var activity = httpContext.Features.Get()?.Activity; return new CustomActivityFeature(activity); } +} + +public class StubAuthenticationHandlerProvider : IAuthenticationHandlerProvider +{ + public Task GetHandlerAsync(HttpContext context, string authenticationScheme) + { + throw new NotImplementedException(); + } } \ No newline at end of file diff --git a/src/Persistence/Wolverine.RDBMS/Polling/DatabaseBatcher.cs b/src/Persistence/Wolverine.RDBMS/Polling/DatabaseBatcher.cs index 923dbca48..8171a7c07 100644 --- a/src/Persistence/Wolverine.RDBMS/Polling/DatabaseBatcher.cs +++ b/src/Persistence/Wolverine.RDBMS/Polling/DatabaseBatcher.cs @@ -78,12 +78,19 @@ await _executor.Value.InvokeAsync(new DatabaseOperationBatch(_database, operatio public async Task DrainAsync() { - _internalCancellation.Cancel(); + try + { + _internalCancellation.Cancel(); - _batchingBlock.Complete(); - await _batchingBlock.Completion; + _batchingBlock.Complete(); + await _batchingBlock.Completion; - _executingBlock.Complete(); - await _executingBlock.Completion; + _executingBlock.Complete(); + await _executingBlock.Completion; + } + catch (Exception e) + { + _logger.LogError(e, "Error trying to drain the current database batcher"); + } } } \ No newline at end of file diff --git a/src/Wolverine/HostBuilderExtensions.cs b/src/Wolverine/HostBuilderExtensions.cs index 91c09ab45..462168f64 100644 --- a/src/Wolverine/HostBuilderExtensions.cs +++ b/src/Wolverine/HostBuilderExtensions.cs @@ -378,6 +378,20 @@ public static IServiceCollection DisableAllExternalWolverineTransports(this ISer } #endregion + + /// + /// Disable all Wolverine message persistence bootstrapping and durability agents. This + /// was built for the case of needing to run the application for OpenAPI generation when + /// the database might not be available + /// + /// + /// + public static IServiceCollection DisableAllWolverineMessagePersistence(this IServiceCollection services) + { + services.AddSingleton(); + services.AddSingleton(); + return services; + } #region sample_DisableExternalTransports @@ -391,6 +405,15 @@ public void Configure(WolverineOptions options) #endregion + internal class DisablePersistence : IWolverineExtension + { + public void Configure(WolverineOptions options) + { + options.Durability.DurabilityMetricsEnabled = false; + options.Durability.DurabilityAgentEnabled = false; + } + } + /// /// Override the durability mode of Wolverine to be "Solo". This is valuable in automated /// testing scenarios to make application activation and teardown faster and to bypass diff --git a/src/Wolverine/Runtime/WolverineRuntime.HostService.cs b/src/Wolverine/Runtime/WolverineRuntime.HostService.cs index e174b6bcc..4a395a914 100644 --- a/src/Wolverine/Runtime/WolverineRuntime.HostService.cs +++ b/src/Wolverine/Runtime/WolverineRuntime.HostService.cs @@ -25,9 +25,12 @@ public async Task StartAsync(CancellationToken cancellationToken) await ApplyAsyncExtensions(); - foreach (var configuresRuntime in Options.Transports.OfType().ToArray()) + if (!Options.ExternalTransportsAreStubbed) { - await configuresRuntime.ConfigureAsync(this); + foreach (var configuresRuntime in Options.Transports.OfType().ToArray()) + { + await configuresRuntime.ConfigureAsync(this); + } } // Build up the message handlers