一般来说,在药剂/二郎您有4种方式来存储和使用共享数据:
GenServer或类似的 - 你实现的过程,把握关键,也查询API。您向它发送消息并返回数据。你不会打扰数据来自哪里,使用哪些键以及如何使用。请求被序列化(并行完成的而不是),这可能是你不想要的东西。
代理 - 仅保存数据(密钥)。您可以调用Agent.get/3并获取密钥。无论何时您发现密钥已过期,都可以调用Agent.update/3将新密钥添加到代理中。或者你总是调用update/3。
ETS表 - 最后的手段。如果你没有足够的理由,不要使用它。
任何外部来源 - 你可以从磁盘,网络等读取甚至最后呃;)度假村。
对于您的用例,第一种和第二种解决方案可能几乎相同。但我会因为平顺化而使用第二个。你可以写类似:
defmodule TokenHolder do
def start_link(user,passwd) do
Agent.start_link(fn ->
tok_time = get_token user, passwd
{user,passwd,tok_time}
end, name: __MODULE__)
end
# refresh the token if older that one hour
@max_age 60*60*1000000
def token do
Agent.get_and_update(__MODULE__, fn state={user,passwd,{token,retrieved}} ->
now = :os.timestamp
if(:timer.now_diff(now, retrieved) < @max_age) do
# return old token and old state
{token,state}
else
# retrieve new token, return it and return changed state
tok_time = {token,_} = get_token user, passwd
{token,{user,passwd,tok_time}}
end
end)
end
defp get_token(user,passwd) do
token = ... # retrieve token somehow...
{token,:os.timestamp}
end
end
然后你只需要做:
{:ok,_} = TokenHolder.start_link("user","secret")
token = TokenHolder.token
米罗斯拉夫,你能否详细说明有关要求的系列化一点点? – lessless
GenServer等待请求并回答它们。一个接一个,在一个过程中。请参阅http://www.erlang.org/doc/man/gen_server.html#call-2 如果您希望并行回答您的请求,则必须使用特殊技术,例如为服务器提供PID,在其中产生新进程服务器,并等待“接收”的答案。但是这样你就不能在请求结束时改变服务器状态。 如果您使用上面给出的代码,您只需在序列化代码中获取令牌,然后在您的过程中提出请求 - 即并行。 –
您可以在这里看到示例代码:https://gist.github.com/mprymek/0a8f175d6c9201a81c62 尝试将一些“:timer.sleep”放入“TokenHolder.token”中 - 您将看到KeyHolder中的操作被序列化。但对MyAPI.users的调用是并行完成的。 P.S.你可以运行“iex api_test.exs”的例子 –