Merge lp:~jml/txpkgme/long-check into lp:txpkgme

Proposed by Jonathan Lange
Status: Merged
Approved by: Jonathan Lange
Approved revision: 31
Merged at revision: 30
Proposed branch: lp:~jml/txpkgme/long-check
Merge into: lp:txpkgme
Diff against target: 144 lines (+66/-5)
2 files modified
txpkgme/submitfromdisk.py (+20/-5)
txpkgme/tests/test_submitfromdisk.py (+46/-0)
To merge this branch: bzr merge lp:~jml/txpkgme/long-check
Reviewer Review Type Date Requested Status
Jonathan Lange (community) Approve
Review via email: mp+120198@code.launchpad.net

Commit message

Add --shutdown-delay option to delay shutting down the webserver.

Description of the change

We're getting error messages in our celery log and in our OOPS reports saying
"Connection Refused". Really, these errors are mostly due to a buggy client,
submit-for-packaging, that shuts down the receiving web server before fully
providing a response.

It would be nice to prevent this properly. However, until then, to silence
these warnings and to make debugging nagios failures easier, let's just add
a delay between the webserver sending a response and shutting itself down.

We'll need a txpkgme rollout and an update to the cronjob that feeds the
nagios check (adding '--shutdown-delay 5') before this kicks in.

To post a comment you must log in.
Revision history for this message
Michael Vogt (mvo) wrote :

I give this a tentative +1 - tentative because its friday evening and also because my twisted foo is weak. A second opinion is probably good, but otoh its compact enough for low risk.

Revision history for this message
Jonathan Lange (jml) wrote :

I'm going to seize this as an actual approval. I trust our test suite & our staging server to prevent any real problems.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'txpkgme/submitfromdisk.py'
--- txpkgme/submitfromdisk.py 2012-07-30 15:14:08 +0000
+++ txpkgme/submitfromdisk.py 2012-08-17 16:14:24 +0000
@@ -20,6 +20,7 @@
20import time20import time
2121
22from twisted.internet import reactor as mod_reactor22from twisted.internet import reactor as mod_reactor
23from twisted.internet.task import deferLater
23from twisted.web.resource import Resource24from twisted.web.resource import Resource
24from twisted.web.static import File25from twisted.web.static import File
2526
@@ -167,7 +168,8 @@
167 return result, result_message168 return result, result_message
168169
169170
170def submit_local_files(service_root, file_path, metadata, **webserver_args):171def submit_local_files(service_root, file_path, metadata, shutdown_delay,
172 **webserver_args):
171 """Submit 'path' to pkgme-service at 'service_root' with 'metadata'.173 """Submit 'path' to pkgme-service at 'service_root' with 'metadata'.
172174
173 :return: A Deferred that files with ('PUT', json_result).175 :return: A Deferred that files with ('PUT', json_result).
@@ -184,12 +186,21 @@
184 def web_server_up(metadata, webserver):186 def web_server_up(metadata, webserver):
185 return webserver.send_api_request(metadata, service_root)187 return webserver.send_api_request(metadata, service_root)
186 d.addCallback(web_server_up, harness)188 d.addCallback(web_server_up, harness)
189 d.addBoth(delay_callbacks, shutdown_delay, harness.reactor)
187 d.addBoth(harness.shut_down_web_server)190 d.addBoth(harness.shut_down_web_server)
188 return d191 return d
189192
190193
194def delay_callbacks(value, delay, clock=None):
195 if clock is None:
196 clock = mod_reactor
197 if not delay:
198 return value
199 return deferLater(clock, delay, lambda: value)
200
201
191def fire_request(service_root, app_path, metadata_path, timeout,202def fire_request(service_root, app_path, metadata_path, timeout,
192 hostname, port, result_writer, clock):203 hostname, port, result_writer, clock, shutdown_delay):
193 successful = [False]204 successful = [False]
194205
195 start_time = clock.seconds()206 start_time = clock.seconds()
@@ -222,7 +233,7 @@
222233
223 def send_request(metadata):234 def send_request(metadata):
224 d = submit_local_files(235 d = submit_local_files(
225 service_root, app_path, metadata,236 service_root, app_path, metadata, shutdown_delay,
226 reactor=mod_reactor, timeout=timeout,237 reactor=mod_reactor, timeout=timeout,
227 hostname=hostname, port=port, clock=clock)238 hostname=hostname, port=port, clock=clock)
228 d.addCallback(got_response)239 d.addCallback(got_response)
@@ -263,6 +274,9 @@
263 parser.add_option("-f", "--file", dest="output_file",274 parser.add_option("-f", "--file", dest="output_file",
264 help="write the result to FILE", type="str",275 help="write the result to FILE", type="str",
265 metavar="FILE", default=None)276 metavar="FILE", default=None)
277 parser.add_option("--shutdown-delay", dest="shutdown_delay", type="int",
278 help=("Delay shutting down the web server by this "
279 "many seconds."))
266 options, args = parser.parse_args()280 options, args = parser.parse_args()
267 metadata_path = METADATA_FILE281 metadata_path = METADATA_FILE
268 service_url = None282 service_url = None
@@ -283,9 +297,10 @@
283 result_writer = ResultWriter()297 result_writer = ResultWriter()
284 if options.output_file is not None:298 if options.output_file is not None:
285 result_writer = OutputFileResultWriter(options.output_file, clock)299 result_writer = OutputFileResultWriter(options.output_file, clock)
286 successful = fire_request(300 successful = fire_request(
287 service_url, app_path, metadata_path, options.timeout,301 service_url, app_path, metadata_path, options.timeout,
288 options.hostname, options.port, result_writer, clock)302 options.hostname, options.port, result_writer, clock,
303 options.shutdown_delay)
289 if not successful:304 if not successful:
290 return 1305 return 1
291 return 0306 return 0
292307
=== modified file 'txpkgme/tests/test_submitfromdisk.py'
--- txpkgme/tests/test_submitfromdisk.py 2012-07-19 17:49:22 +0000
+++ txpkgme/tests/test_submitfromdisk.py 2012-08-17 16:14:24 +0000
@@ -20,17 +20,63 @@
20 TempDir,20 TempDir,
21 )21 )
22from testtools import TestCase22from testtools import TestCase
23from testtools._spinner import (
24 DeferredNotFired,
25 extract_result,
26 )
27from twisted.internet.defer import Deferred
23from twisted.internet.task import Clock28from twisted.internet.task import Clock
24from twisted.web.resource import Resource29from twisted.web.resource import Resource
2530
26from txpkgme.submitfromdisk import (31from txpkgme.submitfromdisk import (
27 add_local_files,32 add_local_files,
28 check_saved_output,33 check_saved_output,
34 delay_callbacks,
29 OutputFileResultWriter,35 OutputFileResultWriter,
30 parse_output,36 parse_output,
31)37)
3238
3339
40class DelayCallbacksTest(TestCase):
41
42 def test_no_delay(self):
43 clock = Clock()
44 marker = object()
45 d = Deferred()
46 d.addBoth(delay_callbacks, 0, clock)
47 d.callback(marker)
48 self.assertIs(marker, extract_result(d))
49
50 def test_stops_firing(self):
51 clock = Clock()
52 marker = object()
53 d = Deferred()
54 d.addBoth(delay_callbacks, 5, clock)
55 d.callback(marker)
56 self.assertRaises(DeferredNotFired, extract_result, d)
57
58 def test_fires_after_time(self):
59 clock = Clock()
60 marker = object()
61 delay = 5
62 d = Deferred()
63 d.addBoth(delay_callbacks, 5, clock)
64 d.callback(marker)
65 clock.advance(delay + 1)
66 self.assertIs(marker, extract_result(d))
67
68 def test_failure(self):
69 clock = Clock()
70 delay = 5
71 d = Deferred()
72 d.addCallback(lambda x: 1/0)
73 d.addBoth(delay_callbacks, 5, clock)
74 d.callback(None)
75 clock.advance(delay + 1)
76 self.assertRaises(ZeroDivisionError, extract_result, d)
77
78
79
34class OutputFileResultWriterTests(TestCase):80class OutputFileResultWriterTests(TestCase):
3581
36 def write(self, success, duration, msg, clock=None):82 def write(self, success, duration, msg, clock=None):

Subscribers

People subscribed via source and target branches