Dear Jeff and other sudders,<div><br></div><div>I have posted this as ticket 331, but in case anyone is multithreading.</div><div><br></div><div>The application I develop on top of suds is multithreaded and was hitting a small race condition, where suds would return the object corresponding to the next call.</div>
<div><br></div><div>The suds client "clone" method should ideally return an object that could be used in a thread-safe manner, but it didn't seem the case.</div><div><br></div><div>After discarding my own transport (by switching back to suds original transport) I think I have nailed it down to the construction of the method bindings.</div>
<div><br></div><div>In suds/wsdl.py:</div><div><br></div><blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px;"><div><div> def add_methods(self, service):</div><div> """ Build method view for service """</div>
<div> bindings = {</div><div><b><u>----> Problem is here <--------------</u></b></div><div> 'document/literal' : Document(self),</div><div> 'rpc/literal' : RPC(self),</div>
<div> 'rpc/encoded' : Encoded(self)</div><div><b><u>----> Problem is here <--------------</u></b></div><div> }</div><div> for p in service.ports:</div><div> binding = p.binding</div>
<div> ptype = p.binding.type</div><div> operations = p.binding.type.operations.values()</div><div> for name in [<a href="http://op.name">op.name</a> for op in operations]:</div><div> m = Facade('Method')</div>
<div> <a href="http://m.name">m.name</a> = name</div><div> m.location = p.location</div><div> m.binding = Facade('binding')</div><div> op = binding.operation(name)</div>
<div> m.soap = op.soap</div><div> key = '/'.join((op.soap.style, op.soap.input.body.use))</div><div> m.binding.input = bindings.get(key) <b><u>----> Problem is here <--------------</u></b></div>
<div> key = '/'.join((op.soap.style, op.soap.output.body.use))</div><div> m.binding.output = bindings.get(key) <b><u>----> Problem is here <--------------</u></b></div><div> op = ptype.operation(name)</div>
<div> p.methods[name] = m</div></div></blockquote><div><br></div><div>The same "binding" (Document in my case) object is being assigned to all methods and shared by all instances of a suds Client created with clone. This is apparently why while still processing one method, the next one (in another thread) would actually overwrite the expected output.</div>
<div><br></div><div>The solution is to delay the binding construction until the binding is assigned to the method (all still within the same function):</div><div><br></div><div><div> def add_methods(self, service):</div>
<div> """ Build method view for service """</div><div> bindings = {</div><div><b><u>----> Only reference to the class, no construction <--------------</u></b></div><div> 'document/literal' : Document,</div>
<div> 'rpc/literal' : RPC,</div><div> 'rpc/encoded' : Encoded</div><div><b><u>----> Only reference to the class, no construction <--------------</u></b></div><div> }</div>
<div> for p in service.ports:</div><div> binding = p.binding</div><div> ptype = p.binding.type</div><div> operations = p.binding.type.operations.values()</div><div> for name in [<a href="http://op.name">op.name</a> for op in operations]:</div>
<div> m = Facade('Method')</div><div> <a href="http://m.name">m.name</a> = name</div><div> m.location = p.location</div><div> m.binding = Facade('binding')</div>
<div> op = binding.operation(name)</div><div> m.soap = op.soap</div><div> key = '/'.join((op.soap.style, op.soap.input.body.use))</div><div> m.binding.input = bindings.get(key)(self) <b><u>----> Construction of the binding object <--------------</u></b></div>
<div> key = '/'.join((op.soap.style, op.soap.output.body.use))</div><div> m.binding.output = bindings.get(key)(self) <b><u>----> Construction of the binding object <--------------</u></b></div>
<div> op = ptype.operation(name)</div><div> p.methods[name] = m</div></div><div><br></div><div>As with any multithreading problem, this seems to be a cure for the problem. The race condition hasn't shown up again, which by no means ensures its removal, but may have drastically reduced the probability of occurrence.</div>
<div><br></div><div>Best regards</div><div><br></div><div>Daniel</div><div><br></div><div><br></div><div><br></div><div><br></div>