OLD | NEW |
1 # Copyright 2016 The Chromium Authors. All rights reserved. | 1 # Copyright 2016 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 math |
6 import os | 7 import os |
7 import sys | 8 import sys |
8 import time | 9 import time |
9 | 10 |
10 import cloudstorage | 11 import cloudstorage |
11 import flask | 12 import flask |
12 from google.appengine.api import (app_identity, taskqueue) | 13 from google.appengine.api import (app_identity, taskqueue) |
13 from google.appengine.ext import deferred | 14 from google.appengine.ext import deferred |
14 from oauth2client.client import GoogleCredentials | 15 from oauth2client.client import GoogleCredentials |
15 | 16 |
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
351 # Compute estimates for the work duration, in order to compute the instance | 352 # Compute estimates for the work duration, in order to compute the instance |
352 # count and the timeout. | 353 # count and the timeout. |
353 sequential_duration_s = \ | 354 sequential_duration_s = \ |
354 GetEstimatedTaskDurationInSeconds(sub_tasks[0]) * len(sub_tasks) | 355 GetEstimatedTaskDurationInSeconds(sub_tasks[0]) * len(sub_tasks) |
355 if sequential_duration_s <= 0: | 356 if sequential_duration_s <= 0: |
356 return Render('Time estimation failed.', memory_logs) | 357 return Render('Time estimation failed.', memory_logs) |
357 | 358 |
358 # Compute the number of required instances if not specified. | 359 # Compute the number of required instances if not specified. |
359 if not task.BackendParams().get('instance_count'): | 360 if not task.BackendParams().get('instance_count'): |
360 target_parallel_duration_s = 1800.0 # 30 minutes. | 361 target_parallel_duration_s = 1800.0 # 30 minutes. |
361 task.BackendParams()['instance_count'] = int( | 362 task.BackendParams()['instance_count'] = math.ceil( |
362 sequential_duration_s / target_parallel_duration_s + 0.5) # Rounded up. | 363 sequential_duration_s / target_parallel_duration_s) |
363 | 364 |
364 # Check the instance quotas. | 365 # Check the instance quotas. |
365 clovis_logger.info( | 366 clovis_logger.info( |
366 'Requesting %i instances.' % task.BackendParams()['instance_count']) | 367 'Requesting %i instances.' % task.BackendParams()['instance_count']) |
367 max_instances = instance_helper.GetAvailableInstanceCount() | 368 max_instances = instance_helper.GetAvailableInstanceCount() |
368 if max_instances == -1: | 369 if max_instances == -1: |
369 return Render('Failed to count the available instances.', memory_logs) | 370 return Render('Failed to count the available instances.', memory_logs) |
370 elif task.BackendParams()['instance_count'] == 0: | 371 elif task.BackendParams()['instance_count'] == 0: |
371 return Render('Cannot create instances, quota exceeded.', memory_logs) | 372 return Render('Cannot create instances, quota exceeded.', memory_logs) |
372 elif max_instances < task.BackendParams()['instance_count']: | 373 elif max_instances < task.BackendParams()['instance_count']: |
373 clovis_logger.warning( | 374 clovis_logger.warning( |
374 'Instance count limited by quota: %i available / %i requested.' % ( | 375 'Instance count limited by quota: %i available / %i requested.' % ( |
375 max_instances, task.BackendParams()['instance_count'])) | 376 max_instances, task.BackendParams()['instance_count'])) |
376 task.BackendParams()['instance_count'] = max_instances | 377 task.BackendParams()['instance_count'] = max_instances |
377 | 378 |
378 # Compute the timeout if there is none specified. | 379 # Compute the timeout if there is none specified. |
379 expected_duration_h = sequential_duration_s / ( | 380 expected_duration_h = sequential_duration_s / ( |
380 task.BackendParams()['instance_count'] * 3600.0) | 381 task.BackendParams()['instance_count'] * 3600.0) |
381 if not task.BackendParams().get('timeout_hours'): | 382 if not task.BackendParams().get('timeout_hours'): |
382 # Timeout is at least 1 hour. | 383 # Timeout is at least 1 hour. |
383 task.BackendParams()['timeout_hours'] = max(1, 5 * expected_duration_h) | 384 task.BackendParams()['timeout_hours'] = max(1, 5 * expected_duration_h) |
384 clovis_logger.info( | 385 clovis_logger.info( |
385 'Timeout delay: %i hours. ' % task.BackendParams()['timeout_hours']) | 386 'Timeout delay: %.1f hours. ' % task.BackendParams()['timeout_hours']) |
386 | 387 |
387 if not EnqueueTasks(sub_tasks, task_tag): | 388 if not EnqueueTasks(sub_tasks, task_tag): |
388 return Render('Task creation failed.', memory_logs) | 389 return Render('Task creation failed.', memory_logs) |
389 | 390 |
390 # Start polling the progress. | 391 # Start polling the progress. |
391 clovis_logger.info('Creating worker polling task.') | 392 clovis_logger.info('Creating worker polling task.') |
392 first_poll_delay_minutes = 10 | 393 first_poll_delay_minutes = 10 |
393 deferred.defer(PollWorkers, task_tag, time.time(), | 394 deferred.defer(PollWorkers, task_tag, time.time(), |
394 task.BackendParams()['timeout_hours'], user_email, | 395 task.BackendParams()['timeout_hours'], user_email, |
395 task_url, _countdown=(60 * first_poll_delay_minutes)) | 396 task_url, _countdown=(60 * first_poll_delay_minutes)) |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
456 @app.errorhandler(404) | 457 @app.errorhandler(404) |
457 def PageNotFound(e): # pylint: disable=unused-argument | 458 def PageNotFound(e): # pylint: disable=unused-argument |
458 """Return a custom 404 error.""" | 459 """Return a custom 404 error.""" |
459 return 'Sorry, Nothing at this URL.', 404 | 460 return 'Sorry, Nothing at this URL.', 404 |
460 | 461 |
461 | 462 |
462 @app.errorhandler(500) | 463 @app.errorhandler(500) |
463 def ApplicationError(e): | 464 def ApplicationError(e): |
464 """Return a custom 500 error.""" | 465 """Return a custom 500 error.""" |
465 return 'Sorry, unexpected error: {}'.format(e), 499 | 466 return 'Sorry, unexpected error: {}'.format(e), 499 |
OLD | NEW |