Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2015 The LUCI Authors. All rights reserved. | 1 # Copyright 2015 The LUCI Authors. All rights reserved. |
| 2 # Use of this source code is governed under the Apache License, Version 2.0 | 2 # Use of this source code is governed under the Apache License, Version 2.0 |
| 3 # that can be found in the LICENSE file. | 3 # that can be found in the LICENSE file. |
| 4 | 4 |
| 5 """This module defines Swarming Server endpoints handlers.""" | 5 """This module defines Swarming Server endpoints handlers.""" |
| 6 | 6 |
| 7 import logging | 7 import logging |
| 8 import os | 8 import os |
| 9 | 9 |
| 10 from google.appengine.api import datastore_errors | 10 from google.appengine.api import datastore_errors |
| 11 from google.appengine.api import memcache as gae_memcache | |
|
M-A Ruel
2017/02/16 18:15:19
why rename?
kjlubick
2017/02/17 15:54:49
It was to be consistent with components/utils.py.
| |
| 11 from google.appengine.ext import ndb | 12 from google.appengine.ext import ndb |
| 13 | |
| 12 import endpoints | 14 import endpoints |
| 13 import gae_ts_mon | 15 import gae_ts_mon |
| 14 from protorpc import messages | 16 from protorpc import messages |
| 15 from protorpc import message_types | 17 from protorpc import message_types |
| 16 from protorpc import protojson | 18 from protorpc import protojson |
| 17 from protorpc import remote | 19 from protorpc import remote |
| 18 | 20 |
| 19 from components import auth | 21 from components import auth |
| 20 from components import datastore_utils | 22 from components import datastore_utils |
| 21 from components import endpoints_webapp2 | 23 from components import endpoints_webapp2 |
| (...skipping 481 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 503 @auth.endpoints_method( | 505 @auth.endpoints_method( |
| 504 swarming_rpcs.TasksCountRequest, swarming_rpcs.TasksCount, | 506 swarming_rpcs.TasksCountRequest, swarming_rpcs.TasksCount, |
| 505 http_method='GET') | 507 http_method='GET') |
| 506 @auth.require(acl.is_privileged_user) | 508 @auth.require(acl.is_privileged_user) |
| 507 def count(self, request): | 509 def count(self, request): |
| 508 """Counts number of tasks in a given state.""" | 510 """Counts number of tasks in a given state.""" |
| 509 logging.info('%s', request) | 511 logging.info('%s', request) |
| 510 if not request.start: | 512 if not request.start: |
| 511 raise endpoints.BadRequestException('start (as epoch) is required') | 513 raise endpoints.BadRequestException('start (as epoch) is required') |
| 512 now = utils.utcnow() | 514 now = utils.utcnow() |
| 515 mem_key = self._memcache_key(request, now) | |
| 516 count = gae_memcache.get(mem_key) | |
|
M-A Ruel
2017/02/16 18:15:19
use a namespace, e.g. 'tasks_count'
| |
| 517 if count is not None: | |
| 518 return swarming_rpcs.TasksCount(count=count, now=now) | |
| 519 | |
| 513 try: | 520 try: |
| 514 count = self._query_from_request(request, 'created_ts').count() | 521 count = self._query_from_request(request, 'created_ts').count() |
| 522 gae_memcache.add(mem_key, count, 120) | |
|
M-A Ruel
2017/02/16 18:15:19
technically the entry is valid for a while since y
kjlubick
2017/02/17 15:54:49
Done
| |
| 515 except ValueError as e: | 523 except ValueError as e: |
| 516 raise endpoints.BadRequestException( | 524 raise endpoints.BadRequestException( |
| 517 'Inappropriate filter for tasks/count: %s' % e) | 525 'Inappropriate filter for tasks/count: %s' % e) |
| 518 return swarming_rpcs.TasksCount(count=count, now=now) | 526 return swarming_rpcs.TasksCount(count=count, now=now) |
| 519 | 527 |
| 528 def _memcache_key(self, request, now): | |
| 529 # Floor now to minute to account for empty "end" | |
| 530 end = request.end or now.replace(second=0, microsecond=0) | |
| 531 request.tags.sort() | |
| 532 return '%s|%s|%s|%s' % (request.tags, request.state, request.start, end) | |
| 533 | |
| 520 def _query_from_request(self, request, sort=None): | 534 def _query_from_request(self, request, sort=None): |
| 521 """Returns a TaskResultSummary query.""" | 535 """Returns a TaskResultSummary query.""" |
| 522 start = message_conversion.epoch_to_datetime(request.start) | 536 start = message_conversion.epoch_to_datetime(request.start) |
| 523 end = message_conversion.epoch_to_datetime(request.end) | 537 end = message_conversion.epoch_to_datetime(request.end) |
| 524 return task_result.get_result_summaries_query( | 538 return task_result.get_result_summaries_query( |
| 525 start, end, | 539 start, end, |
| 526 sort or request.sort.name.lower(), | 540 sort or request.sort.name.lower(), |
| 527 request.state.name.lower(), | 541 request.state.name.lower(), |
| 528 request.tags) | 542 request.tags) |
| 529 | 543 |
| (...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 819 def get_routes(): | 833 def get_routes(): |
| 820 return ( | 834 return ( |
| 821 endpoints_webapp2.api_routes(SwarmingServerService) + | 835 endpoints_webapp2.api_routes(SwarmingServerService) + |
| 822 endpoints_webapp2.api_routes(SwarmingTaskService) + | 836 endpoints_webapp2.api_routes(SwarmingTaskService) + |
| 823 endpoints_webapp2.api_routes(SwarmingTasksService) + | 837 endpoints_webapp2.api_routes(SwarmingTasksService) + |
| 824 endpoints_webapp2.api_routes(SwarmingBotService) + | 838 endpoints_webapp2.api_routes(SwarmingBotService) + |
| 825 endpoints_webapp2.api_routes(SwarmingBotsService) + | 839 endpoints_webapp2.api_routes(SwarmingBotsService) + |
| 826 # components.config endpoints for validation and configuring of luci-config | 840 # components.config endpoints for validation and configuring of luci-config |
| 827 # service URL. | 841 # service URL. |
| 828 endpoints_webapp2.api_routes(config.ConfigApi)) | 842 endpoints_webapp2.api_routes(config.ConfigApi)) |
| OLD | NEW |