Index: chromium-jobqueue/app.py |
=================================================================== |
--- chromium-jobqueue/app.py (revision 0) |
+++ chromium-jobqueue/app.py (revision 0) |
@@ -0,0 +1,130 @@ |
+# Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+import datetime |
+import json |
+ |
+import webapp2 |
+from google.appengine.ext import ndb |
+ |
+ |
+DEFAULT_NAMESPACE = 'default' |
+DEFAULT_JOBS_TO_SERVE = 20 |
+ |
+ |
+class Job(ndb.Model): |
+ """Represents a single build job description. |
+ |
+ Attributes: |
+ description: A JSON blob representing the job itself. |
+ created: A timestamp for when this job was posted. |
+ last_served: A timestamp for the last time this job was served, usually |
+ to a polling buildbot. Default is epoch 0, so new jobs are "old". |
+ taken: A boolean signalling that this job has been successfully picked |
+ up by a poller and can be dropped. |
+ """ |
+ description = ndb.JsonProperty() |
+ last_served = ndb.DateTimeProperty( |
+ default=datetime.datetime.utcfromtimestamp(0)) |
+ taken = ndb.BooleanProperty(default=False) |
+ |
+ |
+class MainHandler(webapp2.RequestHandler): |
+ |
+ def get(self): |
+ self.response.write(""" |
+<html> |
+ <body> |
+ <form action="/default/push" method="post"> |
+ <div><textarea name="job" rows="3" cols="60"></textarea></div> |
+ <div><input type="submit" value="Add Job"></div> |
+ </form> |
+ <form action="/default/accept" method="post"> |
+ <div><textarea name="job" rows="1" cols="60"></textarea></div> |
+ <div><input type="submit" value="Accept Job"></div> |
+ </form> |
+ </body> |
+</html> |
+""") |
+ |
+ |
+class PushHandler(webapp2.RequestHandler): |
+ |
+ def post(self, project): |
+ job = Job(description=self.request.get('job'), namespace=project) |
+ job.put() |
+ |
+ |
+class PullHandler(webapp2.RequestHandler): |
+ |
+ def post(self, project): |
+ # Get the jobs we'd like to serve. |
+ time_threshold = datetime.datetime.utcnow() - datetime.timedelta(seconds=30) |
+ query = Job.query(namespace=project) |
+ query = query.filter(Job.last_served < time_threshold) |
+ query = query.filter(Job.taken == False) |
+ query = query.order(Job.last_served) |
+ jobs = query.fetch(DEFAULT_JOBS_TO_SERVE) |
+ |
+ # Mark them as served. |
+ for job in jobs: |
+ job.last_served = datetime.datetime.utcnow() |
+ job.put() |
+ |
+ # Serve them. |
+ result = [] |
+ for job in jobs: |
+ job_blob = json.loads(job.description) |
+ job_blob.update({'job_key': job.key.urlsafe()}) |
+ result.append(job_blob) |
+ self.response.headers['Content-Type'] = 'application/json' |
+ self.response.write(json.dumps(result)) |
+ |
+ |
+class PeekHandler(webapp2.RequestHandler): |
+ |
+ def get(self, project, job): |
+ # Get the jobs we'd like to serve. |
+ if job: |
+ job_key = ndb.Key(urlsafe=job, namespace=project) |
+ job = job_key.get() |
+ jobs = [job] |
+ else: |
+ time_threshold = (datetime.datetime.utcnow() - |
+ datetime.timedelta(seconds=30)) |
+ query = Job.query(namespace=project) |
+ query = query.filter(Job.last_served < time_threshold) |
+ query = query.filter(Job.taken == False) |
+ query = query.order(Job.last_served) |
+ jobs = query.fetch(DEFAULT_JOBS_TO_SERVE) |
+ |
+ # Serve them. |
+ result = [] |
+ for job in jobs: |
+ job_blob = json.loads(job.description) |
+ job_blob.update({'job_key': job.key.urlsafe()}) |
+ result.append(job_blob) |
+ self.response.headers['Content-Type'] = 'application/json' |
+ self.response.write(json.dumps(result)) |
+ |
+ |
+class AcceptHandler(webapp2.RequestHandler): |
+ |
+ def post(self, project, job): |
+ job_key = ndb.Key(urlsafe=job, namespace=project) |
+ job = job_key.get() |
+ if job.taken: |
+ # This job has been previously accepted by someone else. |
+ self.response.set_status(409) |
+ job.taken = True |
+ job.put() |
+ |
+ |
+app = webapp2.WSGIApplication([ |
+ ('/', MainHandler), |
+ ('/(.*)/push', PushHandler), |
+ ('/(.*)/pull', PullHandler), |
+ ('/(.*)/peek/?(.*)', PeekHandler), |
+ ('/(.*)/accept/(.*)', AcceptHandler), |
+]) |