Thanks Drew<div><br></div><div>Yes, you spotted an error in my email, which is not replicated in my code. ie My AdapterQueue in the code inherits from Service. It in turn is a service of a parent which <i>is</i> a MultiService instance.</div>
<div><br></div><div>The tests are Integration tests, not unit tests, and as such run up an instance of our entire messaging gateway. To date we have run it up once at the start of the test run, run all test suites, then torn down (with unclean reactor). The Integration tests have been notoriously brittle, so am hoping that tearing down the gateway after <i>each</i> individual test will help with that. To that end, I have refactored the code to better utilise services, so that teardown (without just stopping the reactor) is possible.</div>
<div><br></div><div>So in the setUp() of each trial.unittest.TestCase, is a call to test_utils.startGateway(). This returns the result of gateway_svc.startService() (starts the parent MultiService of all child services). Each of these setUp methods uses @inlineCallbacks and yields the deferred returned from this top-level startService().</div>
<div><div>@inlineCallbacks</div><div>def setUp(self):</div><div>   yield test_utils.startGateway()</div></div><div>   {do other set up}</div><div><br></div><div>By the same token, the tearDown() in each test class calls test_utils.tearDown(), which looks like:</div>
<div><br></div><div>class SomeTests(TestCase):</div><div><div>    def tearDown(self):</div><div>        self.extra_svc.stopService()</div><div>        test_utils.tearDown()</div></div><div><br></div><div>Haha! In writing this I&#39;ve realised what I believe was the problem (and my repeat testing just now has failed to show the intermittent failure). Each test class&#39;s tearDown() was <i>not</i> <i>returning</i> the deferred returned from stopService(). Changing the final line above seems to solve the issue:</div>
<div><br></div><div>return test_utils.tearDown()</div><div><br></div><div>Thanks for the sounding board, Drew.</div><div>Cheers</div><div>Brad</div><div><br></div><div><br></div><div><br><div class="gmail_quote">On 17 March 2011 05:06, Drew Smathers <span dir="ltr">&lt;<a href="mailto:drew.smathers@gmail.com">drew.smathers@gmail.com</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"><div class="im">On Tue, Mar 15, 2011 at 9:55 PM, Brad Milne<br>
&lt;<a href="mailto:brad.milne@devx.runthered.com">brad.milne@devx.runthered.com</a>&gt; wrote:<br>
&gt; Hi<br>
&gt; I have a series of MultiService objects, with child Services. Some of these<br>
&gt; services are TCPServers, for example, and others are my own objects<br>
&gt; (extending from Service).<br>
&gt; In the instance that I have a Service which controls a LoopingCall, I am<br>
&gt; getting intermittent &#39;unclean reactor&#39; errors during tests. I feel I might<br>
&gt; be missing some handling of deferreds, perhaps.<br>
&gt; (using 8.2.0 - looking to migrate to 10.2.0 soon)<br>
&gt; Here is an example of the approach being used:<br>
&gt; class AdapterQueue(service.MultiService):<br>
&gt;     def startService(self):<br>
&gt;         service.Service.startService(self)<br>
&gt;         self._looping_controller = LoopingCall(self._action)<br>
&gt;         d = self._looping_controller.start(self.delay, False)<br>
&gt;         d.addErrback(self._errorInScheduler)<br>
&gt;     def stopService(self):<br>
&gt;         service.Service.stopService(self)<br>
&gt;         d = self._looping_controller.deferred<br>
&gt;         self._looping_controller.stop()<br>
&gt;         return d<br>
<br>
<br>
</div>I&#39;m not sure if this is part of the issue or not, but it seems odd<br>
that you may have accidentally inherited from MultiService instead of<br>
Service.<br>
<div><div></div><div class="h5"><br>
<br>
&gt; And an example error (happens about 1/3 of the time):<br>
&gt; DirtyReactorAggregateError: Reactor was unclean.<br>
&gt; DelayedCalls: (set twisted.internet.base.DelayedCall.debug = True to debug)<br>
&gt; &lt;DelayedCall 30800112 [0.0189974308014s] called=0 cancelled=0<br>
&gt; LoopingCall&lt;0.033333333333333333&gt;(AdapterQueue._action, *(), **{})()<br>
&gt; traceback at creation:<br>
&gt;   File &quot;C:\Python26\lib\threading.py&quot;, line 497, in __bootstrap<br>
&gt;     self.__bootstrap_inner()<br>
&gt;       File &quot;C:\Python26\lib\threading.py&quot;, line 525, in __bootstrap_inner<br>
&gt;     self.run()<br>
&gt;       File &quot;C:\Python26\lib\threading.py&quot;, line 477, in run<br>
&gt;     self.__target(*self.__args, **self.__kwargs)<br>
&gt;       File &quot;D:\dev\eggs\nose-0.11.3-py2.6.egg\nose\twistedtools.py&quot;, line<br>
&gt; 57, in &lt;lambda&gt;<br>
&gt;     installSignalHandlers=False))<br>
&gt;       File<br>
&gt; &quot;D:\dev\eggs\twisted-8.2.0-py2.6-win32.egg\twisted\internet\base.py&quot;, line<br>
&gt; 1128, in run<br>
&gt;     self.mainLoop()<br>
&gt;       File<br>
&gt; &quot;D:\dev\eggs\twisted-8.2.0-py2.6-win32.egg\twisted\internet\base.py&quot;, line<br>
&gt; 1137, in mainLoop<br>
&gt;     self.runUntilCurrent()<br>
&gt;       File<br>
&gt; &quot;D:\dev\eggs\twisted-8.2.0-py2.6-win32.egg\twisted\internet\base.py&quot;, line<br>
&gt; 757, in runUntilCurrent<br>
&gt;     call.func(*call.args, **<a href="http://call.kw" target="_blank">call.kw</a>)<br>
&gt;       File<br>
&gt; &quot;D:\dev\eggs\twisted-8.2.0-py2.6-win32.egg\twisted\internet\task.py&quot;, line<br>
&gt; 115, in __call__<br>
&gt;     d.addCallback(cb)<br>
&gt;       File<br>
&gt; &quot;D:\dev\eggs\twisted-8.2.0-py2.6-win32.egg\twisted\internet\defer.py&quot;, line<br>
&gt; 195, in addCallback<br>
&gt;     callbackKeywords=kw)<br>
&gt;       File<br>
&gt; &quot;D:\dev\eggs\twisted-8.2.0-py2.6-win32.egg\twisted\internet\defer.py&quot;, line<br>
&gt; 186, in addCallbacks<br>
&gt;     self._runCallbacks()<br>
&gt;       File<br>
&gt; &quot;D:\dev\eggs\twisted-8.2.0-py2.6-win32.egg\twisted\internet\defer.py&quot;, line<br>
&gt; 328, in _runCallbacks<br>
&gt;     self.result = callback(self.result, *args, **kw)<br>
&gt;       File<br>
&gt; &quot;D:\dev\eggs\twisted-8.2.0-py2.6-win32.egg\twisted\internet\task.py&quot;, line<br>
&gt; 103, in cb<br>
&gt;     self._reschedule()<br>
&gt;       File<br>
&gt; &quot;D:\dev\eggs\twisted-8.2.0-py2.6-win32.egg\twisted\internet\task.py&quot;, line<br>
&gt; 139, in _reschedule<br>
&gt;     self.call = self.clock.callLater(nextTime - currentTime, self)<br>
&gt;&gt;<br>
&gt;<br>
<br>
<br>
</div></div>Can you post code for the test?  This means generally (as you<br>
suggested) that you haven&#39;t waited for all related deferreds to fire<br>
before ending the test. Return the deferred returned by stopService(),<br>
for example, and make final assertions in a callback; but I&#39;m guessing<br>
you already know this.<br>
<br>
<br>
-Drew<br>
<br>
_______________________________________________<br>
Twisted-Python mailing list<br>
<a href="mailto:Twisted-Python@twistedmatrix.com">Twisted-Python@twistedmatrix.com</a><br>
<a href="http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python" target="_blank">http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python</a><br>
</blockquote></div><br><br clear="all"><br>-- <br><span style="font-family:arial, sans-serif;font-size:13px;border-collapse:collapse;color:rgb(136, 136, 136)">Brad Milne | Run The Red | <span style="font-family:arial, sans-serif;font-size:13px;white-space:nowrap"><b><a href="mailto:brad.milne@devx.runthered.com" style="color:rgb(42, 93, 176)" target="_blank">brad.milne@devx.runthered.com</a></b></span></span><br>

</div>