一般來說,在藥劑/二郎您有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」的例子 –