Scenario : We have Configuration Page in Tridion, sometimes we get Error on Production Servers that the Configuration Page is not Published, that means it is not in DD4T Cache nor in Broker. We are using DD4T 2.2 and SDL Web 8.5
Findings: Error comes exactly for the same time(5 minutes, strangelly which is DD4T Cache duration as well) then it goes away and everything seems to be working fine. When i went through the Code for DD4T Page Factory, it basically tries to search for a page from DD4T Cache and if is not in Cache then it fetch the Page from Broker and if it finds the page then it stores it in DD4T Cache , so the next time it will serve the Page from DD4T Cache only. There is one more thing like if Page is not in Cache nor in Broker then it stores the Page in Cache with the Page Title "DD4T-Special-Value-PageNotFound", so the next time if we visit any Page and if the Page is in Cache but with the Page Title "DD4T-Special-Value-PageNotFound" then it will directly return null from Cache itself. And this will happen till the Cache duration which is Set in the Configuration File. So basically First time if the page is not in Cache nor in Broker , DD4T set that special page title and store such pages in Cache so the next time it will Directly return null from Cache itself. (Please correct me if i am wrong). This is what i got in DD4T page Factry Method:
In Our case Like we are getting null from Page Factory for exactly 5 minutes (DD4T Cache Duration) , i assume Some how the Page Title set to that DD4T Special Page Title and we get the Configuration Page Error. Now the big Question is how? What my Suspect is that as it Uses PublicationId to Generate Cache Key and For some Special case it is not able to resolve the Publication Id and that is how the Page Title is Set to "DD4T-Special-Value-PageNotFound" . But As it Uses DD4T FactoryBase Class Private Property "PublicationID" which actually set it From PublicationReolver, i don't know how it would not able ti resolve it ? This is what we got in DD4t Factory Base class:
Note : We have our Custom Publication Resolver which Resolve the PublicationID using GetPublicationMapping Method of DynamicMappingRetriever Class of Tridion.ContentDelivery.DynamicContent And we added a lock there around 6 months back to fix some other Thread issue in Tridion Assembly. No matching Localization found for Url I am not sure if this issue seems to be happen after No Localization Fix or not.
So we do this :
public int ResolvePublicationId()
{
return this.FindMapping().PublicationId;
}
Where ResolvePublicationId is method of our Custom Publication Resolver Class.
To Retrieve Configurations we Call our Custom PUblicationResolver, And in LoadConfiguration Method we Call PageFctory TryFindPage Method to Retrieve page, where it exactly breaks.
public IDictionary<string, string> RetrieveConfiguration()
{
var pubId = _publicationResolver.ResolvePublicationId();
var key = _cacheKeyFormat.FormatString(pubId);
var configuration = _cacheAgent.Load(key) as IDictionary<string, string>;
if (configuration == null)
{
configuration = LoadConfiguration();
if (configuration != null)
{
_cacheAgent.Store(key, _cacheRegion, configuration);
}
}
}
I am not sure if Custom Publication Resolver is actually Causing issue or not as ideally it should not, because TryFindPage pageFactory Method should use its Own PublicationReolver to resolve publication Id. Beacuse it resolve from Factory Base.
Here is the code for LoadConfiguration:
private Dictionary<string, string> LoadConfiguration()
{
var pubId = _publicationResolver.ResolvePublicationId();
_logger.Debug("about to load configuration page. Url: {0}".FormatString(URL));
var page = GetPage(URL);
if (page == null)
{
_logger.Error("configuration page is not published. Url : {0}".FormatString(URL));
throw new Exception("configuration page not found. Url: {0}; Is the page published?".FormatString(URL));
}}
public IPage GetPage(string url)
{
_logger.Debug("GetPage - Processing request for page: {0}", url);
var currentUrl = _publicationResolver.GetBaseUri().AbsolutePath ;
IPage page;
if (_pageFactory.TryFindPage(Uri.EscapeUriString(currentUrl), out page))
{
return page;
}
else
return null;
}
Where Url is configuration Page Url and GetBaseURI is Method of Our Custom Publication Resolver which returns base URI of the current publication.
Update: I got More information From New Relic alerts :