के साथ ऑनस्डिंग हेडर्स डेडलॉक को हल करना मैं कटाना प्रोजेक्ट द्वारा प्रदान किए गए ओपनआईडी कनेक्ट प्रमाणीकरण मिडलवेयर का उपयोग करने की कोशिश कर रहा हूं।कटाना ओपनआईडी कनेक्ट मिडलवेयर
वहाँ जो इन परिस्थितियों में एक गतिरोध का कारण बनता है कार्यान्वयन में एक बग है:
- एक मेजबान जहां अनुरोध धागे की आत्मीयता (जैसे आईआईएस) है में चल रहा है।
- ओपनआईडी कनेक्ट मेटाडाटा दस्तावेज़ पुनर्प्राप्त नहीं किया गया है या कैश की गई प्रति समाप्त हो गई है।
- एप्लिकेशन प्रमाणीकरण विधि के लिए
SignOut
पर कॉल करता है। - एप्लिकेशन में एक क्रिया होती है जो प्रतिक्रिया स्ट्रीम को लिखने का कारण बनती है।
प्रमाणीकरण मिडलवेयर मेजबान सिग्नलिंग से कॉलबैक को संभालने के तरीके के कारण होता है जो हेडर भेजे जा रहे हैं।
private static void OnSendingHeaderCallback(object state)
{
AuthenticationHandler handler = (AuthenticationHandler)state;
handler.ApplyResponseAsync().Wait();
}
से Microsoft.Owin.Security.Infrastructure.AuthenticationHandler
जब लौटे Task
पहले से ही पूरा कर लिया है जो इसे OpenID Connect के मामले में नहीं किया है Task.Wait()
करने के लिए कॉल केवल सुरक्षित है: समस्या के मूल इस विधि में है मिडलवेयर।
मिडलवेयर इसकी कॉन्फ़िगरेशन की कैश की गई प्रति प्रबंधित करने के लिए Microsoft.IdentityModel.Protocols.ConfigurationManager<T>
का उदाहरण उपयोग करता है। यह SemaphoreSlim
का उपयोग एसिंक्रोनस लॉक और कॉन्फ़िगरेशन प्राप्त करने के लिए HTTP दस्तावेज़ पुनर्प्राप्ति के रूप में एक असंगत कार्यान्वयन है। मुझे लगता है कि यह डेडलॉक Wait()
कॉल का ट्रिगर होगा।
public async Task<T> GetConfigurationAsync(CancellationToken cancel)
{
DateTimeOffset now = DateTimeOffset.UtcNow;
if (_currentConfiguration != null && _syncAfter > now)
{
return _currentConfiguration;
}
await _refreshLock.WaitAsync(cancel);
try
{
Exception retrieveEx = null;
if (_syncAfter <= now)
{
try
{
// Don't use the individual CT here, this is a shared operation that shouldn't be affected by an individual's cancellation.
// The transport should have it's own timeouts, etc..
_currentConfiguration = await _configRetriever.GetConfigurationAsync(_metadataAddress, _docRetriever, CancellationToken.None);
Contract.Assert(_currentConfiguration != null);
_lastRefresh = now;
_syncAfter = DateTimeUtil.Add(now.UtcDateTime, _automaticRefreshInterval);
}
catch (Exception ex)
{
retrieveEx = ex;
_syncAfter = DateTimeUtil.Add(now.UtcDateTime, _automaticRefreshInterval < _refreshInterval ? _automaticRefreshInterval : _refreshInterval);
}
}
if (_currentConfiguration == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10803, _metadataAddress ?? "null"), retrieveEx);
}
// Stale metadata is better than no metadata
return _currentConfiguration;
}
finally
{
_refreshLock.Release();
}
}
मैं थ्रेड पूल पर निरंतरता मार्शल करने के प्रयास में बहुप्रतीक्षित कार्यों के सभी के लिए .ConfigureAwait(false)
जोड़ने की कोशिश की है, न कि ASP.NET:
इस विधि मैं कारण हो पर शक है कार्यकर्ता धागा, लेकिन मुझे डेडलॉक से बचने में कोई सफलता नहीं मिली है।
क्या कोई गहरा मुद्दा है जिसका मैं सामना कर सकता हूं? मुझे घटकों को बदलने में कोई फर्क नहीं पड़ता - मैंने पहले ही IConfiguratioManager<T>
के अपने प्रयोगात्मक कार्यान्वयन बनाए हैं। क्या कोई साधारण फिक्स है जिसे डेडलॉक को रोकने के लिए लागू किया जा सकता है?
मुझे उम्मीद नहीं है कि यह कुछ भी बदलेगा, लेकिन 'प्रतीक्षा करें()' के बजाय GetAwaiter()। GetResult() 'को आजमाएं। –
@PauloMorgado दुर्भाग्य से, 'ऑनसेंडिंग हैडर' कोड को 'प्रमाणीकरण हैंडलर' वर्ग में गहरा दफनाया गया है और इसे बदला नहीं जा सकता है। –
वैकल्पिक रूप से, 'कार्य' IsComplete 'के लिए प्रतीक्षा करने का प्रयास करें। संदर्भ स्विच किए बिना प्रतीक्षा करने के लिए [स्पिनवाइट] (https://msdn.microsoft.com/library/system.threading.spinwait.aspx "स्पिनवाइट संरचना") का उपयोग करें। –