我正在通过多个域提供的Google App Engine Python标准环境中使用Flask构建API。
API可用于存储数据和获取数据。
我想使用云数据存储的多租户来存储或获取仅由访问API的域确定的命名空间中的数据。
我能看到的唯一方法是使用google.appengine.api.namespace_manager
在请求时或在I / O时在上下文管理器中设置命名空间。
我写了这个上下文管理器:
@contextmanager
def multitenancy_namespace(namespace):
original_namespace = namespace_manager.get_namespace()
if namespace:
new_namespace = to_namespace_safe_url(namespace)
namespace_manager.set_namespace(new_namespace)
yield
namespace_manager.set_namespace(original_namespace)
它按预期工作。
我担心的是namespace_manager
的范围。我无法找到任何关于此的文档。
如果我的API被> 1000个用户同时线程化并使用,假设namespace_manager.set_namespace(...)
设置的命名空间是全局的,我会期待一些冲突 - 数据存储在错误的命名空间中,因为另一个请求叫{ {1}}在第一个请求之后,但在第一个请求执行其I / O之前。
我编写了一个传递的线程测试here,它告诉我set_namespace
的范围至少局限于单个线程(这对我的Flask应用程序来说已经足够了)。
但是 namespace
的上下文? namespace_manager
实际上做了什么?命名空间设置保存在哪里?是否存在名称空间冲突可能发生的用例?
答案 0 :(得分:1)
如果您查看count
的{{3}},您会看到它通过将命名空间设置为环境变量来实现:
namespace_manager.set_namespace(...)
当线程切换上下文时,AppEngine备份&根据需要恢复环境变量。保证它们受到请求限制,因此对用户的代码不透明。我不记得是否有这方面的文档,我想我已经在某个论坛帖子中学到了这一点。
评论def set_namespace(namespace):
"""Set the default namespace for the current HTTP request.
Args:
namespace: A string naming the new namespace to use. A value of None
will unset the default namespace value.
"""
if namespace is None:
os.environ.pop(_ENV_CURRENT_NAMESPACE, None)
else:
validate_namespace(namespace)
os.environ[_ENV_CURRENT_NAMESPACE] = namespace
隐含地证实了这一点。
我们在source code使用了几年,这从来都不是问题。
如此放松,您可以安全地在多线程环境中使用它!