| 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 |