[OfficeDevPnP.Core] Threadpool issue in AuthenticationManager().GetAppOnlyAuthenticatedContext(...)
See original GitHub issueHi
We noticed errors in Azure webjobs that ran this code in big for loops (i.e. customer has thousands of sites to manage). I managed to reproduce this locally:
There were not enough free threads in the ThreadPool to complete the operation
Which is caused by:
using (var context = new AuthenticationManager().GetAppOnlyAuthenticatedContext(siteUrl, clientId, clientSecret))
A thread is being created to account for access token renewal it seems (‘EnsureToken’, see screenshot below): https://github.com/pnp/PnP-Sites-Core/blob/master/Core/OfficeDevPnP.Core/AuthenticationManager.cs#L326
wi.Handle = ThreadPool.RegisterWaitForSingleObject(appOnlyAccessTokenResetEvent, ...);
Although there does seem to be a dispose method that should release the thread when exiting the using curly braces: https://github.com/pnp/PnP-Sites-Core/blob/master/Core/OfficeDevPnP.Core/AuthenticationManager.cs#L1496
It can be easily reproduced by creating a console app (.NET 4.7.2), installing NuGet package ‘SharePointPnPCoreOnline’ version 3.18.2002. The code can be found below. Open up the Threads window during a debug session (Debug > Windows > Threads) and you will see a surplus thread per context that has been created, despite the using statement (or .dispose() method). This can be seen in the screenshot below. At a certain moment in time, the maximum available threads are exhausted, which causes the error.
How can I update the this piece of (legacy) code to avoid this error?
I don’t think there is something inherently wrong with the sample script, that is a perfectly viable way to go about processing multiple sites using CSOM. Correct me if I’m wrong.
The fact remains that we need to iterate over thousands of different sites and perform 1 or 2 csom calls on them, to set some SP settings.
` using Microsoft.SharePoint.Client; using OfficeDevPnP.Core;
namespace OfficeDevPnPAuthManagerThreadIssue
{
internal class Program
{
static void Main(string[] args)
{
var siteUrl = "https://***.sharepoint.com/sites/kyataccount";
var clientId = "*****";
var clientSecret = "***";
for (int i = 0; i < 50; i++)
{
using (var context = new AuthenticationManager()
.GetAppOnlyAuthenticatedContext(siteUrl, clientId, clientSecret))
{
var web = context.Web;
context.Load(web, w => w.Title);
context.ExecuteQueryRetry();
var title = web.Title;
if(40 == i)
{
var breakPoint = "put breakpoint here";
}
}
}
}
}
}`
Issue Analytics
- State:
- Created 2 years ago
- Comments:5 (1 by maintainers)
Top GitHub Comments
@patrikhellgren, the Clone method seems to work as you mentioned! Only a single thread is used for this. Thanks!
@PieterHeemeryck Try to use context.Clone(newSiteUrl) instead, that will not get a new token as long as it is within the same host and as I understand it you will be. So something like this: