def _WaitImpl(self): try: already_finishing = False with self.lock: if self._state == apiproxy_rpc.RPC.FINISHING: already_finishing = True else: self._state = apiproxy_rpc.RPC.FINISHING if already_finishing: self.event.wait() return True try: response = self._result_future.get() if response.status_code != requests.codes.ok: raise apiproxy_errors.RPCFailedError( 'Proxy returned HTTP status %s %s' % (response.status_code, response.reason)) except requests.exceptions.Timeout: raise self._ErrorException(*_DEADLINE_EXCEEDED_EXCEPTION) except requests.exceptions.RequestException: raise self._ErrorException(*_DEFAULT_EXCEPTION) parsed_response = remote_api_pb.Response(response.content) if (parsed_response.has_application_error() or parsed_response.has_rpc_error()): raise self._TranslateToError(parsed_response) self.response.ParseFromString(parsed_response.response()) except Exception: _, exc, tb = sys.exc_info() self._exception = exc self._traceback = tb try: self._Callback() return True finally: self.event.set()
def _SendRequest(self, **kwargs): try: response = self.stub.http.request(**kwargs) if response.status != 200: raise apiproxy_errors.RPCFailedError( 'Proxy returned HTTP status %s %s' % (response.status, response.reason)) except urllib3.exceptions.TimeoutError: raise self._ErrorException(*_DEADLINE_EXCEEDED_EXCEPTION) except (urllib3.exceptions.RequestError, urllib3.exceptions.ConnectionError): raise self._ErrorException(*_DEFAULT_EXCEPTION) parsed_response = remote_api_pb2.Response.FromString(response.data) if (parsed_response.HasField('application_error') or parsed_response.HasField('rpc_error')): raise self._TranslateToError(parsed_response) self.response.ParseFromString(parsed_response.response)
def _MakeCallImpl(self): """Makes an asynchronous API call over the service bridge. For this to work the following must be set: self.package: the API package name; self.call: the name of the API call/method to invoke; self.request: the API request body as a serialized protocol buffer. The actual API call is made by urllib3.request via a thread pool (multiprocessing.dummy.Pool). The thread pool restricts the number of concurrent requests to MAX_CONCURRENT_API_CALLS, so this method will block if that limit is exceeded, until other asynchronous calls resolve. If the main thread holds the import lock, waiting on thread work can cause a deadlock: https://docs.python.org/2/library/threading.html#importing-in-threaded-code Therefore, we try to detect this error case and fall back to sync calls. """ assert self._state == apiproxy_rpc.RPC.IDLE, self._state ticket = None if VMStub.ShouldUseRequestSecurityTicketForThread(): ticket = os.environ.get(TICKET_HEADER, os.environ.get(DEV_TICKET_HEADER)) if not ticket: raise apiproxy_errors.RPCFailedError( 'Attempted RPC call without active security ticket') request = remote_api_pb2.Request( service_name=self.package, method=self.call, request_id=ticket, request=self.request.SerializeToString()) deadline = self.deadline or DEFAULT_TIMEOUT body_data = request.SerializeToString() headers = { SERVICE_DEADLINE_HEADER: str(deadline), SERVICE_ENDPOINT_HEADER: SERVICE_ENDPOINT_NAME, SERVICE_METHOD_HEADER: APIHOST_METHOD, 'Content-type': RPC_CONTENT_TYPE, } dapper_header_value = os.environ.get(DAPPER_ENV_KEY) if dapper_header_value: headers[DAPPER_HEADER] = dapper_header_value api_host = os.environ.get('API_HOST', SERVICE_BRIDGE_HOST) api_port = os.environ.get('API_PORT', API_PORT) if ':' in api_host: api_host = '[{}]'.format(api_host) endpoint_url = six.moves.urllib.parse.urlunparse( ('http', '%s:%s' % (api_host, api_port), PROXY_PATH, '', '', '')) self._state = apiproxy_rpc.RPC.RUNNING request_kwargs = dict(url=endpoint_url, method='POST', timeout=DEADLINE_DELTA_SECONDS + deadline, headers=headers, body=body_data) if six.PY2 and imp.lock_held(): self.future = futures.Future() self.future.set_result( self._SendRequestAndFinish(**request_kwargs)) else: self.future = self.stub.thread_pool.submit( self._SendRequestAndFinish, **request_kwargs)