Skip to content

Instantly share code, notes, and snippets.

@dgoldie
Last active August 29, 2015 14:05
Show Gist options
  • Save dgoldie/6c1f0db6060536e534e5 to your computer and use it in GitHub Desktop.
Save dgoldie/6c1f0db6060536e534e5 to your computer and use it in GitHub Desktop.
rate limit resource problem
defmodule Connection.Yahoo.ConsumerAgent do
require Logger
@name {:global, YahooConsumerAgent }
def name do
@name
end
@doc """
Starts a new consumer key agent.
"""
def start_link(opts) do
Agent.start_link(fn ->
last = Connection.Yahoo.Consumer.total_keys - 1
dict = HashDict.new |> Dict.put( :current, 0)
key_range = 0..last
Enum.reduce(key_range, dict, fn x,dict -> Dict.put(dict, x, 0) end)
end,
opts)
end
@doc """
Gets the current consumer key from the agent`.
And updates the count of tries for that key.
"""
def get do
Agent.get_and_update(@name, fn dict ->
current = HashDict.get(dict, :current)
dict = Dict.update!(dict, current, fn x -> x + 1 end)
{current, dict}
end)
end
@doc """
Switch to next consumer key after rejection.
"""
def get_after_rejection do
Agent.get_and_update(@name, fn dict ->
new_value = switch_consumer_keys(dict)
IO.inspect new_value
{ new_value, HashDict.put(dict, :current, new_value) }
end)
end
@doc """
Get the count of tries for the current consumer key.
"""
def get_current_count do
Agent.get(@name, fn dict ->
current = HashDict.get(dict, :current)
HashDict.get(dict, current)
end)
end
@doc """
Puts the `value` for the given `key` in the dictionary in `agent`.
"""
def put(key, value) do
Agent.update(@name, &HashDict.put(&1, key, value))
end
defp switch_consumer_keys(dict) do
old_index = HashDict.get(dict, :current)
count = HashDict.get(dict, old_index)
Logger.info "Consumer Key ##{old_index}: is switched at count #{count}"
new_index = old_index |> Connection.Yahoo.Consumer.next_key_id
HashDict.put(dict, new_index, 0)
new_index
end
# def init(num) do
# for n <- 1..num, into: HashDict.new do
# {n, 0}
# end
# end
end
defmodule Connection.Yahoo.ConsumerAgentTest do
use ExUnit.Case, async: true
alias Connection.Yahoo.ConsumerAgent
setup do
# Logger.start
{:ok, agent} = ConsumerAgent.start_link name: ConsumerAgent.name
{:ok, agent: agent}
end
test "get current consumer key" do
assert ConsumerAgent.get == 0
end
test "switches current consumer key from 0 to 1" do
assert ConsumerAgent.get_after_rejection == 1
end
test "switches from last consumer key to first" do
first_key = 0
last_key = Connection.Yahoo.Consumer.last_key
ConsumerAgent.put(:current, last_key)
assert ConsumerAgent.get == last_key
assert ConsumerAgent.get_after_rejection == first_key
end
test "counting keys used" do
for _n <- 1..6, do: ConsumerAgent.get
assert ConsumerAgent.get_current_count == 6
end
end
defmodule Connection.Yahoo.ConsumerSupervisor do
use Supervisor
def start_link do
Supervisor.start_link(__MODULE__, :ok)
end
@agent_name YahooConsumerAgent
def init(:ok) do
children = [
worker(Connection.Yahoo.ConsumerAgent, [[name: {:global, @agent_name}]])
]
supervise(children, strategy: :one_for_one)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment