IdentityServer is a separate micro-service, other micro-services use it for authentication via JWT tokens.
Set DelayLoadMetadata = true in middleware options. (Some background: this was done to make Startup of micro-services more reliable and independent from external factors, in this case request to discovery endpoint which might be not available at startup time)
Stop the IdentityServer website.
Make a request to one of the micro-services which use IdentityServer authentication
Start the IdentityServer website.
Make the request again
Expected result:
Step 3 fails with
"System.InvalidOperationException: IDX10803: Unable to create to obtain configuration from ... "
exception.
Step 5 succeeds, because IdentityServer is up and running again and metadata can be retrieved.
Actual result:
All subsequent requests fail with the same exception. There is no retry behavior for retrieving discovery endpoint metadata.
Cause:
Lazy<T> is used when initializing LocalValidation (Same situation is in ConfigureLocalValidationmethod.):
if (options.LocalValidationOptions != null)
{
_localValidationFunc = new Lazy<AppFunc>(() =>
{
var localBuilder = app.New();
localBuilder.UseOAuthBearerAuthentication(options.LocalValidationOptions.Value);
localBuilder.Run(ctx => next(ctx.Environment));
return localBuilder.Build();
}, true);
}
Passing true is the same as using LazyThreadSafetyMode.ExecutionAndPublication. This ensures that only one thread can initialize Lazy, but this also caches exception in case it is thrown during initialization. So all subsequent calls to Lazy.Value will experience the same cached exception thrown every time. In this case the only way to "heal" a micro-service is restart.
I would suggest to use LazyThreadSafetyMode.PublicationOnly mode: multiple threads can invoke the initialization logic but the first thread to complete the initialization successfully sets the value of the Lazy instance. This would make the middleware more fault-tolerant by enabling implicit retry behavior in subsequent requests.
Scenario:
IdentityServer is a separate micro-service, other micro-services use it for authentication via JWT tokens.
DelayLoadMetadata = true
in middleware options. (Some background: this was done to make Startup of micro-services more reliable and independent from external factors, in this case request to discovery endpoint which might be not available at startup time)Expected result: Step 3 fails with
Step 5 succeeds, because IdentityServer is up and running again and metadata can be retrieved.
Actual result:
All subsequent requests fail with the same exception. There is no retry behavior for retrieving discovery endpoint metadata.
Cause:
Lazy<T>
is used when initializing LocalValidation (Same situation is inConfigureLocalValidation
method.):Passing true is the same as using, but this also caches exception in case it is thrown during initialization. So all subsequent calls to Lazy.Value will experience the same cached exception thrown every time. In this case the only way to "heal" a micro-service is restart.
LazyThreadSafetyMode.ExecutionAndPublication
. This ensures that only one thread can initialize LazyI would suggest to use instance. This would make the middleware more fault-tolerant by enabling implicit retry behavior in subsequent requests.
LazyThreadSafetyMode.PublicationOnly
mode: multiple threads can invoke the initialization logic but the first thread to complete the initialization successfully sets the value of the Lazy