-
Notifications
You must be signed in to change notification settings - Fork 160
"Down for maintenance" feature
The AuthP's multi-tenant code contains features to update, delete, move (hierarchical only) and move database (sharding), which I refer to as change / move. All of these changes / moves are done while the application is running, which means that a user could alter the tenant's data during a change / move. This could cause problems to the change / move, of which the worse could be corruption of the tenant data! Also, user reading a tenant during a change might contain invalid data.
In version 4.3.0 of the AuthP library a feature called "Down for maintenance" feature (sometimes shortened to "down") was added. This document explains how this feature works and what you need to do to use this optional feature.
NOTE: There is an article called How to take an ASP.NET Core web site “Down for maintenance” which covers this topic in more detail.
The "Down for maintenance" feature contains a way to divert a user's HTTP request to a "please wait" type page, if the data they want to access is set as "down". The figure below shows the case where "tenant 123" is changed / moved within "Down" section which will divert any users linked to "tenant 123" to a "please wait" page, while users not linked to “tenant 123” would work normally.
The four types of "downs" are described below. The first two are triggered by code, while the last two are manually applied via
This is triggered by the ISetRemoveStatus
service SetTenantDownWithDelayAsync
before a tenant move is run and released when the move has finished. Any tenant users linked to the tenant being moved will diverted to a "please wait" page while the "down" is in place.
NOTE: if there is a exception in the move command, then the tenant "down" will still be in place and must be manually removed via the Status controller. This gives an admin user to check the tenant data is OK before releasing the "down".
This permanently diverts all users linked to the deleted tenant to a page saying, “the tenant is deleted”. This is a permanent divert triggered by the ISetRemoveStatus
service SetTenantDownWithDelayAsync
, but can only be removed manually.
In AuthP you can't delete a tenant until all of its users are deleted, but an already logged-in tenant user could try to access the tenant. This "down" version makes sure an already logged-in tenant user is caught.
Allows an admin user to manually “down” a tenant database via a page/Web API (in the example code, a StatusController) and diverting all users linked to “downed” tenant database to a page saying, “stopped by admin”. Access to the tenant can be restored by an admin manually removing this this “down”.
This allows an admin user to manually “down” the whole application via a page/Web API (in the example code, a StatusController). Every user apart from the admin who took the app “down” will be diverted to a page with an explanation and expected time when the app will be available.
There are three parts to adding "down to maintenance" feature to your application:
- Startup: Registering the services / middleware
- Adding a StatusController (or an equivalent Web API)
- Using the ISetRemoveStatus service to set / remove a “down” state
There are two parts to setup the register the “down for maintenance” feature:
- Registering the “down for maintenance” services
- Adding the “down for maintenance” middleware.
_NOTE: See Example4's Program's file (hierarchical tenant design) or Example6's Program's file (single-level + sharding) for examples of the setup.
Both parts are applied in the ASP.NET Core Program / Startup code. First is the registering of the FileStore cache, which holds the various “down” statuses, and the ISetRemoveStatus
service, which provide simple methods to add / remove “down” statuses. The code below is added in the startup section that registers services with the .NET dependency injection provider.
builder.Services.AddDistributedFileStoreCache(options =>
{
options.WhichVersion = FileStoreCacheVersions.Class;
}, builder.Environment);
builder.Services.AddTransient<ISetRemoveStatus, SetRemoveStatus>();
The “down for maintenance” middleware is added in the “app” part of the ASP.NET Core startup code – see the highlighted line that adds the extra middleware.
var app = builder.Build();
//other app code left out
app.UseAuthentication();
app.UseAuthorization();
//The DownForMaintenance needs the type of multi-tenant the app is using
app.UseDownForMaintenance(TenantTypes.HierarchicalTenant);
//other code left out
You need pages / APIs to handle the following:
- For the admin users
- Look at all the current “downs” and have the ability to remove any
- Manually set the app “down” (with messages for the users)
- Manually set a tenant “down”
- For diverted users
- Tenant down while being updated
- Tenant down by admin
- Tenant is deleted
- App Down
In the Example4 web site (hierarchical tenant design) and Example6 web site (single-level + sharding) I have a controller called StatusController that contains the actions / pages listed above. Please look at the Example4's StatusController
for an example of what you need to create.
NOTE: the diverted pages are hard coded into the RedirectUsersViaStatusData
class, while the controller’s name can be changed. If you want to have different urls for the diverted pages, then you need to copy the code and register your version of the RedirectUsersViaStatusData class. See the Changing the “down for maintenance” middleware section for more on this.
The SetRemoveStatus
class contains the code to set, remove and display the “down” statues in the FileStore distributed cache. This service creates the cache key which defines the type of divert that the user should be diverted to.
The AppDown divert has its own method called SetAppDown
which takes in the ManuelAppDownDto
class. This allows the admin user's UserId (which means that user won't be diverted) and a Message and ExpectedTimeDownMinutes properties that the admin user can fill in to let the users what is going on and when the application will be back up. It's also up to the admin user to remove the AppDown divert by selecting that divert shown in list of all diverts provided by the StatusController Index.
For tenant diverts there is a method called SetTenantDownWithDelayAsync
which takes various parameters to create the correctly named "down" entry in the FileStore database. It also returns the code to remove the "down" entry after the tenant change has finished - see the code taken from Example6's TenantController
[HttpPost]
[ValidateAntiForgeryToken]
[HasPermission(Example6Permissions.MoveTenantDatabase)]
public async Task<IActionResult> MoveDatabase(ShardingSingleLevelTenantDto input)
{
//This a) sets the tenant down entry and delays (default: 100 ms) to make sure
//already running requests have stopped before returning.
//It also returns the Func to run after the change has finished.
//This Func will remove the tenant down entry.
var removeDownAsync = await _upDownService
.SetTenantDownWithDelayAsync(TenantDownVersions.Update, input.TenantId);
var status = await _authTenantAdmin.MoveToDifferentDatabaseAsync(
input.TenantId, input.HasOwnDb, input.ConnectionName);
//This removes the tenant down entry
await removeDownAsync();
return status.HasErrors
? RedirectToAction(nameof(ErrorDisplay),
new { errorMessage = status.GetAllErrors() })
: RedirectToAction(nameof(Index), new { message = status.Message });
}
A couple of the tenant downs are slightly different from others.
- Tenant Delete: In this case you don't don't remove the tenant down after the delete unless there is a error.
- Hierarchical Move : The hierarchical move needs to lock two parts of the tenant data - the data to be moved and the tenant the data is moved too. The
SetTenantDownWithDelayAsync
method has a optional parameter calledparentId
which set up another tenant "down" entry. See the [Example4'sTenantController](https://github.com/JonPSmith/AuthPermissions.AspNetCore/blob/main/Example4.MvcWebApp.IndividualAccounts/Controllers/TenantController.cs) and look at the Post
Move` action.
The middleware code is in the RedirectUsersViaStatusData
class has code to look for certain "down" entries and diverts to to a preset set of Controller + Action as described in this document. But what if your application needs to be change what the middleware does? For instance, to change the URL of the diverts.
The answer you can change the middleware by creating a new class and register your middleware in the same way as the , i.e app.UseMyMiddleware()
. Any if your new middleware uses the same "down" key / value format for entries in the FileStore database, then the ISetRemoveStatus
service will still work
NOTE: If you plan to replace the middleware code I recommend you read the 4. Understanding the “down for maintenance” middleware section in the article called How to take an ASP.NET Core web site “Down for maintenance” which covers the various stages in the middleware, and the previous section which covers the key / value format of the "down" entries.
- Intro to multi-tenants (ASP.NET video)
- Articles in date order:
- 0. Improved Roles/Permissions
- 1. Setting up the database
- 2. Admin: adding users and tenants
- 3. Versioning your app
- 4. Hierarchical multi-tenant
- 5. Advanced technique with claims
- 6. Sharding multi-tenant setup
- 7. Three ways to add new users
- 8. The design of the sharding data
- 9. Down for maintenance article
- 10: Three ways to refresh claims
- 11. Features of Multilingual service
- 12. Custom databases - Part1
- Videos (old)
- Authentication explained
- Permissions explained
- Roles explained
- AuthUser explained
- Multi tenant explained
- Sharding explained
- How AuthP handles sharding
- How AuthP handles errors
- Languages & cultures explained
- JWT Token refresh explained
- Setup Permissions
- Setup Authentication
- Startup code
- Setup the custom database feature
- JWT Token configuration
- Multi tenant configuration
- Using Permissions
- Using JWT Tokens
- Creating a multi-tenant app
- Supporting multiple languages
- Unit Test your AuthP app