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 &quot;clone&quot; method should ideally return an object that could be used in a thread-safe manner, but it didn&#39;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>        &quot;&quot;&quot; Build method view for service &quot;&quot;&quot;</div>
<div>        bindings = {</div><div><b><u>----&gt; Problem is here &lt;--------------</u></b></div><div>            &#39;document/literal&#39; : Document(self),</div><div>            &#39;rpc/literal&#39; : RPC(self),</div>
<div>            &#39;rpc/encoded&#39; : Encoded(self)</div><div><b><u>----&gt; Problem is here &lt;--------------</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(&#39;Method&#39;)</div>
<div>                <a href="http://m.name">m.name</a> = name</div><div>                m.location = p.location</div><div>                m.binding = Facade(&#39;binding&#39;)</div><div>                op = binding.operation(name)</div>
<div>                m.soap = op.soap</div><div>                key = &#39;/&#39;.join((op.soap.style, op.soap.input.body.use))</div><div>                m.binding.input = bindings.get(key) <b><u>----&gt; Problem is here &lt;--------------</u></b></div>
<div>                key = &#39;/&#39;.join((op.soap.style, op.soap.output.body.use))</div><div>                m.binding.output = bindings.get(key) <b><u>----&gt; Problem is here &lt;--------------</u></b></div><div>                op = ptype.operation(name)</div>
<div>                p.methods[name] = m</div></div></blockquote><div><br></div><div>The same &quot;binding&quot; (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>        &quot;&quot;&quot; Build method view for service &quot;&quot;&quot;</div><div>        bindings = {</div><div><b><u>----&gt; Only reference to the class, no construction &lt;--------------</u></b></div><div>            &#39;document/literal&#39; : Document,</div>
<div>            &#39;rpc/literal&#39; : RPC,</div><div>            &#39;rpc/encoded&#39; : Encoded</div><div><b><u>----&gt; Only reference to the class, no construction &lt;--------------</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(&#39;Method&#39;)</div><div>                <a href="http://m.name">m.name</a> = name</div><div>                m.location = p.location</div><div>                m.binding = Facade(&#39;binding&#39;)</div>
<div>                op = binding.operation(name)</div><div>                m.soap = op.soap</div><div>                key = &#39;/&#39;.join((op.soap.style, op.soap.input.body.use))</div><div>                m.binding.input = bindings.get(key)(self) <b><u>----&gt; Construction of the binding object &lt;--------------</u></b></div>
<div>                key = &#39;/&#39;.join((op.soap.style, op.soap.output.body.use))</div><div>                m.binding.output = bindings.get(key)(self) <b><u>----&gt; Construction of the binding object &lt;--------------</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&#39;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>