Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: chrome/common/extensions/docs/server2/handler.py

Issue 14218004: Devserver: only populate data during cron jobs, meaning all data from instances (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix integration test Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import logging 5 import logging
6 import os 6 import os
7 from StringIO import StringIO 7 from StringIO import StringIO
8 8
9 from appengine_wrappers import webapp 9 from appengine_wrappers import webapp
10 from appengine_wrappers import memcache 10 from appengine_wrappers import memcache
11 from appengine_wrappers import urlfetch 11 from appengine_wrappers import urlfetch
12 from branch_utility import BranchUtility 12 from branch_utility import BranchUtility
13 from server_instance import ServerInstance 13 from server_instance import ServerInstance
14 import svn_constants 14 import svn_constants
15 import time 15 import time
16 16
17 # The default channel to serve docs for if no channel is specified. 17 # The default channel to serve docs for if no channel is specified.
18 _DEFAULT_CHANNEL = 'stable' 18 _DEFAULT_CHANNEL = 'stable'
19 19
20 class Handler(webapp.RequestHandler): 20 class Handler(webapp.RequestHandler):
21 # AppEngine instances should never need to call out to SVN. That should only
22 # ever be done by the cronjobs, which then write the result into DataStore,
23 # which is as far as instances look.
24 #
25 # Why? SVN is slow and a bit flaky. Cronjobs failing is annoying but
26 # temporary. Instances failing affects users, and is really bad.
27 #
28 # Anyway - to enforce this, we actually don't give instances access to SVN.
29 # If anything is missing from datastore, it'll be a 404. If the cronjobs
30 # don't manage to catch everything - uhoh. On the other hand, we'll figure it
31 # out pretty soon, and it also means that legitimate 404s are caught before a
32 # round trip to SVN.
33 #
34 # However, we can't expect users of preview.py to run a cronjob first, so,
35 # this is a hack allow that to be online all of the time.
36 # TODO(kalman): achieve this via proper dependency injection.
37 ALWAYS_ONLINE = False
38
21 def __init__(self, request, response): 39 def __init__(self, request, response):
22 super(Handler, self).__init__(request, response) 40 super(Handler, self).__init__(request, response)
23 41
24 def _HandleGet(self, path): 42 def _HandleGet(self, path):
25 channel_name, real_path = BranchUtility.SplitChannelNameFromPath(path) 43 channel_name, real_path = BranchUtility.SplitChannelNameFromPath(path)
26 44
27 if channel_name == _DEFAULT_CHANNEL: 45 if channel_name == _DEFAULT_CHANNEL:
28 self.redirect('/%s' % real_path) 46 self.redirect('/%s' % real_path)
29 return 47 return
30 48
31 if channel_name is None: 49 if channel_name is None:
32 channel_name = _DEFAULT_CHANNEL 50 channel_name = _DEFAULT_CHANNEL
33 51
34 # TODO(kalman): Check if |path| is a directory and serve path/index.html 52 # TODO(kalman): Check if |path| is a directory and serve path/index.html
35 # rather than special-casing apps/extensions. 53 # rather than special-casing apps/extensions.
36 if real_path.strip('/') == 'apps': 54 if real_path.strip('/') == 'apps':
37 real_path = 'apps/index.html' 55 real_path = 'apps/index.html'
38 if real_path.strip('/') == 'extensions': 56 if real_path.strip('/') == 'extensions':
39 real_path = 'extensions/index.html' 57 real_path = 'extensions/index.html'
40 58
41 server_instance = ServerInstance.GetOrCreate(channel_name) 59 constructor = (
60 ServerInstance.GetOrCreateOnline if Handler.ALWAYS_ONLINE else
61 ServerInstance.GetOrCreateOffline)
62 server_instance = constructor(channel_name)
42 63
43 canonical_path = server_instance.path_canonicalizer.Canonicalize(real_path) 64 canonical_path = server_instance.path_canonicalizer.Canonicalize(real_path)
44 if real_path != canonical_path: 65 if real_path != canonical_path:
45 self.redirect(canonical_path) 66 self.redirect(canonical_path)
46 return 67 return
47 68
48 ServerInstance.GetOrCreate(channel_name).Get(real_path, 69 server_instance.Get(real_path, self.request, self.response)
49 self.request,
50 self.response)
51 70
52 def _HandleCron(self, path): 71 def _HandleCron(self, path):
53 # Cron strategy: 72 # Cron strategy:
54 # 73 #
55 # Find all public template files and static files, and render them. Most of 74 # Find all public template files and static files, and render them. Most of
56 # the time these won't have changed since the last cron run, so it's a 75 # the time these won't have changed since the last cron run, so it's a
57 # little wasteful, but hopefully rendering is really fast (if it isn't we 76 # little wasteful, but hopefully rendering is really fast (if it isn't we
58 # have a problem). 77 # have a problem).
59 class MockResponse(object): 78 class MockResponse(object):
60 def __init__(self): 79 def __init__(self):
61 self.status = 200 80 self.status = 200
62 self.out = StringIO() 81 self.out = StringIO()
63 self.headers = {} 82 self.headers = {}
64 def set_status(self, status): 83 def set_status(self, status):
65 self.status = status 84 self.status = status
66 def clear(self, *args): 85 def clear(self, *args):
67 pass 86 pass
68 87
69 class MockRequest(object): 88 class MockRequest(object):
70 def __init__(self, path): 89 def __init__(self, path):
71 self.headers = {} 90 self.headers = {}
72 self.path = path 91 self.path = path
73 self.url = '//localhost/%s' % path 92 self.url = '//localhost/%s' % path
74 93
75 channel = path.split('/')[-1] 94 channel = path.split('/')[-1]
76 logging.info('cron/%s: starting' % channel) 95 logging.info('cron/%s: starting' % channel)
77 96
78 server_instance = ServerInstance.GetOrCreate(channel) 97 server_instance = ServerInstance.GetOrCreateOnline(channel)
79 98
80 def run_cron_for_dir(d): 99 def run_cron_for_dir(d, path_prefix=''):
81 error = None 100 error = None
82 start_time = time.time() 101 start_time = time.time()
83 files = [f for f in server_instance.content_cache.GetFromFileListing(d) 102 files = [f for f in server_instance.content_cache.GetFromFileListing(d)
84 if not f.endswith('/')] 103 if not f.endswith('/')]
85 for f in files: 104 for f in files:
105 path = '%s%s' % (path_prefix, f)
86 try: 106 try:
87 server_instance.Get(f, MockRequest(f), MockResponse()) 107 response = MockResponse()
108 server_instance.Get(path, MockRequest(path), response)
109 if response.status != 200:
110 error = 'Got %s response' % response.status
88 except error: 111 except error:
89 logging.error('cron/%s: error rendering %s/%s: %s' % ( 112 pass
90 channel, d, f, error)) 113 if error:
91 logging.info('cron/%s: rendering %s files in %s took %s seconds' % ( 114 logging.error('cron/%s: error rendering %s: %s' % (
92 channel, len(files), d, time.time() - start_time)) 115 channel, path, error))
116 logging.info('cron/%s: rendering %s files took %s seconds' % (
117 channel, len(files), time.time() - start_time))
93 return error 118 return error
94 119
95 # Don't use "or" since we want to evaluate everything no matter what. 120 # Don't use "or" since we want to evaluate everything no matter what.
96 was_error = any((run_cron_for_dir(svn_constants.PUBLIC_TEMPLATE_PATH), 121 was_error = any((
97 run_cron_for_dir(svn_constants.STATIC_PATH))) 122 run_cron_for_dir(svn_constants.PUBLIC_TEMPLATE_PATH),
123 run_cron_for_dir(svn_constants.STATIC_PATH, path_prefix='static/')))
98 124
99 if was_error: 125 if was_error:
100 self.response.status = 500 126 self.response.status = 500
101 self.response.out.write('Failure') 127 self.response.out.write('Failure')
102 else: 128 else:
103 self.response.status = 200 129 self.response.status = 200
104 self.response.out.write('Success') 130 self.response.out.write('Success')
105 131
106 logging.info('cron/%s: finished' % channel) 132 logging.info('cron/%s: finished' % channel)
107 133
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
153 # file paths will know to treat this as a directory. 179 # file paths will know to treat this as a directory.
154 if os.path.splitext(path)[1] == '' and path[-1] != '/': 180 if os.path.splitext(path)[1] == '' and path[-1] != '/':
155 self.redirect(path + '/') 181 self.redirect(path + '/')
156 return 182 return
157 183
158 path = path.strip('/') 184 path = path.strip('/')
159 if self._RedirectFromCodeDotGoogleDotCom(path): 185 if self._RedirectFromCodeDotGoogleDotCom(path):
160 return 186 return
161 187
162 self._HandleGet(path) 188 self._HandleGet(path)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698