From 4142fd0ac59b2afbb2b09db30feb8200663af348 Mon Sep 17 00:00:00 2001 From: Oskar Dudycz Date: Sat, 22 Jul 2023 13:02:54 +0200 Subject: [PATCH] Added docs around dynamically setting up tenants for multitenancy per database --- docs/configuration/cli.md | 2 +- docs/configuration/hostbuilder.md | 2 +- docs/configuration/multitenancy.md | 26 ++++++++++++++++--- docs/schema/extensions.md | 13 ++++++++-- src/CoreTests/adding_custom_schema_objects.cs | 2 ++ 5 files changed, 37 insertions(+), 8 deletions(-) diff --git a/docs/configuration/cli.md b/docs/configuration/cli.md index a73b1d4e66f..609f3348bcc 100644 --- a/docs/configuration/cli.md +++ b/docs/configuration/cli.md @@ -2,7 +2,7 @@ ::: warning The usage of Marten.CommandLine shown in this document is only valid for applications bootstrapped with the -[generic host builder](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-3.1) with Marten registered in the application's IoC container. +[generic host builder](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host) with Marten registered in the application's IoC container. ::: There is a separate NuGet package called _Marten.CommandLine_ that can be used to quickly add command-line tooling directly to diff --git a/docs/configuration/hostbuilder.md b/docs/configuration/hostbuilder.md index c306a1d4a9d..a7a8ecf0605 100644 --- a/docs/configuration/hostbuilder.md +++ b/docs/configuration/hostbuilder.md @@ -44,7 +44,7 @@ The `AddMarten()` method will add these service registrations to your applicatio For more information, see: -* [Dependency injection in ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1) for more explanation about the service lifetime behavior. +* [Dependency injection in ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection) for more explanation about the service lifetime behavior. * Check [identity map mechanics](/documents/identity) for an explanation of Marten session behavior * Check [storing documents and unit of work](/documents/sessions) for session basics diff --git a/docs/configuration/multitenancy.md b/docs/configuration/multitenancy.md index dc265322b41..132ae24a054 100644 --- a/docs/configuration/multitenancy.md +++ b/docs/configuration/multitenancy.md @@ -89,13 +89,31 @@ _host = await Host.CreateDefaultBuilder() snippet source | anchor +## Dynamically applying changes to tenants databases + +If you didn't call the `ApplyAllDatabaseChangesOnStartup` method, Marten would still try to create a database [upon the session creation](/documents/sessions). This action is invasive and can cause issues like timeouts, cold starts, or deadlocks. It also won't apply all defined changes upfront (so, e.g. [indexes](/documents/indexing), [custom schema extensions](/schema/extensions)). + +If you don't know the tenant upfront, you can create and apply changes dynamically by: + + + +```cs +var tenant = await theStore.Tenancy.GetTenantAsync(tenantId); +await tenant.Database.ApplyAllConfiguredChangesToDatabaseAsync(); +``` +snippet source | anchor + + +You can place this code somewhere in the tenant initialization code. For instance: + +- tenant setup procedure, +- dedicated API endpoint +- [custom session factory](/configuration/hostbuilder/#customizing-session-creation-globally), although that's not recommended for the reasons mentioned above. + ## Write your own tenancy strategy! :::tip -It is strongly recommended that you first refer to the existing Marten options for per-database multi-tenancy -before you write your own model. There are several helpers in the Marten codebase that will hopefully make -this task easier. Failing all else, please feel free to ask questions in the [Marten's Discord channel](https://discord.gg/WMxrvegf8H) about custom -multi-tenancy strategies. +It is strongly recommended that you first refer to the existing Marten options for per-database multi-tenancy before you write your own model. There are several helpers in the Marten codebase that will hopefully make this task easier. Failing all else, please feel free to ask questions in the [Marten's Discord channel](https://discord.gg/WMxrvegf8H) about custom multi-tenancy strategies. ::: The multi-tenancy strategy is pluggable. Start by implementing the `Marten.Storage.ITenancy` interface: diff --git a/docs/schema/extensions.md b/docs/schema/extensions.md index 13efdb05b49..1dd464b4c0a 100644 --- a/docs/schema/extensions.md +++ b/docs/schema/extensions.md @@ -51,6 +51,15 @@ Do note that when you use the `Add()` syntax, Marten will pass along the curr While you *can* directly implement the `ISchemaObject` interface for something Marten doesn't already support. Marten provides an even easier extensibility mechanism to add custom database objects such as Postgres tables, functions and sequences using `StorageFeatures.ExtendedSchemaObjects` using [Weasel](https://github.com/JasperFx/weasel). +::: warning +Marten will apply **Schema Feature Extensions** automatically when you call `ApplyAllConfiguredChangesToDatabaseAsync` for: + +- single schema configuration, +- [multitenancy per database](/configuration/multitenancy) with tenants known upfront. + +But it **won't apply them** for multitenancy per database with **unknown** tenants. If you cannot predict them, read the guidance on [dynamically applying changes to tenants databases](/configuration/multitenancy#dynamically-applying-changes-to-tenants-databases). +::: + ## Table Postgresql tables can be modeled with the `Table` class from `Weasel.Postgresql.Tables` as shown in this example below: @@ -100,7 +109,7 @@ $f$ language sql immutable; await theStore.Storage.ApplyAllConfiguredChangesToDatabaseAsync(); ``` -snippet source | anchor +snippet source | anchor ## Sequence @@ -122,7 +131,7 @@ StoreOptions(opts => await theStore.Storage.ApplyAllConfiguredChangesToDatabaseAsync(); ``` -snippet source | anchor +snippet source | anchor ## Extension diff --git a/src/CoreTests/adding_custom_schema_objects.cs b/src/CoreTests/adding_custom_schema_objects.cs index 1180b9c7894..f0d64d3e8eb 100644 --- a/src/CoreTests/adding_custom_schema_objects.cs +++ b/src/CoreTests/adding_custom_schema_objects.cs @@ -148,8 +148,10 @@ public async Task enable_an_extension_with_multitenancy_with_tenants_upfront_thr opts.Storage.ExtendedSchemaObjects.Add(extension); }); + #region sample_manual_single_tenancy_apply_changes var tenant = await theStore.Tenancy.GetTenantAsync(tenantId); await tenant.Database.ApplyAllConfiguredChangesToDatabaseAsync(); + #endregion await using var sessionNext = theStore.QuerySession(tenantId); var result = await sessionNext.QueryAsync("select unaccent('Æ') = 'AE';");