对于一定比例的生产流量,我希望将重复收到的请求发送到我的应用程序的其他版本。这需要异步发生,因此我不会将服务时间增加一倍。
这样做的原因是我可以比较prod版本和生产候选版本生成的响应。如果他们的结果大致相似,我可以确信新版本没有破坏任何东西。 (如果我对应用程序进行了功能更改,我会从此比较中过滤出必要的响应部分。)
所以我正在寻找相当于:
class Foo(webapp2.RequestHandler):
def post(self):
handle = make_async_call_to('http://other_service_endpoint.com/', self.request)
# process the user's request in the usual way
test_response = handle.get_response()
# compare the locally-prepared response and the remote one, and log
# the diffs
# return the locally-prepared response to the caller
更新 google.appengine.api.urlfetch被建议作为我的问题的潜在解决方案,但它在dev_appserver中是同步的,尽管它的行为方式符合我的生产方式(请求不是&#39) ; t出去,直到调用get_response(),并阻止)。 :
start_time = time.time()
rpcs = []
print 'creating rpcs:'
for _ in xrange(3):
rpcs.append(urlfetch.create_rpc())
print time.time() - start_time
print 'making fetch calls:'
for rpc in rpcs:
urlfetch.make_fetch_call(rpc, 'http://httpbin.org/delay/3')
print time.time() - start_time
print 'getting results:'
for rpc in rpcs:
rpc.get_result()
print time.time() - start_time
creating rpcs:
9.51290130615e-05
0.000154972076416
0.000189065933228
making fetch calls:
0.00029993057251
0.000356912612915
0.000473976135254
getting results:
3.15417003632
6.31326603889
9.46627306938
UPDATE2
所以,在玩了一些其他选项之后,我找到了一种方法来完成非阻塞请求:
start_time = time.time()
rpcs = []
logging.info('creating rpcs:')
for i in xrange(10):
rpc = urlfetch.create_rpc(deadline=30.0)
url = 'http://httpbin.org/delay/{}'.format(i)
urlfetch.make_fetch_call(rpc, url)
rpc.callback = create_callback(rpc, url)
rpcs.append(rpc)
logging.info(time.time() - start_time)
logging.info('getting results:')
while rpcs:
rpc = apiproxy_stub_map.UserRPC.wait_any(rpcs)
rpcs.remove(rpc)
logging.info(time.time() - start_time)
...但需要注意的重点是 urllib中的异步提取选项都没有在dev_appserver中工作。发现这个后,我回去试试@ DanCornilescu的解决方案并发现它只能在生产中正常工作,但不能在dev_appserver中正常工作。
答案 0 :(得分:1)
URL Fetch服务支持异步请求。来自Issuing an asynchronous request:
HTTP(S)请求默认是同步的。发出异步 请求,您的申请必须:
- 使用urlfetch.create_rpc()创建新的RPC对象。此对象表示后续方法调用中的异步调用。
- 致电urlfetch.make_fetch_call()发出请求。此方法将您的RPC对象和请求目标的URL作为参数。
- 调用RPC对象的get_result()方法。如果请求成功,此方法返回结果对象,如果是,则引发异常 请求期间发生错误。
醇>以下代码段演示了如何进行基本的异步操作 来自Python应用程序的请求。首先,导入urlfetch库 来自App Engine SDK:
from google.appengine.api import urlfetch
接下来,使用urlfetch发出异步请求:
rpc = urlfetch.create_rpc() urlfetch.make_fetch_call(rpc, "http://www.google.com/") # ... do other things ... try: result = rpc.get_result() if result.status_code == 200: text = result.content self.response.write(text) else: self.response.status_code = result.status_code logging.error("Error making RPC request") except urlfetch.DownloadError: logging.error("Error fetching URL0")
注意:根据问题更新中提到的Sniggerfardimungus实验,异步调用可能无法在开发服务器上按预期工作 - 被序列化而不是并发,但是在GAE上部署时这样做。就个人而言,我还没有使用异步电话,所以我真的不能说。
如果意图不是阻止完全等待来自生产候选应用程序的响应,您可以在任务队列上推送原始请求和生产准备响应的副本,然后回答原始请求 - 具有可忽略的延迟(将任务排入队列)。
相应任务队列的处理程序将在原始请求的关键路径之外,使用原始请求的副本向登台应用程序发出请求(异步与否,并不重要)从影响生产应用程序的响应时间的角度来看,得到它的响应并将其与生产准备的响应进行比较,记录增量等。这可以很好地包装在一个单独的模块中,以便对生产应用程序并根据需要部署/删除。