OLD | NEW |
---|---|
(Empty) | |
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
cmp
2013/08/22 04:44:12
2013?
There should be a LICENSE file in the CL, t
agable
2013/08/22 13:43:42
Done, copied from depot_tools. Out of curiosity, w
| |
2 # Use of this source code is governed by a BSD-style license that can be | |
3 # found in the LICENSE file. | |
4 | |
5 import datetime | |
6 import json | |
7 | |
8 import webapp2 | |
9 from google.appengine.ext import ndb | |
10 | |
11 | |
12 DEFAULT_NAMESPACE = 'default' | |
13 DEFAULT_JOBS_TO_SERVE = 20 | |
14 | |
15 | |
16 class Job(ndb.Model): | |
17 """Represents a single tryjob description. | |
18 | |
19 Attributes: | |
20 description: A JSON blob representing the job itself. | |
21 created: A timestamp for when this job was posted. | |
22 last_served: A timestamp for the last time this job was served to a polling | |
23 tryserver. Default is epoch 0, so new jobs are "old". | |
cmp
2013/08/22 04:44:12
tryserver -> other name
agable
2013/08/22 13:43:42
Done.
| |
24 taken: A boolean signalling that this job has been successfully picked up by | |
25 a trysever and can be dropped. | |
cmp
2013/08/22 04:44:12
tryserver -> other name
agable
2013/08/22 13:43:42
Done.
| |
26 """ | |
27 description = ndb.JsonProperty() | |
28 last_served = ndb.DateTimeProperty( | |
29 default=datetime.datetime.utcfromtimestamp(0)) | |
30 taken = ndb.BooleanProperty(default=False) | |
31 | |
32 | |
33 class MainHandler(webapp2.RequestHandler): | |
34 | |
35 def get(self): | |
36 self.response.write(""" | |
37 <html> | |
38 <body> | |
39 <form action="/default/push" method="post"> | |
40 <div><textarea name="job" rows="3" cols="60"></textarea></div> | |
41 <div><input type="submit" value="Add Job"></div> | |
42 </form> | |
43 <form action="/default/accept" method="post"> | |
44 <div><textarea name="job" rows="1" cols="60"></textarea></div> | |
45 <div><input type="submit" value="Accept Job"></div> | |
46 </form> | |
47 </body> | |
48 </html> | |
49 """) | |
50 | |
51 | |
52 class PushHandler(webapp2.RequestHandler): | |
53 | |
54 def post(self, project): | |
55 job = Job(description=self.request.get('job'), namespace=project) | |
56 job.put() | |
57 | |
58 | |
59 class PullHandler(webapp2.RequestHandler): | |
60 | |
61 def post(self, project): | |
62 # Get the jobs we'd like to serve. | |
63 time_threshold = datetime.datetime.utcnow() - datetime.timedelta(seconds=30) | |
64 query = Job.query(namespace=project) | |
65 query = query.filter(Job.last_served < time_threshold) | |
66 query = query.filter(Job.taken == False) | |
67 query = query.order(Job.last_served) | |
68 jobs = query.fetch(DEFAULT_JOBS_TO_SERVE) | |
69 | |
70 # Mark them as served. | |
71 for job in jobs: | |
72 job.last_served = datetime.datetime.utcnow() | |
73 job.put() | |
74 | |
75 # Serve them. | |
76 result = [] | |
77 for job in jobs: | |
78 job_blob = json.loads(job.description) | |
79 job_blob.update({'job_key': job.key.urlsafe()}) | |
80 result.append(job_blob) | |
81 self.response.headers['Content-Type'] = 'application/json' | |
82 self.response.write(json.dumps(result)) | |
83 | |
84 | |
85 class PeekHandler(webapp2.RequestHandler): | |
86 | |
87 def get(self, project, job): | |
88 # Get the jobs we'd like to serve. | |
89 if job: | |
90 job_key = ndb.Key(urlsafe=job, namespace=project) | |
91 job = job_key.get() | |
92 jobs = [job] | |
93 else: | |
94 time_threshold = datetime.datetime.utcnow() - datetime.timedelta(seconds=3 0) | |
cmp
2013/08/22 04:44:12
wrap at 80 chars
agable
2013/08/22 13:43:42
Done.
| |
95 query = Job.query(namespace=project) | |
96 query = query.filter(Job.last_served < time_threshold) | |
97 query = query.filter(Job.taken == False) | |
98 query = query.order(Job.last_served) | |
99 jobs = query.fetch(DEFAULT_JOBS_TO_SERVE) | |
100 | |
101 # Serve them. | |
102 result = [] | |
103 for job in jobs: | |
104 job_blob = json.loads(job.description) | |
105 job_blob.update({'job_key': job.key.urlsafe()}) | |
106 result.append(job_blob) | |
107 self.response.headers['Content-Type'] = 'application/json' | |
108 self.response.write(json.dumps(result)) | |
109 | |
110 | |
111 class AcceptHandler(webapp2.RequestHandler): | |
112 | |
113 def post(self, project, job): | |
114 job_key = ndb.Key(urlsafe=job, namespace=project) | |
115 job = job_key.get() | |
116 if job.taken: | |
117 # This job has been previously accepted by someone else. | |
118 self.response.set_status(409) | |
119 job.taken = True | |
cmp
2013/08/22 04:44:12
I think this would be a perfect place to use pull
agable
2013/08/22 13:43:42
Agreed. Right now, the Pull/Accept paradigm is jus
| |
120 job.put() | |
121 | |
122 | |
123 app = webapp2.WSGIApplication([ | |
124 ('/', MainHandler), | |
125 ('/(.*)/push', PushHandler), | |
126 ('/(.*)/pull', PullHandler), | |
127 ('/(.*)/peek/?(.*)', PeekHandler), | |
128 ('/(.*)/accept/(.*)', AcceptHandler), | |
129 ]) | |
OLD | NEW |