Index: chrome/common/extensions/docs/server2/cron_servlet.py |
diff --git a/chrome/common/extensions/docs/server2/cron_servlet.py b/chrome/common/extensions/docs/server2/cron_servlet.py |
index e768aa373132597a4186bd877003356d4260f064..e76f07423e2865d738b86011246ca2ca13edfca2 100644 |
--- a/chrome/common/extensions/docs/server2/cron_servlet.py |
+++ b/chrome/common/extensions/docs/server2/cron_servlet.py |
@@ -6,16 +6,61 @@ import logging |
import time |
import traceback |
-from appengine_wrappers import DeadlineExceededError, logservice |
+from appengine_wrappers import DeadlineExceededError, IsDevServer, logservice |
from branch_utility import BranchUtility |
+from caching_file_system import CachingFileSystem |
+from github_file_system import GithubFileSystem |
+from object_store_creator import ObjectStoreCreator |
from render_servlet import RenderServlet |
from server_instance import ServerInstance |
from servlet import Servlet, Request, Response |
+from subversion_file_system import SubversionFileSystem |
import svn_constants |
+from third_party.json_schema_compiler.memoize import memoize |
+ |
+def _CreateServerInstanceForChannel(channel, delegate): |
+ object_store_creator = ObjectStoreCreator(channel, start_empty=True) |
+ branch = (delegate.CreateBranchUtility(object_store_creator) |
+ .GetBranchForChannel(channel)) |
+ host_file_system = CachingFileSystem( |
+ delegate.CreateHostFileSystemForBranch(branch), |
+ object_store_creator) |
+ app_samples_file_system = delegate.CreateAppSamplesFileSystem( |
+ object_store_creator) |
+ return ServerInstance(channel, |
+ object_store_creator, |
+ host_file_system, |
+ app_samples_file_system) |
+ |
+class _SingletonRenderServletDelegate(RenderServlet.Delegate): |
+ def __init__(self, server_instance): |
+ self._server_instance = server_instance |
+ |
+ def CreateServerInstanceForChannel(self, channel): |
+ return self._server_instance |
class CronServlet(Servlet): |
'''Servlet which runs a cron job. |
''' |
+ def __init__(self, request, delegate_for_test=None): |
+ Servlet.__init__(self, request) |
+ self._delegate = delegate_for_test or CronServlet.Delegate() |
+ |
+ class Delegate(object): |
+ '''Allow runtime dependencies to be overridden for testing. |
+ ''' |
+ def CreateBranchUtility(self, object_store_creator): |
+ return BranchUtility.Create(object_store_creator) |
+ |
+ def CreateHostFileSystemForBranch(self, branch): |
+ return SubversionFileSystem.Create(branch) |
+ |
+ def CreateAppSamplesFileSystem(self, object_store_creator): |
+ # TODO(kalman): CachingFileSystem wrapper for GithubFileSystem, but it's |
+ # not supported yet (see comment there). |
+ return (EmptyDirFileSystem() if IsDevServer() else |
+ GithubFileSystem.Create(object_store_creator)) |
+ |
def Get(self): |
# Crons often time out, and when they do *and* then eventually try to |
# flush logs they die. Turn off autoflush and manually do so at the end. |
@@ -35,7 +80,14 @@ class CronServlet(Servlet): |
channel = self._request.path.strip('/') |
logging.info('cron/%s: starting' % channel) |
- server_instance = ServerInstance.CreateOnline(channel) |
+ # This is returned every time RenderServlet wants to create a new |
+ # ServerInstance. |
+ server_instance = _CreateServerInstanceForChannel(channel, self._delegate) |
+ |
+ def get_via_render_servlet(path): |
+ return RenderServlet( |
+ Request(path, self._request.host, self._request.headers), |
+ _SingletonRenderServletDelegate(server_instance)).Get() |
def run_cron_for_dir(d, path_prefix=''): |
success = True |
@@ -49,8 +101,7 @@ class CronServlet(Servlet): |
error = None |
path = '%s%s' % (path_prefix, f) |
try: |
- response = RenderServlet(Request(path, self._request.headers)).Get( |
- server_instance=server_instance) |
+ response = get_via_render_servlet(path) |
if response.status != 200: |
error = 'Got %s response' % response.status |
except DeadlineExceededError: |
@@ -70,22 +121,52 @@ class CronServlet(Servlet): |
return success |
success = True |
- for path, path_prefix in ( |
- # Note: rendering the public templates will pull in all of the private |
- # templates. |
- (svn_constants.PUBLIC_TEMPLATE_PATH, ''), |
- # Note: rendering the public templates will have pulled in the .js and |
- # manifest.json files (for listing examples on the API reference pages), |
- # but there are still images, CSS, etc. |
- (svn_constants.STATIC_PATH, 'static/'), |
- (svn_constants.EXAMPLES_PATH, 'extensions/examples/')): |
- try: |
- # Note: don't try to short circuit any of this stuff. We want to run |
- # the cron for all the directories regardless of intermediate failures. |
+ try: |
+ # Render all of the publicly accessible files. |
+ for path, path_prefix in ( |
+ # Note: rendering the public templates will pull in all of the private |
+ # templates. |
+ (svn_constants.PUBLIC_TEMPLATE_PATH, ''), |
+ # Note: rendering the public templates will have pulled in the .js |
+ # and manifest.json files (for listing examples on the API reference |
+ # pages), but there are still images, CSS, etc. |
+ (svn_constants.STATIC_PATH, 'static/'), |
+ (svn_constants.EXAMPLES_PATH, 'extensions/examples/')): |
+ # Note: don't try to short circuit any of this stuff. We want to run |
+ # the cron for all the directories regardless of intermediate |
+ # failures. |
success = run_cron_for_dir(path, path_prefix=path_prefix) and success |
- except DeadlineExceededError: |
- success = False |
- break |
+ |
+ # TODO(kalman): Generic way for classes to request cron access. The next |
+ # two special cases are ugly. It would potentially greatly speed up cron |
+ # runs, too. |
+ |
+ # Extension examples have zip files too. Well, so do apps, but the app |
+ # file system doesn't get the Offline treatment so they don't need cron. |
+ manifest_json = '/manifest.json' |
+ example_zips = [ |
+ '%s.zip' % filename[:-len(manifest_json)] |
+ for filename in server_instance.content_cache.GetFromFileListing( |
+ svn_constants.EXAMPLES_PATH) |
+ if filename.endswith(manifest_json)] |
+ logging.info('cron/%s: rendering %s example zips...' % ( |
+ channel, len(example_zips))) |
+ start_time = time.time() |
+ try: |
+ success = success and all( |
+ get_via_render_servlet('extensions/examples/%s' % z).status == 200 |
+ for z in example_zips) |
+ finally: |
+ logging.info('cron/%s: rendering %s example zips took %s seconds' % ( |
+ channel, len(example_zips), time.time() - start_time)) |
+ |
+ # Also trigger a redirect so that PathCanonicalizer has an opportunity to |
+ # cache file listings. |
+ logging.info('cron/%s: triggering a redirect...' % channel) |
+ redirect_response = get_via_render_servlet('storage.html') |
+ success = success and redirect_response.status == 302 |
+ except DeadlineExceededError: |
+ success = False |
logging.info('cron/%s: finished' % channel) |