def new_instance(self, instance_id, expect_ready_request=False): """Create and return a new Instance. Args: instance_id: A string or integer representing the unique (per module) id of the instance. expect_ready_request: If True then the instance will be sent a special request (i.e. /_ah/warmup or /_ah/start) before it can handle external requests. Returns: The newly created instance.Instance. """ def instance_config_getter(): runtime_config = self._GenerateConfigForRuntime() runtime_config.instance_id = str(instance_id) return runtime_config php_executable_path = ( self._GenerateConfigForRuntime().php_config.php_executable_path) gae_extension_path = ( self._GenerateConfigForRuntime().php_config.gae_extension_path) self._check_binaries(php_executable_path, gae_extension_path) proxy = http_runtime.HttpRuntimeProxy(_RUNTIME_ARGS, instance_config_getter, self._module_configuration) return instance.Instance(self.request_data, instance_id, proxy, self.max_concurrent_requests, self.max_background_threads, expect_ready_request)
def new_instance(self, instance_id, expect_ready_request=False): """Create and return a new Instance. Args: instance_id: A string or integer representing the unique (per module) id of the instance. expect_ready_request: If True then the instance will be sent a special request (i.e. /_ah/warmup or /_ah/start) before it can handle external requests. Returns: The newly created instance.Instance. """ def instance_config_getter(): runtime_config = self._runtime_config_getter() runtime_config.instance_id = str(instance_id) return runtime_config env = self._java_application.get_environment() with self._application_lock: proxy = http_runtime.HttpRuntimeProxy( self._java_command, instance_config_getter, self._module_configuration, env=env, start_process_flavor=http_runtime.START_PROCESS_FILE) return instance.Instance(self.request_data, instance_id, proxy, self.max_concurrent_requests, self.max_background_threads, expect_ready_request)
def new_instance(self, instance_id, expect_ready_request=False): """Create and return a new Instance. Args: instance_id: A string or integer representing the unique (per module) id of the instance. expect_ready_request: If True then the instance will be sent a special request (i.e. /_ah/warmup or /_ah/start) before it can handle external requests. Returns: The newly created instance.Instance. """ def instance_config_getter(): runtime_config = self._runtime_config_getter() runtime_config.instance_id = str(instance_id) return runtime_config # This is also checked in a more user-friendly fashion earlier in execution. assert self._runtime_config_getter().custom_config.custom_entrypoint proxy = http_runtime.HttpRuntimeProxy( # Split the input from the command line into a Popen-compatible list. shlex.split( self._runtime_config_getter().custom_config.custom_entrypoint), instance_config_getter, self._module_configuration, env=dict(os.environ), start_process_flavor=http_runtime.START_PROCESS_REVERSE_NO_FILE) return instance.Instance(self.request_data, instance_id, proxy, self.max_concurrent_requests, self.max_background_threads, expect_ready_request)
def test_handle_background_request(self): inst = instance.Instance(self.request_data, 'name', self.proxy, max_concurrent_requests=5, max_background_threads=2) inst._num_running_background_threads = 1 self.mox.StubOutWithMock(inst._condition, 'notify') self.proxy.start() self.environ = {} self.request_data.set_request_instance(self.request_id, inst) self.proxy.handle(self.environ, self.start_response, self.url_map, self.match, self.request_id, instance.BACKGROUND_REQUEST).AndReturn(self.response) self.mox.ReplayAll() inst.start() self.assertTrue(inst.can_accept_requests) self.assertEqual(1, inst.remaining_background_thread_capacity) self.assertEqual( self.response, list( inst.handle(self.environ, self.start_response, self.url_map, self.match, self.request_id, instance.BACKGROUND_REQUEST))) self.mox.VerifyAll() self.assertEqual(1, inst.total_requests) self.assertEqual(5, inst.remaining_request_capacity) self.assertEqual(0, inst.num_outstanding_requests) self.assertTrue(0 < inst.get_qps_60s()) self.assertEqual(2, inst.remaining_background_thread_capacity) self.assertFalse(inst.handling_ready_request)
def new_instance(self, instance_id, expect_ready_request=False): """Create and return a new Instance. Args: instance_id: A string or integer representing the unique (per module) id of the instance. expect_ready_request: If True then the instance will be sent a special request (i.e. /_ah/warmup or /_ah/start) before it can handle external requests. Returns: The newly created instance.Instance. """ def instance_config_getter(): runtime_config = self._runtime_config_getter() runtime_config.instance_id = str(instance_id) return runtime_config proxy = http_runtime.HttpRuntimeProxy( _RUNTIME_ARGS, instance_config_getter, self._module_configuration, env=dict(os.environ, PYTHONHASHSEED='random'), start_process_flavor=http_runtime.START_PROCESS_FILE) return instance.Instance(self.request_data, instance_id, proxy, self.max_concurrent_requests, self.max_background_threads, expect_ready_request)
def test_handle(self): inst = instance.Instance(self.request_data, 'name', self.proxy, max_concurrent_requests=5) self.mox.StubOutWithMock(inst._condition, 'notify') self.proxy.start() self.environ = {} self.request_data.set_request_instance(self.request_id, inst) self.proxy.handle(self.environ, self.start_response, self.url_map, self.match, self.request_id, instance.NORMAL_REQUEST).AndReturn(self.response) inst._condition.notify() self.mox.ReplayAll() now = time.time() inst._request_history.append((now - 100, now - 80)) inst.start() self.assertTrue(inst.can_accept_requests) self.assertEqual( self.response, list( inst.handle(self.environ, self.start_response, self.url_map, self.match, self.request_id, instance.NORMAL_REQUEST))) self.mox.VerifyAll() self.assertEqual(1, len(inst._request_history)) self.assertEqual(1, inst.total_requests) self.assertEqual(5, inst.remaining_request_capacity) self.assertEqual(0, inst.num_outstanding_requests) self.assertTrue(0 < inst.get_qps_60s())
def test_handle_ready_request(self): inst = instance.Instance(self.request_data, 'name', self.proxy, max_concurrent_requests=5, expect_ready_request=True) self.mox.StubOutWithMock(inst._condition, 'notify') self.proxy.start() self.environ = {} self.request_data.set_request_instance(self.request_id, inst) self.proxy.handle(self.environ, self.start_response, self.url_map, self.match, self.request_id, instance.READY_REQUEST).AndReturn(self.response) inst._condition.notify(5) self.mox.ReplayAll() inst.start() self.assertFalse(inst.can_accept_requests) self.assertRaises(instance.CannotAcceptRequests, inst.handle, self.environ, self.start_response, self.url_map, self.match, self.request_id, instance.NORMAL_REQUEST) self.assertEqual( self.response, list( inst.handle(self.environ, self.start_response, self.url_map, self.match, self.request_id, instance.READY_REQUEST))) self.mox.VerifyAll() self.assertEqual(1, inst.total_requests) self.assertEqual(5, inst.remaining_request_capacity) self.assertEqual(0, inst.num_outstanding_requests) self.assertTrue(0 < inst.get_qps_60s()) self.assertFalse(inst.handling_ready_request)
def new_instance(self, instance_id, expect_ready_request=False): """Create and return a new Instance. Args: instance_id: A string or integer representing the unique (per module) id of the instance. expect_ready_request: If True then the instance will be sent a special request (i.e. /_ah/warmup or /_ah/start) before it can handle external requests. Returns: The newly created instance.Instance. """ def runtime_config_getter(): runtime_config = self._runtime_config_getter() runtime_config.instance_id = str(instance_id) return runtime_config effective_runtime = self._module_configuration.effective_runtime proxy_class = self.RUNTIME_SPECIFIC_PROXY.get( effective_runtime, vm_runtime_proxy.VMRuntimeProxy) proxy = proxy_class(self._docker_client, runtime_config_getter, self._module_configuration) return instance.Instance(self.request_data, instance_id, proxy, self.max_concurrent_requests, self.max_background_threads, expect_ready_request)
def new_instance(self, instance_id, expect_ready_request=False): """Create and return a new Instance. Args: instance_id: A string or integer representing the unique (per module) id of the instance. expect_ready_request: If True then the instance will be sent a special request (i.e. /_ah/warmup or /_ah/start) before it can handle external requests. Returns: The newly created instance.Instance. """ def instance_config_getter(): runtime_config = self._runtime_config_getter() runtime_config.instance_id = str(instance_id) return runtime_config proxy = http_runtime.HttpRuntimeProxy( self._GetRuntimeArgs(), instance_config_getter, self._module_configuration, env=self._GetRuntimeEnvironmentVariables(instance_id), start_process_flavor=self._get_process_flavor()) return instance.Instance(self.request_data, instance_id, proxy, self.max_concurrent_requests, self.max_background_threads, expect_ready_request)
def test_get_latency_60s(self): inst = instance.Instance(self.request_data, 'name', self.proxy, max_concurrent_requests=5) now = time.time() inst._request_history = [(now, now + 1), (now + 2, now + 4)] self.assertEqual(1.5, inst.get_latency_60s())
def test_get_qps_60s(self): inst = instance.Instance(self.request_data, 'name', self.proxy, max_concurrent_requests=5) now = time.time() inst._request_history = [(now, now + 1)] * 120 self.assertEqual(2.0, inst.get_qps_60s())
def test_wait_timed_out_without_capacity(self): inst = instance.Instance(self.request_data, 'name', self.proxy, max_concurrent_requests=0) inst._started = True self.mox.StubOutWithMock(inst._condition, 'wait') self.mox.ReplayAll() self.assertFalse(inst.wait(0)) self.mox.VerifyAll()
def test_wait_quit_while_waiting(self): self.mox.stubs.Set(time, 'time', lambda: 0) inst = instance.Instance(self.request_data, 'name', self.proxy, max_concurrent_requests=0) self.mox.StubOutWithMock(inst._condition, 'wait') inst._condition.wait(1).WithSideEffects(lambda *unused_args: inst.quit()) self.mox.ReplayAll() self.assertFalse(inst.wait(1)) self.mox.VerifyAll()
def test_wait_with_capacity(self): inst = instance.Instance(self.request_data, 'name', self.proxy, max_concurrent_requests=1) inst._started = True self.mox.StubOutWithMock(inst._condition, 'wait') self.mox.stubs.Set(time, 'time', lambda: 0) self.mox.ReplayAll() self.assertTrue(inst.wait(1)) self.mox.VerifyAll()
def new_instance(self, instance_id, expect_ready_request=False): """Create and return a new Instance. Args: instance_id: A string or integer representing the unique (per module) id of the instance. expect_ready_request: If True then the instance will be sent a special request (i.e. /_ah/warmup or /_ah/start) before it can handle external requests. Returns: The newly created instance.Instance. """ def instance_config_getter(): runtime_config = self._runtime_config_getter() runtime_config.instance_id = str(instance_id) return runtime_config with self._application_lock: try: if self._go_application.maybe_build( self._modified_since_last_build): if self._last_build_error: logging.info('Go application successfully built.') self._last_build_error = None except go_errors.BuildError as e: logging.error('Failed to build Go application: %s', e) # Deploy a failure proxy now and each time a new instance is requested. self._last_build_error = e metrics.GetMetricsLogger().LogOnceOnStop( metrics.DEVAPPSERVER_CATEGORY, metrics.ERROR_ACTION, label=repr(e)) self._modified_since_last_build = False if self._last_build_error: logging.debug('Deploying new instance of failure proxy.') proxy = _GoBuildFailureRuntimeProxy(self._last_build_error) else: environ = self._go_application.get_environment() # Add in the environment settings from app_yaml "env_variables:" runtime_config = self._runtime_config_getter() for kv in runtime_config.environ: environ[kv.key] = kv.value proxy = http_runtime.HttpRuntimeProxy( [self._go_application.go_executable], instance_config_getter, self._module_configuration, environ, start_process_flavor=self._start_process_flavor) return instance.Instance(self.request_data, instance_id, proxy, self.max_concurrent_requests, self.max_background_threads, expect_ready_request)
def test_handle_before_start(self): inst = instance.Instance(self.request_data, 'name', self.proxy, max_concurrent_requests=5) self.mox.StubOutWithMock(inst._condition, 'notify') self.assertRaises(instance.CannotAcceptRequests, inst.handle, self.environ, self.start_response, self.url_map, self.match, self.request_id, instance.NORMAL_REQUEST)
def test_reserve_background_thread_not_started(self): inst = instance.Instance(self.request_data, 'name', self.proxy, max_concurrent_requests=5, max_background_threads=1) self.mox.ReplayAll() self.assertEqual(1, inst.remaining_background_thread_capacity) self.assertRaises(instance.CannotAcceptRequests, inst.reserve_background_thread) self.mox.VerifyAll() self.assertEqual(1, inst.remaining_background_thread_capacity)
def test_reserve_background_thread_not_ready(self): inst = instance.Instance(self.request_data, 'name', self.proxy, max_concurrent_requests=5, max_background_threads=2, expect_ready_request=True) inst._started = True self.mox.ReplayAll() self.assertEqual(2, inst.remaining_background_thread_capacity) inst.reserve_background_thread() self.mox.VerifyAll() self.assertEqual(1, inst.remaining_background_thread_capacity)
def test_wait_quit_while_starting(self): inst = instance.Instance(self.request_data, 'name', self.proxy, max_concurrent_requests=5) self.mox.StubOutWithMock(inst._condition, 'notify_all') self.proxy.start().WithSideEffects(inst.quit) self.proxy.quit() self.mox.ReplayAll() inst.start() self.mox.VerifyAll() self.assertFalse(inst.can_accept_requests)
def test_quit_with_request(self): inst = instance.Instance(self.request_data, 'name', self.proxy, max_concurrent_requests=5) self.mox.StubOutWithMock(inst._condition, 'notify_all') self.proxy.start() self.mox.ReplayAll() inst.start() self.mox.VerifyAll() inst._num_outstanding_requests = 1 self.assertRaises(instance.CannotQuitServingInstance, inst.quit)
def test_new_instance(self): inst = instance.Instance( self.request_data, 'name', self.proxy, max_concurrent_requests=5, expect_ready_request=True) self.assertEqual(0, inst.total_requests) self.assertEqual(5, inst.remaining_request_capacity) self.assertEqual(0, inst.num_outstanding_requests) self.assertFalse(inst.can_accept_requests) self.assertTrue(inst.handling_ready_request) self.assertAlmostEqual(0, inst.idle_seconds, places=2) self.assertEqual(0, inst.get_latency_60s()) self.assertEqual(0, inst.get_qps_60s()) self.assertEqual('name', inst.instance_id)
def test_quit_with_request_allow_async(self): inst = instance.Instance(self.request_data, 'name', self.proxy, max_concurrent_requests=5) self.mox.StubOutWithMock(inst._condition, 'notify_all') inst._num_outstanding_requests = 1 self.proxy.start() self.mox.ReplayAll() inst.start() inst.quit(allow_async=True) self.mox.VerifyAll() self.assertTrue(inst._quitting)
def test_quit_shutdown(self): inst = instance.Instance(self.request_data, 'name', self.proxy, max_concurrent_requests=5) self.mox.StubOutWithMock(inst._condition, 'notify_all') inst._num_outstanding_requests = 1 self.proxy.start() self.mox.ReplayAll() inst.start() inst.quit(expect_shutdown=True) self.mox.VerifyAll() self.assertTrue(inst._expecting_shutdown_request) self.assertFalse(inst._quitting)
def test_wait_without_capacity(self): inst = instance.Instance(self.request_data, 'name', self.proxy, max_concurrent_requests=0) inst._started = True self.mox.StubOutWithMock(inst._condition, 'wait') self.time = 0 self.mox.stubs.Set(time, 'time', lambda: self.time) def advance_time(*unused_args): self.time += 10 inst._condition.wait(1).WithSideEffects(advance_time) self.mox.ReplayAll() self.assertFalse(inst.wait(1)) self.mox.VerifyAll()
def new_instance(self, instance_id, expect_ready_request=False): """Create and return a new Instance. Args: instance_id: A string or integer representing the unique (per module) id of the instance. expect_ready_request: If True then the instance will be sent a special request (i.e. /_ah/warmup or /_ah/start) before it can handle external requests. Returns: The newly created instance.Instance. """ def instance_config_getter(): runtime_config = self._runtime_config_getter() runtime_config.instance_id = str(instance_id) return runtime_config with self._application_lock: try: if self._go_application.maybe_build(self._modified_since_last_build): if self._last_build_error: logging.info('Go application successfully built.') self._last_build_error = None except go_application.BuildError as e: logging.error('Failed to build Go application: %s', e) # Deploy a failure proxy now and each time a new instance is requested. self._last_build_error = e self._modified_since_last_build = False if self._last_build_error: logging.debug('Deploying new instance of failure proxy.') proxy = _GoBuildFailureRuntimeProxy(self._last_build_error) else: proxy = http_runtime.HttpRuntimeProxy( self._go_application.go_executable, instance_config_getter, self._module_configuration, self._go_application.get_environment()) return instance.Instance(self.request_data, instance_id, proxy, self.max_concurrent_requests, self.max_background_threads, expect_ready_request)
def test_health(self): inst = instance.Instance(self.request_data, 'name', self.proxy, max_concurrent_requests=5) self.mox.StubOutWithMock(inst._condition, 'notify_all') self.proxy.start() self.proxy.quit() inst._condition.notify_all() self.mox.ReplayAll() inst.start() self.assertTrue(inst.can_accept_requests) inst.set_health(False) self.assertFalse(inst.can_accept_requests) inst.set_health(True) self.assertTrue(inst.can_accept_requests)
def new_instance(self, instance_id, expect_ready_request=False): """Create and return a new Instance. Args: instance_id: A string or integer representing the unique (per module) id of the instance. expect_ready_request: If True then the instance will be sent a special request (i.e. /_ah/warmup or /_ah/start) before it can handle external requests. Returns: The newly created instance.Instance. """ def instance_config_getter(): runtime_config = self._GenerateConfigForRuntime() runtime_config.instance_id = str(instance_id) return runtime_config php_executable_path = ( self._GenerateConfigForRuntime().php_config.php_executable_path) gae_extension_path = ( self._GenerateConfigForRuntime().php_config.gae_extension_path) if php_executable_path not in self._php_binary_to_error_proxy: try: self._check_binaries(php_executable_path, gae_extension_path) except Exception as e: self._php_binary_to_error_proxy[php_executable_path] = ( _BadPHPEnvironmentRuntimeProxy(php_executable_path, e)) logging.exception('The PHP runtime is not available') else: self._php_binary_to_error_proxy[php_executable_path] = None proxy = self._php_binary_to_error_proxy[php_executable_path] if proxy is None: proxy = http_runtime.HttpRuntimeProxy(_RUNTIME_ARGS, instance_config_getter, self._module_configuration) return instance.Instance(self.request_data, instance_id, proxy, self.max_concurrent_requests, self.max_background_threads, expect_ready_request)
def test_handle_while_quitting(self): inst = instance.Instance(self.request_data, 'name', self.proxy, max_concurrent_requests=5) self.mox.StubOutWithMock(inst._condition, 'notify') inst._num_outstanding_requests = 1 self.proxy.start() self.mox.ReplayAll() inst.start() inst.quit(allow_async=True) self.mox.VerifyAll() self.assertRaises(instance.CannotAcceptRequests, inst.handle, self.environ, self.start_response, self.url_map, self.match, self.request_id, instance.NORMAL_REQUEST)
def new_instance(self, instance_id, expect_ready_request=False): """Create and return a new Instance. Args: instance_id: A string or integer representing the unique (per module) id of the instance. expect_ready_request: If True then the instance will be sent a special request (i.e. /_ah/warmup or /_ah/start) before it can handle external requests. Returns: The newly created instance.Instance. """ def instance_config_getter(): runtime_config = self._runtime_config_getter() runtime_config.instance_id = str(instance_id) return runtime_config def extra_args_getter(port): return 'jetty.port=%s' % port env = self._java_application.get_environment() runtime_config = instance_config_getter() for env_entry in runtime_config.environ: env[env_entry.key] = env_entry.value if self._for_jetty9: start_process_flavor = http_runtime.START_PROCESS_REVERSE_NO_FILE env['APP_ENGINE_LOG_CONFIG_PATTERN'] = (os.path.join( tempfile.mkdtemp(suffix='gae'), 'log.%g')) else: start_process_flavor = http_runtime.START_PROCESS_FILE with self._application_lock: proxy = http_runtime.HttpRuntimeProxy( self._java_command, instance_config_getter, self._module_configuration, env=env, start_process_flavor=start_process_flavor, extra_args_getter=extra_args_getter) return instance.Instance(self.request_data, instance_id, proxy, self.max_concurrent_requests, self.max_background_threads, expect_ready_request)
def test__trim_request_history_to_60s(self): inst = instance.Instance(self.request_data, 'name', self.proxy, max_concurrent_requests=5) inst._request_history.append((0, 100)) inst._request_history.append((1.0, 101)) inst._request_history.append((1.2, 102)) inst._request_history.append((2.5, 103)) now = time.time() inst._request_history.append((now, 42)) inst._request_history.append((now + 1, 43)) inst._request_history.append((now + 3, 44)) inst._request_history.append((now + 4, 45)) inst._trim_request_history_to_60s() self.assertEqual([(now, 42), (now + 1, 43), (now + 3, 44), (now + 4, 45)], list(inst._request_history))