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
1=== modified file 'txpkgme/submitfromdisk.py'
2--- txpkgme/submitfromdisk.py 2012-07-30 15:14:08 +0000
3+++ txpkgme/submitfromdisk.py 2012-08-17 16:14:24 +0000
4@@ -20,6 +20,7 @@
5 import time
6
7 from twisted.internet import reactor as mod_reactor
8+from twisted.internet.task import deferLater
9 from twisted.web.resource import Resource
10 from twisted.web.static import File
11
12@@ -167,7 +168,8 @@
13 return result, result_message
14
15
16-def submit_local_files(service_root, file_path, metadata, **webserver_args):
17+def submit_local_files(service_root, file_path, metadata, shutdown_delay,
18+ **webserver_args):
19 """Submit 'path' to pkgme-service at 'service_root' with 'metadata'.
20
21 :return: A Deferred that files with ('PUT', json_result).
22@@ -184,12 +186,21 @@
23 def web_server_up(metadata, webserver):
24 return webserver.send_api_request(metadata, service_root)
25 d.addCallback(web_server_up, harness)
26+ d.addBoth(delay_callbacks, shutdown_delay, harness.reactor)
27 d.addBoth(harness.shut_down_web_server)
28 return d
29
30
31+def delay_callbacks(value, delay, clock=None):
32+ if clock is None:
33+ clock = mod_reactor
34+ if not delay:
35+ return value
36+ return deferLater(clock, delay, lambda: value)
37+
38+
39 def fire_request(service_root, app_path, metadata_path, timeout,
40- hostname, port, result_writer, clock):
41+ hostname, port, result_writer, clock, shutdown_delay):
42 successful = [False]
43
44 start_time = clock.seconds()
45@@ -222,7 +233,7 @@
46
47 def send_request(metadata):
48 d = submit_local_files(
49- service_root, app_path, metadata,
50+ service_root, app_path, metadata, shutdown_delay,
51 reactor=mod_reactor, timeout=timeout,
52 hostname=hostname, port=port, clock=clock)
53 d.addCallback(got_response)
54@@ -263,6 +274,9 @@
55 parser.add_option("-f", "--file", dest="output_file",
56 help="write the result to FILE", type="str",
57 metavar="FILE", default=None)
58+ parser.add_option("--shutdown-delay", dest="shutdown_delay", type="int",
59+ help=("Delay shutting down the web server by this "
60+ "many seconds."))
61 options, args = parser.parse_args()
62 metadata_path = METADATA_FILE
63 service_url = None
64@@ -283,9 +297,10 @@
65 result_writer = ResultWriter()
66 if options.output_file is not None:
67 result_writer = OutputFileResultWriter(options.output_file, clock)
68- successful = fire_request(
69+ successful = fire_request(
70 service_url, app_path, metadata_path, options.timeout,
71- options.hostname, options.port, result_writer, clock)
72+ options.hostname, options.port, result_writer, clock,
73+ options.shutdown_delay)
74 if not successful:
75 return 1
76 return 0
77
78=== modified file 'txpkgme/tests/test_submitfromdisk.py'
79--- txpkgme/tests/test_submitfromdisk.py 2012-07-19 17:49:22 +0000
80+++ txpkgme/tests/test_submitfromdisk.py 2012-08-17 16:14:24 +0000
81@@ -20,17 +20,63 @@
82 TempDir,
83 )
84 from testtools import TestCase
85+from testtools._spinner import (
86+ DeferredNotFired,
87+ extract_result,
88+ )
89+from twisted.internet.defer import Deferred
90 from twisted.internet.task import Clock
91 from twisted.web.resource import Resource
92
93 from txpkgme.submitfromdisk import (
94 add_local_files,
95 check_saved_output,
96+ delay_callbacks,
97 OutputFileResultWriter,
98 parse_output,
99 )
100
101
102+class DelayCallbacksTest(TestCase):
103+
104+ def test_no_delay(self):
105+ clock = Clock()
106+ marker = object()
107+ d = Deferred()
108+ d.addBoth(delay_callbacks, 0, clock)
109+ d.callback(marker)
110+ self.assertIs(marker, extract_result(d))
111+
112+ def test_stops_firing(self):
113+ clock = Clock()
114+ marker = object()
115+ d = Deferred()
116+ d.addBoth(delay_callbacks, 5, clock)
117+ d.callback(marker)
118+ self.assertRaises(DeferredNotFired, extract_result, d)
119+
120+ def test_fires_after_time(self):
121+ clock = Clock()
122+ marker = object()
123+ delay = 5
124+ d = Deferred()
125+ d.addBoth(delay_callbacks, 5, clock)
126+ d.callback(marker)
127+ clock.advance(delay + 1)
128+ self.assertIs(marker, extract_result(d))
129+
130+ def test_failure(self):
131+ clock = Clock()
132+ delay = 5
133+ d = Deferred()
134+ d.addCallback(lambda x: 1/0)
135+ d.addBoth(delay_callbacks, 5, clock)
136+ d.callback(None)
137+ clock.advance(delay + 1)
138+ self.assertRaises(ZeroDivisionError, extract_result, d)
139+
140+
141+
142 class OutputFileResultWriterTests(TestCase):
143
144 def write(self, success, duration, msg, clock=None):

Subscribers

People subscribed via source and target branches