comparison piecrust/baking/worker.py @ 415:0e9a94b7fdfa

bake: Improve bake record information. * Store things in the bake record that require less interaction between the master process and the workers. For instance, don't store the paginator object in the render pass info -- instead, just store whether pagination was used, and whether it had more items. * Simplify information passing between workers and bake passes by saving the rendering info to the JSON cache. This means the "render first sub" job doesn't have to return anything except errors now. * Add more performance counter info.
author Ludovic Chabant <ludovic@chabant.com>
date Sat, 20 Jun 2015 19:23:16 -0700
parents e7b865f8f335
children 4a43d7015b75
comparison
equal deleted inserted replaced
414:c4b3a7fd2f87 415:0e9a94b7fdfa
62 JOB_BAKE: BakeJobHandler(app, self.ctx)} 62 JOB_BAKE: BakeJobHandler(app, self.ctx)}
63 for jt, jh in job_handlers.items(): 63 for jt, jh in job_handlers.items():
64 app.env.registerTimer(type(jh).__name__) 64 app.env.registerTimer(type(jh).__name__)
65 65
66 # Start working! 66 # Start working!
67 aborted_with_exception = None
67 while not self.ctx.abort_event.is_set(): 68 while not self.ctx.abort_event.is_set():
68 try: 69 try:
69 with app.env.timerScope('JobReceive'): 70 with app.env.timerScope('JobReceive'):
70 job = self.ctx.work_queue.get(True, 0.01) 71 job = self.ctx.work_queue.get(True, 0.01)
71 except queue.Empty: 72 except queue.Empty:
75 handler = job_handlers[job.job_type] 76 handler = job_handlers[job.job_type]
76 with app.env.timerScope(type(handler).__name__): 77 with app.env.timerScope(type(handler).__name__):
77 handler.handleJob(job) 78 handler.handleJob(job)
78 except Exception as ex: 79 except Exception as ex:
79 self.ctx.abort_event.set() 80 self.ctx.abort_event.set()
80 self.abort_exception = ex 81 aborted_with_exception = ex
81 self.success = False
82 logger.debug("[%d] Critical error, aborting." % self.wid) 82 logger.debug("[%d] Critical error, aborting." % self.wid)
83 if self.ctx.app.debug: 83 if self.ctx.debug:
84 logger.exception(ex) 84 logger.exception(ex)
85 break 85 break
86 finally: 86 finally:
87 self.ctx.work_queue.task_done() 87 self.ctx.work_queue.task_done()
88 88
89 if aborted_with_exception is not None:
90 msgs = _get_errors(aborted_with_exception)
91 self.ctx.results.put_nowait({'type': 'error', 'messages': msgs})
92
89 # Send our timers to the main process before exiting. 93 # Send our timers to the main process before exiting.
90 app.env.stepTimer("Worker_%d" % self.wid, 94 app.env.stepTimer("Worker_%d" % self.wid,
91 time.perf_counter() - work_start_time) 95 time.perf_counter() - work_start_time)
92 self.ctx.results.put_nowait(app.env._timers) 96 self.ctx.results.put_nowait({
97 'type': 'timers', 'data': app.env._timers})
93 98
94 99
95 class JobHandler(object): 100 class JobHandler(object):
96 def __init__(self, app, ctx): 101 def __init__(self, app, ctx):
97 self.app = app 102 self.app = app
139 144
140 145
141 class RenderFirstSubJobResult(object): 146 class RenderFirstSubJobResult(object):
142 def __init__(self, path): 147 def __init__(self, path):
143 self.path = path 148 self.path = path
144 self.used_assets = None
145 self.used_pagination = None
146 self.pagination_has_more = False
147 self.errors = None 149 self.errors = None
148 150
149 151
150 class BakeJobPayload(object): 152 class BakeJobPayload(object):
151 def __init__(self, fac, route_metadata, previous_entry, 153 def __init__(self, fac, route_metadata, previous_entry,
152 first_render_info, dirty_source_names, tax_info=None): 154 dirty_source_names, tax_info=None):
153 self.factory_info = PageFactoryInfo(fac) 155 self.factory_info = PageFactoryInfo(fac)
154 self.route_metadata = route_metadata 156 self.route_metadata = route_metadata
155 self.previous_entry = previous_entry 157 self.previous_entry = previous_entry
156 self.dirty_source_names = dirty_source_names 158 self.dirty_source_names = dirty_source_names
157 self.first_render_info = first_render_info
158 self.taxonomy_info = tax_info 159 self.taxonomy_info = tax_info
159 160
160 161
161 class BakeJobResult(object): 162 class BakeJobResult(object):
162 def __init__(self, path, tax_info=None): 163 def __init__(self, path, tax_info=None):
163 self.path = path 164 self.path = path
164 self.taxonomy_info = tax_info 165 self.taxonomy_info = tax_info
165 self.bake_info = None 166 self.sub_entries = None
166 self.errors = None 167 self.errors = None
167 168
168 169
169 class LoadJobHandler(JobHandler): 170 class LoadJobHandler(JobHandler):
170 def handleJob(self, job): 171 def handleJob(self, job):
175 try: 176 try:
176 page = fac.buildPage() 177 page = fac.buildPage()
177 page._load() 178 page._load()
178 result.config = page.config.get() 179 result.config = page.config.get()
179 except Exception as ex: 180 except Exception as ex:
181 logger.debug("Got loading error. Sending it to master.")
180 result.errors = _get_errors(ex) 182 result.errors = _get_errors(ex)
183 if self.ctx.debug:
184 logger.exception(ex)
181 185
182 self.ctx.results.put_nowait(result) 186 self.ctx.results.put_nowait(result)
183 187
184 188
185 class RenderFirstSubJobHandler(JobHandler): 189 class RenderFirstSubJobHandler(JobHandler):
199 203
200 result = RenderFirstSubJobResult(fac.path) 204 result = RenderFirstSubJobResult(fac.path)
201 logger.debug("Preparing page: %s" % fac.ref_spec) 205 logger.debug("Preparing page: %s" % fac.ref_spec)
202 try: 206 try:
203 render_page_segments(ctx) 207 render_page_segments(ctx)
204 result.used_assets = ctx.used_assets
205 result.used_pagination = ctx.used_pagination is not None
206 if result.used_pagination:
207 result.pagination_has_more = ctx.used_pagination.has_more
208 except Exception as ex: 208 except Exception as ex:
209 logger.debug("Got rendering error. Sending it to master.") 209 logger.debug("Got rendering error. Sending it to master.")
210 result.errors = _get_errors(ex) 210 result.errors = _get_errors(ex)
211 if self.ctx.debug:
212 logger.exception(ex)
211 213
212 self.ctx.results.put_nowait(result) 214 self.ctx.results.put_nowait(result)
213 215
214 216
215 class BakeJobHandler(JobHandler): 217 class BakeJobHandler(JobHandler):
231 skip_taxonomies=True) 233 skip_taxonomies=True)
232 assert route is not None 234 assert route is not None
233 235
234 result = BakeJobResult(fac.path, tax_info) 236 result = BakeJobResult(fac.path, tax_info)
235 previous_entry = job.payload.previous_entry 237 previous_entry = job.payload.previous_entry
236 first_render_info = job.payload.first_render_info
237 dirty_source_names = job.payload.dirty_source_names 238 dirty_source_names = job.payload.dirty_source_names
238 logger.debug("Baking page: %s" % fac.ref_spec) 239 logger.debug("Baking page: %s" % fac.ref_spec)
239 try: 240 try:
240 report = self.page_baker.bake(fac, route, route_metadata, 241 sub_entries = self.page_baker.bake(
241 previous_entry, first_render_info, 242 fac, route, route_metadata, previous_entry,
242 dirty_source_names, tax_info) 243 dirty_source_names, tax_info)
243 result.bake_info = report 244 result.sub_entries = sub_entries
244 245
245 except BakingError as ex: 246 except BakingError as ex:
246 logger.debug("Got baking error. Sending it to master.") 247 logger.debug("Got baking error. Sending it to master.")
247 result.errors = _get_errors(ex) 248 result.errors = _get_errors(ex)
249 if self.ctx.debug:
250 logger.exception(ex)
248 251
249 self.ctx.results.put_nowait(result) 252 self.ctx.results.put_nowait(result)
250 253