任务是通过服务到服务身份验证机制查询其中一项Google服务,该机制假定每60分钟获取一个新的访问令牌。因此,如果请求失败,需要主动刷新或刷新。
最新似乎是一种防御性技术,不符合Elixir哲学。更多信息无法确定请求是否因访问令牌过期而失败,或者因为提供的凭据(电子邮件和密钥)通常无效 - 它将是相同的文本和相同的401代码。
也许有人可以就实施策略提出建议?这将是主机应用程序使用的库,并假设在令牌刷新期间(可能是90ms?)将创建新的请求,一般来说,等待新令牌而不是很快使用它们将是有益的。过时了。
答案 0 :(得分:1)
通常,在Elixir / Erlang中,您有大约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