我正在尝试找出在SQL数据库中创建新行后将文档插入/更新到elasticsearch (或者实际上是任何nosql数据库)中的最佳流程,以及在Elixir Phoenix中将逻辑放在哪里。
假设我的SQL表是posts
has_many comments
,并且我的elasticsearch结构有一个posts
索引,其中comments
是一个嵌套文档,这样我就可以同时搜索/检索帖子和评论内容。这意味着,如果用户创建或更新其评论消息,则elasticsearch中的相关post
文档也应更新。
最好的方法是什么?
发布于 2021-11-09 11:03:24
确切的实现可能取决于几件事:操作的速度有多快,用户需要知道结果吗?
如果这两个操作都相当快(即用户可以等待),那么您可以使用一个简单的with
语句来确保两个操作都成功完成,例如
with {:ok, _result1} <- update_postgres(data),
{:ok, _result2} <- update_elasticsearch(data) do
{:ok, "Everything updated!"}
end
如果你需要更多关于“绑定”2个操作的形式,那么Ecto transaction就可以完成这项工作。文档通常假设这两个操作都是数据库操作,或者它们使用相同的Repo
,但您可以在事务中执行任意任务,例如更新Elasticache:
def two_things(data) do
My.Repo.transaction fn ->
with {:ok, _result1} <- update_postgres(data),
{:ok, _result2} <- update_elasticache(data)
do
{:ok, "Everything updated!"}
else
{:error, e} ->
My.Repo.rollback(e)
{:error, "Something failed!"}
end
end
end
只有当您需要在失败时执行回滚时,使用事务才真正有意义。
这里的另一个选项假设操作可能足够慢,以至于您不想让用户等待它们完成。通常,至关重要的“主要”操作是更新数据库。有时,其他相关的更新(例如,在缓存层中)最好留给异步副作用。例如:
result = update_postgres(data)
Task.async(fn -> update_elasticache(data) end)
result
或者可能只在数据库操作成功时才触发副作用:
case update_postgres(data) do
{:ok, result} ->
Task.async(fn -> update_elasticache(data) end)
{:ok, result}
{:error, error} -> {:error, error}
end
或者更简洁的语法:
with {:ok, result} <- update_postgres(data) do
Task.async(fn -> update_elasticache(data) end)
{:ok, result}
end
有许多语法/帮助器可以实现这一点,但其思想是任何辅助操作都是非阻塞的,并且可以在将结果返回给用户后完成。
https://stackoverflow.com/questions/69892288
复制相似问题