- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我的一项服务与速率受限的外部 API 进行通信,因此我想确保每 10 秒发送的调用不超过 1 个。
我的天真的方法是拥有一个长期运行的 API 服务,并在每次调用后超时:
def handle_cast({:call_api, data}, state) do
send_to_external_api(data)
:timer.sleep(10000)
{:noreply, state}
end
我不确定是否有正确的方法来做到这一点。
最佳答案
编辑:原始解决方案在 10 秒内丢弃消息,如 burmajam建议。编辑提供了更合适的解决方案。
编辑
由于 GenServer handle_* 函数实际上并不从队列接收消息,而只是处理它们,因此我们无法利用模式匹配来选择性地从进程队列中每 10 秒接收一次消息。
因此,由于我们按照消息到达的顺序来获取消息,因此我们需要内部队列作为 GenServer 状态的一部分。
defmodule RateLimited do
use GenServer
def start_link do
GenServer.start_link(__MODULE__, %{queue: []})
end
def init(state) do
allow_work()
{:ok, state}
end
def handle_cast({:call_api, data}, %{"queue" => queue} = state) do
{:noreply, %{state | queue: queue ++ [data]}}
end
def handle_info(:work, %{"queue" => [data | queue]} = state) do
send_to_external_api(data)
allow_work()
{:noreply, %{state | queue: queue}}
end
defp allow_work() do
Process.send_after(self(), :work, 10000) # after 10s
end
defp send_to_external_api (data) do end
end
因此,我们只是将消息从进程队列移动到状态队列,并在我们向自己发出 10 秒已经过去的信号时处理头部。
但最终,我们实际上获得了与让进程休眠 10 秒相同的结果。您的解决方案似乎更简单并达到相同的结果。
解决方案基于How to run some code every few hours in Phoenix framework?
首先,让您的 GenServer 在其状态中存储一个标志(work = true/false)。
然后让 GenServer 使用 Process.send_after
向自己发出信号,告诉自己何时可以工作。您在 handle_info
中收到信号,将 work
状态标志设置为 true
。
现在请注意 handle_cast
函数中状态的模式匹配:只有当 work
状态标志等于 true 时,它才会拾取消息。否则,消息将被放入队列中等待。
将消息发送到外部服务后,再次运行 Process.send_after
来安排下一个信号并返回将 work
标志设置为 的状态false
以防止立即拾取下一条消息。
defmodule RateLimited do
use GenServer
def start_link do
GenServer.start_link(__MODULE__, %{work: false})
end
def init(state) do
allow_work()
{:ok, state}
end
def handle_cast({:call_api, data}, %{"work" => true} = state) do
send_to_external_api(data)
allow_work()
{:noreply, %{state | work = false}}
end
def handle_info(:work, state) do
{:noreply, %{state | work = true}}
end
defp allow_work() do
Process.send_after(self(), :work, 10000) # after 10s
end
end
关于elixir - 如何制作一个以特定速率处理消息的 GenServer? (每n秒),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39625536/
我在自动启动监督树时遇到了死锁问题。一个 GenServer 的初始状态是树中另一个主管的子进程。代码如下: 主管和 worker : defmodule Parallel.Worker.Superv
考虑这样简单的 GenServer 模块: defmodule Crap do use GenServer ... #All the needed crap def handle_info
背景 我有一组测试需要先启动 GenServer。根据经验,我知道在每次测试后进行清理是一种很好的做法,因此我也想在每次测试后停止 GenServer。 问题 这里的问题是我不知道如何在测试完成后停止
在elixir GenServer中,有sync和async方法,handle_cast和handle_call。在异步情况下,如果该方法失败,我如何获得通知? 方法失败意味着在handle_call
我对一些 OTP 概念不熟悉。我有 GenServer,它将向 RabbitMQ 发布事件。此 GenServer 具有状态:amqp Chanel,它在 init() 期间启动一次,并在 cast
我缩小了问题的大小,因为它太大了。这是代码: defmodule MayRaiseGenServer do use GenServer def start_link do IO.put
我正在练习这个例子。 https://github.com/kwmiebach/how-to-elixir-supervisor 我按照说明进行操作并了解它是如何工作的,但我无法理解 Supervis
我的一项服务与速率受限的外部 API 进行通信,因此我想确保每 10 秒发送的调用不超过 1 个。 我的天真的方法是拥有一个长期运行的 API 服务,并在每次调用后超时: def handle_cas
我最近遇到了一点麻烦:GenServer 进程使用的内存非常高,可能是因为大量的二进制泄漏。 问题来自于这里:我们通过 GenServer 接收大型二进制文件,并将它们传递给消费者,然后消费者与该数据
我知道我可以像这样调用 GenServer GenServer.call(pid, request) # using a pid 或者像这样 GenServer.call(registered_nam
我的一项服务与速率受限的外部 API 进行通信,因此我想确保每 10 秒发送的调用不超过 1 个。 我的天真的方法是拥有一个长期运行的 API 服务,并在每次调用后超时: def handle_cas
假设我有 GenServer 实例: defmodule MyModule do use GenServer def init(_) do {:ok, %{}} end #... e
我有一个为单个项目实现功能的 GenServer,例如: def handle_call({:sync, id}, _from, state) do ## update data {:
给定一个简单的 GenServer过程。 defmodule KVServer do use GenServer def start do GenServer.start(__MODU
我正在编写一个模块来查询在线天气 API。我决定将它作为一个应用程序来实现,并带有一个受监督的 GenServer . 这是代码: defmodule Weather do use GenServ
场景: 我有一个简单的GenServer来管理某些状态。 目前,我正在使用 map 来管理我的状态。但它正在增长我正在向该状态添加更多数据。 问题: 那么,为了获得一些编译时保证,我的 GenServ
我正在阅读this关于如何从现有的phoenix应用程序中提取微服务的文章。作者重构了 phoenix 应用程序 Controller 之一,并将其方法之一移至 Genserver,之后将该 Ge
我有一个模拟应用程序范围的 Repo 的测试。大多数时候,测试都是绿色的。当我在循环中运行测试时,使用相同的种子,可能有 10% 的运行成功,但带有 GenServer 终止消息: 15:39:34.
我有一个 GenServer,它负责联系外部资源。调用外部资源的结果并不重要,偶尔失败是可以接受的,所以使用 handle_cast 似乎适用于代码的其他部分。我确实有一个用于该外部资源的类似接口(i
在这两种方法中,我都坚持如何通过给定的一组 id 或组映射进程,然后将存储的结构映射到过滤数据。%{group => [users]}执行。 我意识到组将与用户相反,因此我创建了一个使用组名称作为键的
我是一名优秀的程序员,十分优秀!