4

I am currently running Tridion 2011 SP1.

I am writing some code that runs whenever a page is published. It loops through each component template in the page, gets the component and writes out various fields to an XML document. For pages with many component templates or components with many fields this process can take a while to run. If the process takes more than 30 seconds I get an error

The operation performed by thread "EventSystem0" timed out.

Component: Tridion.ContentManager
Errorcode: 0
User: NT AUTHORITY\NETWORK SERVICE

followed by another

Thread was being aborted.


Component: Tridion.ContentManager
Errorcode: 0
User: NT AUTHORITY\NETWORK SERVICE

StackTrace Information Details:
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Delegate.DynamicInvokeImpl(Object[] args)
   at Tridion.ContentManager.Extensibility.EventSubscription.DeliverEvent(IEnumerable`1 subjects, TcmEventArgs eventArgs, EventPhases phase)

I believe I have three options.

1. Increase the timeout

This seems like a lazy solution and only hides the problem. There is no guarantee that the timeout problem won't reoccur. I'm also not sure where the timeout value is stored (I've tried changing a few values in the Tridion Content Manager.msc snap-in but no luck).

2. Do less in the actual event handler routine and have a separate process do all the hard work

This doesn't seem like the correct solution either. I would really like to keep all my event handler code in the one place. We have a solution like this in place for our live 5.3 installation and is a nightmare to maintain (it is very old and poorly written).

3. Make my code more efficient

My components have many fields and my code must delve deeper into each field if they are ComponentLinks. I guess because the properties of Tridion objects are lazy loaded there is one call to the API/database for each property I access. It takes on average 0.2 seconds to retrieve a property which soon stacks up when accessing multiple properties. If there was a way to retrieve all properties in one call this would be useful.

Any ideas?

Kevin Brydon
  • 12,524
  • 8
  • 46
  • 76
  • Check if you have any exception in the Tridion event log. Do you know what exactly is timing out? – Andrey Marchuk Sep 07 '12 at 12:20
  • I am making a lot of calls to the API to get components linked to a component. Each call takes 0.2 seconds on average. Say I have a page with 20 components and each one of these components has 10 linked components, that's 200 calls to the Tridion API to get all the information I need. 200 calls * 0.2 seconds is 40 seconds. It seems to have a 30 second timeout limit therefore an exception is raised. – Kevin Brydon Sep 07 '12 at 13:11
  • That's an interesting question Kevin. I'm afraid that getting hundreds of components just takes time. Increasing the time-out sounds like the worst of your options. As I recently tweeted it changes "the software says this action takes too long" to "the user says this action takes too long". Is adding 30 seconds to any publish actions considered acceptable? – Frank van Puffelen Sep 07 '12 at 14:24
  • In my case it doesn't really matter how long it takes the event handler to complete. The important thing is that it is allowed to complete. The users will be aware that if they publish a page with hundreds of components they won't see the changes for some considerable time, but they are assured that the changes will happen at some point in the future. I can always add some code that provides some way to update the user on progress. How would I increase the timeout? – Kevin Brydon Sep 07 '12 at 15:15

5 Answers5

6

Have you considered running your event asynchronously? You can do this by changing the following line:

EventSystem.Subscribe<IdentifiableObject,TcmEventArgs(....)

to

EventSystem.SubscribeAsync<IdentifiableObject,TcmEventArgs(....)
Quirijn
  • 3,549
  • 15
  • 30
  • Thanks for your reply. I did try this but still get a timeout error. I believe it is something to do with a timeout in the Reflection method that calls the Subscribe/SubscribeAsync methods. – Kevin Brydon Sep 07 '12 at 12:01
  • 1
    I think that is highly unlikely, because the subscribe call is not done when the event takes place, but when Tridion is started. An other explanation would be that some Tridion API call that you make from your event code is timing out (rather than the event code itself). – Quirijn Sep 07 '12 at 12:17
  • Sorry. I didn't explain that properly. I meant the method that handles the event (TcmEventHandler eventHandler) is being called via the Reflection classes. So in my case I have the method PagePublishedCommittedHandler that is being invoked by System.RuntimeMethodHandle.InvokeMethod(...) and when PagePublishedCommittedHandler doesn't return within 30 seconds it throws and exception. Maybe I'm wrong? – Kevin Brydon Sep 07 '12 at 12:29
  • To add. I have profiled my code and everything runs fine, not a single huge timeout anywhere. Its the small, 0.2 second calls to the API that add up to over 30 seconds. – Kevin Brydon Sep 07 '12 at 12:32
  • @Kevin If I understand correctly, you are trying to find the links that point towards the current component (the 'where used' functionality in the gui. This is notoriously slow. Would it be possible to rewrite your logic to start from the other end, i.e. the linkER components rather than the linkEEs? – Quirijn Sep 07 '12 at 20:35
  • I think you have misunderstood. I am not using the where used functionality. I have a component (e.g. Person) which has many fields (e.g. Address, AssociatedOrganisation) that link directly to other components. Retrieving the initial Person object takes 0.2 seconds. Retrieving each linked component takes another 0.2 seconds. Having to retrieve many components with many linked fields eventually pushes the amount of time required to over 30 seconds. – Kevin Brydon Sep 10 '12 at 07:25
2

One thing you might consider doing is using the Component's .ToXml() method and get your values from the XML DOM instead of using the Tridion API. This is usually considerably faster, and you can use XSLT or Linq to "walk" through your fields.

If you are really only interested in fields, then just use the .Content (and .Metadata) properties and, again, use Linq or XSLT or whatever technology you want to parse the xml (except RegEx perhaps).

Community
  • 1
  • 1
Nuno Linhares
  • 10,214
  • 1
  • 22
  • 42
  • I don't think this will help my problem. The API is fast enough at giving me the fields of the current component without having to resort to parsing the XML (I'm taking milliseconds fast). I have looked and .ToXML() only gets the XML for the current component. If I want to get details of the component links (and so on) I still have to make a call to the database to retrieve this (which takes 0.2 seconds). Maybe I have to pump events out to the event system to tell it "I'm still working, don't timeout"? – Kevin Brydon Sep 07 '12 at 12:48
  • You could also consider just collecting the starting info and delegating the collection/creating of the XML document to an "external" process to gather the information separately, maybe using WCF "one-way" calls? http://msdn.microsoft.com/en-us/magazine/cc163537.aspx#S1 – Nuno Linhares Sep 07 '12 at 13:15
  • This was one of the options I suggested in the original questions but I was hoping to avoid this. I'd like to keep the code that executes due to a Tridion process (in this case a page pubish) together. Is there no way I can pump out a message to tell the Tridion Event Handler that my process is busy and it shouldn't timeout? – Kevin Brydon Sep 07 '12 at 13:22
  • Not sure you can. This question would probably be better handled via Customer Support, they can reach out to Tridion R&D for an answer on this. – Nuno Linhares Sep 07 '12 at 13:23
  • I've now sent a support request to SDL. I'll update the question when I get a response. – Kevin Brydon Sep 07 '12 at 13:38
2

You are simply doing a lot of processing and that takes time. Maybe there's a technical fix, but the first thing to do in this situation is to go back to Why and What? Publishing a page is fundamentally about rendering the HTML and binaries that you want to output for that page. How long should that take?

So please could you tell us why you are doing this? Perhaps part of the effort can be moved somewhere else without compromising on good design. If we know what the purpose is, perhaps we can help more.

Dominic Cronin
  • 6,062
  • 2
  • 23
  • 56
  • The purpose is to write out some XML that our search engine (Autonomy) uses. The XML contains information on the various components on the page, one XML document per component. The information should be exactly as it is at the point of publish. – Kevin Brydon Sep 10 '12 at 07:20
  • 2
    This is a use case that is commonly met by a custom deployer (pre-2011) of by extending the storage API. (2011-onward). Of course, Content Delivery approaches rely on using the rendered output (albeit that you can choose to modify what you output if this helps). Generally - this is what you want for search. You want to index what's there. There are other possible architectures. My suggestion is that you write a new question addressing the possible ways of solving your actual problem. This question can remain to address how to deal with the issues with your current architecture. – Dominic Cronin Sep 10 '12 at 20:33
2

SDL Customer Support have advised that I increase the timeout. While not a great solution its the only one that is available. To do this

  1. On the server that the content manager is installed open the Tridion.ContentManager.config which should be located in the config/ subdirectory of the Content Manager root location, which defaults to C:\Program Files\Tridion\ or c:\Program Files (x86)\Tridion\
  2. Find the <eventSystem> node
  3. Increase the threadtimeout value (this is in seconds) to something higher (I put it to 120)
  4. Save the Tridion.ContentManager.config and restart the Tridion Content Manager Service Host service

Further documentation is available http://sdllivecontent.sdl.com/LiveContent/web/pub.xql?action=home&pub=SDL_Tridion_2011_SPONE&lang=en-US#addHistory=true&filename=ConfiguringEventSystem.xml&docid=concept_48C53F76CBFD45A783A3975CA72ECC49&inner_id=&tid=&query=&scope=&resource=&eventType=lcContent.loadDocconcept_48C53F76CBFD45A783A3975CA72ECC49. It does require a username and password to access.

Kevin Brydon
  • 12,524
  • 8
  • 46
  • 76
  • 1
    I agree with Dominic's last comment - pushing to a Search Index is best handled as part of Content Deployment. The advantage is that you can pass back success / failure to the publish queue items. Also - the XML for the search engine can be written at the end of the Page inside server-side comment tags starting with <%-- Autonomy... and then your custom deployer picks it up and passes it to Autonomy. You still control the XML within your templates - but the deployer does all the talking to autonomy...more technically difficultl than event system but much more robust.... – robrtc Sep 17 '12 at 15:15
0

If you really need the processing time then I think you should write a web service that performs the actions you need, which you can call from the event handler. This would not influence user experience (in the case of a synchronous event handler) as much either.

Arjen Stobbe
  • 1,684
  • 9
  • 15