在 Phoenix 应用程序中提取微服务:Genserver
Extracting Microservices in Phoenix app : Genserver
我正在阅读 this 关于如何从现有的 phoenix 应用程序中提取微服务的文章。作者重构了其中一个 phoenix 应用程序控制器并将其方法之一移动到 Genserver 之后,他将该 Genserver 移动到一个单独的应用程序并将其添加到主项目中的依赖项。
但我在这里有点困惑,因为 GenServer 只允许您有两个服务器回调(分别是 handle call 和 handle cast)。但是,如果我希望将功能作为微服务移出,我们最终会创建与该服务中涉及的端点一样多的 Genserver,因为单个 genserver 将允许 one/two 方法调用。
genserver 是提取服务的理想方法吗?
我对你的问题有点困惑,但我认为你对 GenServers 的了解不正确。
2 个回调,handle_call
和 handle_cast
用于接收通过 GenServer.call
或 GenServer.cast
函数发送的消息。还有 handle_info
可以接收发送到 GenServer 进程的任何非 OTP 消息。
调用同步消息,同步消息将阻塞响应。我想这就是您想要的微服务。 (Cast 用于异步消息。)
单个 GenServer 实现可以接收通过 call
发送的任意数量的消息。
handle_call
callback 有 3 个参数。第一个是它正在处理的消息。通常,该消息是一个标记的元组,这意味着它的第一项标识它是哪种类型的消息。您可以处理多个不同的消息并使用模式匹配在您的 GenServer 中执行正确的功能子句,如下所示:
def handle_call({:message_one, foo}, _from, state)
# create some_response from foo or modify state here
{:reply, some_respone, state}
end
def handle_call({:message_two, bar}, _from, state)
# create some_response from bar or modify state here
{:reply, some_response, state}
end
def handle_call({:message_three, buzz}, _from, state)
# create some_response from buzz or modify state here
{:reply, some_response, state}
end
您的 GenServer 可以根据需要拥有任意数量的这些函数子句。您通常还会将这些消息标记原子保留为实现细节,并创建 public API 函数来包装对 GenServer.call
.
的调用
GenServer 有 3 个主要回调:handle_cast
、handle_call
和 handle_info
。这些函数中的每一个都可以有多个子句,每个子句实现一个特定的功能。
例如,假设我有一个作为 GenServer 实现的 UserService
模块,具有 5 个操作:create
、show
、index
、update
,以及 delete
。让我们进一步假设我将 delete
实现为异步操作(因此使用 handle_cast
),其余的实现为同步操作(使用 handle_call
)。
def handle_call({:create, user_data}, _from, state) do
new_user = User.create(user_data) // (However you create a user)
{:reply, new_user, state}
end
def handle_call(:index, _from, state) do
users = User.all
{:reply, users, state}
end
def handle_call({:update, user_changes}, _from, state) do
updated_user = User.update(user_changes)
{:reply, updated_user, state}
end
def handle_call({:show, user_id}, _from, state) do
user = User.get(user_id)
{:reply, user, state}
end
def handle_cast({:delete, user_id}, state) do
User.delete(user_id)
{:no_reply, state)
end
客户端模块可以调用 user = GenServer.call(pid, {:show, user_id})
来使用 show
子句。主要的收获是,即使只定义了几个 "functions",您可以根据需要定义该函数的任意多个子句,模式匹配将分派到正确的子句。
我正在阅读 this 关于如何从现有的 phoenix 应用程序中提取微服务的文章。作者重构了其中一个 phoenix 应用程序控制器并将其方法之一移动到 Genserver 之后,他将该 Genserver 移动到一个单独的应用程序并将其添加到主项目中的依赖项。
但我在这里有点困惑,因为 GenServer 只允许您有两个服务器回调(分别是 handle call 和 handle cast)。但是,如果我希望将功能作为微服务移出,我们最终会创建与该服务中涉及的端点一样多的 Genserver,因为单个 genserver 将允许 one/two 方法调用。 genserver 是提取服务的理想方法吗?
我对你的问题有点困惑,但我认为你对 GenServers 的了解不正确。
2 个回调,handle_call
和 handle_cast
用于接收通过 GenServer.call
或 GenServer.cast
函数发送的消息。还有 handle_info
可以接收发送到 GenServer 进程的任何非 OTP 消息。
调用同步消息,同步消息将阻塞响应。我想这就是您想要的微服务。 (Cast 用于异步消息。)
单个 GenServer 实现可以接收通过 call
发送的任意数量的消息。
handle_call
callback 有 3 个参数。第一个是它正在处理的消息。通常,该消息是一个标记的元组,这意味着它的第一项标识它是哪种类型的消息。您可以处理多个不同的消息并使用模式匹配在您的 GenServer 中执行正确的功能子句,如下所示:
def handle_call({:message_one, foo}, _from, state)
# create some_response from foo or modify state here
{:reply, some_respone, state}
end
def handle_call({:message_two, bar}, _from, state)
# create some_response from bar or modify state here
{:reply, some_response, state}
end
def handle_call({:message_three, buzz}, _from, state)
# create some_response from buzz or modify state here
{:reply, some_response, state}
end
您的 GenServer 可以根据需要拥有任意数量的这些函数子句。您通常还会将这些消息标记原子保留为实现细节,并创建 public API 函数来包装对 GenServer.call
.
GenServer 有 3 个主要回调:handle_cast
、handle_call
和 handle_info
。这些函数中的每一个都可以有多个子句,每个子句实现一个特定的功能。
例如,假设我有一个作为 GenServer 实现的 UserService
模块,具有 5 个操作:create
、show
、index
、update
,以及 delete
。让我们进一步假设我将 delete
实现为异步操作(因此使用 handle_cast
),其余的实现为同步操作(使用 handle_call
)。
def handle_call({:create, user_data}, _from, state) do
new_user = User.create(user_data) // (However you create a user)
{:reply, new_user, state}
end
def handle_call(:index, _from, state) do
users = User.all
{:reply, users, state}
end
def handle_call({:update, user_changes}, _from, state) do
updated_user = User.update(user_changes)
{:reply, updated_user, state}
end
def handle_call({:show, user_id}, _from, state) do
user = User.get(user_id)
{:reply, user, state}
end
def handle_cast({:delete, user_id}, state) do
User.delete(user_id)
{:no_reply, state)
end
客户端模块可以调用 user = GenServer.call(pid, {:show, user_id})
来使用 show
子句。主要的收获是,即使只定义了几个 "functions",您可以根据需要定义该函数的任意多个子句,模式匹配将分派到正确的子句。