|
| 1 | +defmodule GoogleCrawler.FetchKeywordWorker do |
| 2 | + use GenServer |
| 3 | + |
| 4 | + alias GoogleCrawler.Search |
| 5 | + alias GoogleCrawler.Search.Keyword |
| 6 | + |
| 7 | + @max_retry_count 3 |
| 8 | + |
| 9 | + # Client |
| 10 | + |
| 11 | + def start_link(_args) do |
| 12 | + GenServer.start_link(__MODULE__, %{}, name: __MODULE__) |
| 13 | + end |
| 14 | + |
| 15 | + def fetch_and_scrap(keyword_id) do |
| 16 | + GenServer.call(__MODULE__, {:fetch_and_scrap, keyword_id}) |
| 17 | + end |
| 18 | + |
| 19 | + # Server Callbacks |
| 20 | + |
| 21 | + def init(state) do |
| 22 | + {:ok, state} |
| 23 | + end |
| 24 | + |
| 25 | + def handle_call({:fetch_and_scrap, keyword_id}, _from, state) do |
| 26 | + IO.puts "Handle call #{keyword_id}" |
| 27 | + |
| 28 | + keyword = Search.get_keyword(keyword_id) |
| 29 | + Search.update_keyword(keyword, %{status: :in_progress}) |
| 30 | + |
| 31 | + # start task and store the state of the task with the retry count |
| 32 | + # as a tuple of {keyword, retry_count} -> {%Keyword{}, 1} |
| 33 | + task = start_task(keyword) |
| 34 | + new_state = Map.put(state, task.ref, {keyword, 0}) |
| 35 | + |
| 36 | + {:reply, :ok, new_state} |
| 37 | + end |
| 38 | + |
| 39 | + def handle_info({ref, result}, state) do |
| 40 | + IO.puts "Handle info | success" |
| 41 | + |
| 42 | + {keyword, _retry_count} = Map.get(state, ref) |
| 43 | + Search.update_keyword(keyword, %{ |
| 44 | + status: :completed, |
| 45 | + raw_html_result: result.raw_html_result |
| 46 | + }) |
| 47 | + |
| 48 | + # Demonitor the task and remove from the state |
| 49 | + Process.demonitor(ref, [:flush]) |
| 50 | + new_state = Map.delete(state, ref) |
| 51 | + |
| 52 | + {:noreply, new_state} |
| 53 | + end |
| 54 | + |
| 55 | + def handle_info({:DOWN, ref, :process, _pid, _reason}, state) do |
| 56 | + IO.puts "Handle info | failed" |
| 57 | + |
| 58 | + {keyword, retry_count} = Map.get(state, ref) |
| 59 | + new_state = if retry_count < @max_retry_count do |
| 60 | + IO.puts "Retry... #{retry_count}" |
| 61 | + task = start_task(keyword) |
| 62 | + |
| 63 | + state |
| 64 | + |> Map.delete(ref) |
| 65 | + |> Map.put(task.ref, {keyword, retry_count + 1}) |
| 66 | + else |
| 67 | + IO.puts "Done with failed..." |
| 68 | + Search.update_keyword(keyword, %{status: :failed}) |
| 69 | + |
| 70 | + Map.delete(state, ref) |
| 71 | + end |
| 72 | + |
| 73 | + {:noreply, new_state} |
| 74 | + end |
| 75 | + |
| 76 | + defp start_task(%Keyword{} = keyword) do |
| 77 | + Task.Supervisor.async_nolink(GoogleCrawler.TaskSupervisor, fn -> |
| 78 | + GoogleCrawler.Search.SearchKeywordTask.perform(keyword) |
| 79 | + end) |
| 80 | + end |
| 81 | +end |
0 commit comments