| 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),
|
| +])
|
|
|