Hi guys,
tl;dr ObjectCache with cachingpolicy=1 seems broken + leaked nsprefix generation when using caching
And in detail:
Suds is a cool SOAP client, great work.
However, we noticed a problem using Suds 0.4 and quite a big WSDL (~200 KB, unfortunately I can't share it).
When we instantiate the Client with the WSDL url, it takes up to 700ms until the Client instance has been created. This is quite long (we use Suds in a SOAP server to call other SOAP services) as we create a new Client per request and so 700ms is way too long. So, for us caching is really important as it reduces the time to create a client significantly.
Unfortunately, caching with cachingpolicy=1 (which is the only option which gives any benefit, Document-based caching is not that useful) causes other problems:
- the built-in ObjectCache causes an "maximum recursion depth" error while pickling the data (stack trace attached)
- I wrote a simple memory cache to avoid pickling and having real fast access times (code attached). However, this causes also problems, see below.
When using the memory-based cache, and this would most probably apply for the filesystem-based ObjectCache as well, on each Client creation, a ServiceDefinition object is instantiated and passed a reference to a wsdl.Definitions object. Since this wsdl.Definitions instance is read from the cache, multiple instantiated clients will be based on that same wsdl.Definitions instance. Great, in theory :).
The problem is that the ServiceDefinition object manages prefix names and creates them on-the-fly when needed and ensures the generated prefix name is not yet used. It takes prefix suffixes out of a pool of 1024. While the used prefixes are bound to the ServiceDefinition instance, they are freed when this instance goes away. Unfortunately, the used prefixes are also bound to the sax.element.Element.nsprefixes of wsdl.Definitions instance which persists due to the cache.
Our WSDL requires about 120 prefixes after parsing and so we populate the nsprefixes dictionaries again and again. After 9 or 10 calls the client breaks with 'prefixes exhausted' (ServiceDefinition.nextprefix()).
A couple of questions about this: - does anyone know whether the nsprefixes dictionary should be cleared at any point to circumvent the described exception? I tried clearing it and it seems to solve the problem but I'm not sure what other impacts that might have (regarding performance, stability) as I don't know the code well enough.
- is the pickling problem with ObjectCache already known?
- any other ideas to improve Client creation performance on bigger WSDL files?
Thanks for your help, guys.
Regards, Enrico
P.S.: I would have filed a bug report in the tracker but it's quite hard when you first have to register for a Fedora account :(.
Did you try the patch mentioned in https://fedorahosted.org/suds/ticket/239?
2012/3/26 Enrico Tröger enrico.troeger@uvena.de
Hi guys,
tl;dr ObjectCache with cachingpolicy=1 seems broken + leaked nsprefix generation when using caching
And in detail:
Suds is a cool SOAP client, great work.
However, we noticed a problem using Suds 0.4 and quite a big WSDL (~200 KB, unfortunately I can't share it).
When we instantiate the Client with the WSDL url, it takes up to 700ms until the Client instance has been created. This is quite long (we use Suds in a SOAP server to call other SOAP services) as we create a new Client per request and so 700ms is way too long. So, for us caching is really important as it reduces the time to create a client significantly.
Unfortunately, caching with cachingpolicy=1 (which is the only option which gives any benefit, Document-based caching is not that useful) causes other problems:
- the built-in ObjectCache causes an "maximum recursion depth" error
while pickling the data (stack trace attached)
- I wrote a simple memory cache to avoid pickling and having real fast
access times (code attached). However, this causes also problems, see below.
When using the memory-based cache, and this would most probably apply for the filesystem-based ObjectCache as well, on each Client creation, a ServiceDefinition object is instantiated and passed a reference to a wsdl.Definitions object. Since this wsdl.Definitions instance is read from the cache, multiple instantiated clients will be based on that same wsdl.Definitions instance. Great, in theory :).
The problem is that the ServiceDefinition object manages prefix names and creates them on-the-fly when needed and ensures the generated prefix name is not yet used. It takes prefix suffixes out of a pool of 1024. While the used prefixes are bound to the ServiceDefinition instance, they are freed when this instance goes away. Unfortunately, the used prefixes are also bound to the sax.element.Element.nsprefixes of wsdl.Definitions instance which persists due to the cache.
Our WSDL requires about 120 prefixes after parsing and so we populate the nsprefixes dictionaries again and again. After 9 or 10 calls the client breaks with 'prefixes exhausted' (ServiceDefinition.nextprefix()).
A couple of questions about this:
- does anyone know whether the nsprefixes dictionary should be cleared
at any point to circumvent the described exception? I tried clearing it and it seems to solve the problem but I'm not sure what other impacts that might have (regarding performance, stability) as I don't know the code well enough.
is the pickling problem with ObjectCache already known?
any other ideas to improve Client creation performance on
bigger WSDL files?
Thanks for your help, guys.
Regards, Enrico
P.S.: I would have filed a bug report in the tracker but it's quite hard when you first have to register for a Fedora account :(.
suds mailing list suds@lists.fedoraproject.org https://admin.fedoraproject.org/mailman/listinfo/suds
On Tue, 27 Mar 2012 08:59:38 -0400, Chris wrote:
Did you try the patch mentioned in https://fedorahosted.org/suds/ticket/239?
Thanks for the pointer. I did try the patch but it doesn't change anything. While I receive the same exception "maximum recursion depth exceeded" as in the ticket, in my case it's caused at another place in the code. Suds parses my WSDL properly, it's just the pickling for caching which causes the exception :(.
Regards, Enrico
P.S.: Chris, sorry for double-posting to you.
Enrico,
On Tue, 27 Mar 2012 08:59:38 -0400, Chris wrote:
Did you try the patch mentioned in https://fedorahosted.org/suds/ticket/239?
Thanks for the pointer. I did try the patch but it doesn't change anything. While I receive the same exception "maximum recursion depth exceeded" as in the ticket, in my case it's caused at another place in the code. Suds parses my WSDL properly, it's just the pickling for caching which causes the exception :(.
From that same ticket, you may have seen an ugly hack that got me
around a similar recursion bug -- https://fedorahosted.org/suds/ticket/239#comment:19
Basically, just manually set the maximum recursion depth to something sufficiently high before calling Suds...
import sys sys.setrecursionlimit(10000)
If you want to experiment with some different limits, it might help you figure out if you're dealing with an infinite call chain or just a very deep one. In my case, the recursion depth seem to scale with the number of import directives in my WSDL file. It's certainly not a real solution and YMMV, but it could be worth a try.
- Chris
On Wed, 28 Mar 2012 07:29:18 -0400, Chris wrote:
Enrico,
On Tue, 27 Mar 2012 08:59:38 -0400, Chris wrote:
Did you try the patch mentioned in https://fedorahosted.org/suds/ticket/239?
Thanks for the pointer. I did try the patch but it doesn't change anything. While I receive the same exception "maximum recursion depth exceeded" as in the ticket, in my case it's caused at another place in the code. Suds parses my WSDL properly, it's just the pickling for caching which causes the exception :(.
From that same ticket, you may have seen an ugly hack that got me around a similar recursion bug -- https://fedorahosted.org/suds/ticket/239#comment:19
Yeah, I read it and also tried it, just forgot to tell about in my previous mail. Sorry.
Basically, just manually set the maximum recursion depth to something sufficiently high before calling Suds...
Values from 10000 on would do for my problem. Then the object is pickled and stored in the cache. Then it can be loaded from the cache and unpickled. But as you said, this is by no means a solution, not even a workaround.
If you want to experiment with some different limits, it might help you figure out if you're dealing with an infinite call chain or just a very deep one. In my case, the recursion depth seem to scale with the
Yes, that question raised also in my head though I didn't find time yet to look deeper into the recursion problem, will do soon, I hope.
The more interesting aspect of my first mail, for me, is rather the prefix generation/leaking problem as the simple memory cache would be good enough for me to not poke around with recursion errors while pickling.
Thanks, Enrico
Hey,
The more interesting aspect of my first mail, for me, is rather the prefix generation/leaking problem as the simple memory cache would be good enough for me to not poke around with recursion errors while pickling.
has anyone any ideas left?
Regards, Enrico