Lazily initialize the internal CloudWatch Logs client to avoid a deadlock when using log4net #269
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Issue #, if available:
#253, aws/aws-sdk-net#1968, DOTNET-5636
Description of changes:
There's a possible deadlock when using:
I wrote a longer description with stack traces in aws/aws-sdk-net#1968 (comment), but in summary:
LogManager.GetLogger
to activate ourAWSAppender
. This gets this lock in log4net'sDefaultRepositorySelector
, then initializes the internal CloudWatch Logs client. The client initialization needs to access the configured retry mode here, via the staticFallbackInternalConfigurationFactory.RetryMode
.AWSLoggerCore
loads credentials which potentially kicks off this timer inDefaultInstanceProfileAWSCredentials
. This starts a new thread for loading the IMDS credentials. As of AWSSDK.Core 3.7.1 when the IMDS endpoint became configurable, this relies on the staticFallbackInternalConfigurationFactory.EC2MetadataServiceEndpoint
for resolving the IMDS endpoint here. The static constructor forFallbackInternalConfigurationFactory
will createEnvironmentVariableInternalConfiguration
instance, which gets its own logger here.This deadlocks when the static constructor for
FallbackInternalConfigurationFactory
is run on thread 2 because:FallbackInternalConfigurationFactory
static constructor to finish while holding the log4net lock.FallbackInternalConfigurationFactory
static constructor, but is blocked on thread 1 when creating additional loggers inside the static constructor.By delaying the initialization of the internal CloudWatch Logs client, we allow thread 1 above to finish before thread 2 starts.
Testing
Alternatives I considered:
FallbackInternalConfigurationFactory
- but I think it's useful, and this would be hard to enforce this permanently.DefaultInstanceProfileAWSCredentials
onFallbackInternalConfigurationFactory
, and have it resolve the IMDS itself from the env var or profile withoutFallbackInternalConfigurationFactory
(and its logging) - again I think the logging is useful, and like keeping the configuration loading + caching centralizedBy submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.