diff --git a/apps/indexer/lib/indexer/buffered_task.ex b/apps/indexer/lib/indexer/buffered_task.ex index f9193a445d0..732992d9097 100644 --- a/apps/indexer/lib/indexer/buffered_task.ex +++ b/apps/indexer/lib/indexer/buffered_task.ex @@ -1285,6 +1285,12 @@ defmodule Indexer.BufferedTask do if state.flush_interval == :infinity do state else + # Keep one flush timer per worker. Overwriting a live reference leaves + # the previous timer running and starts another repeating flush chain. + if is_reference(state.flush_timer) do + Process.cancel_timer(state.flush_timer) + end + timer = Process.send_after(self(), :flush, state.flush_interval) %__MODULE__{state | flush_timer: timer} end diff --git a/apps/indexer/lib/indexer/fetcher/stats/hot_smart_contracts.ex b/apps/indexer/lib/indexer/fetcher/stats/hot_smart_contracts.ex index 7a416e2db7c..8d57ebe1d8a 100644 --- a/apps/indexer/lib/indexer/fetcher/stats/hot_smart_contracts.ex +++ b/apps/indexer/lib/indexer/fetcher/stats/hot_smart_contracts.ex @@ -44,6 +44,17 @@ defmodule Indexer.Fetcher.Stats.HotSmartContracts do Logger.info("Hot contracts fetched for #{date}") else + {:error, {:error, :not_found}} -> + if Date.diff(Date.utc_today(), date) < @max_days_ago do + schedule_message_on_the_next_day({:fetch_for_date, date, false}) + end + + if new_day? do + schedule_next_day_fetch() + end + + Logger.info("No indexed blocks for hot contracts on #{date}") + {:error, error} -> Process.send_after(self(), {:fetch_for_date, date, new_day?}, @retry_interval) Logger.error("Error fetching hot contracts for #{date}: #{inspect(error)}") diff --git a/apps/indexer/test/indexer/buffered_task_test.exs b/apps/indexer/test/indexer/buffered_task_test.exs index 0124f04afdf..6f96085dcff 100644 --- a/apps/indexer/test/indexer/buffered_task_test.exs +++ b/apps/indexer/test/indexer/buffered_task_test.exs @@ -239,6 +239,7 @@ defmodule Indexer.BufferedTaskTest do test "with 0 size without maximum size schedules next flush and hibernates" do bound_queue = %BoundQueue{} + old_timer = Process.send_after(self(), :flush, :timer.minutes(5)) refute BoundQueue.shrunk?(bound_queue) @@ -249,15 +250,16 @@ defmodule Indexer.BufferedTaskTest do callback_module: ShrinkableTask, callback_module_state: nil, bound_queue: bound_queue, - flush_interval: 50, - flush_timer: nil, + flush_interval: :timer.minutes(5), + flush_timer: old_timer, task_supervisor: BufferedTaskSup, max_batch_size: 1, max_concurrency: 1, poll: false }) - refute flush_timer == nil + assert Process.read_timer(old_timer) == false + assert is_integer(Process.read_timer(flush_timer)) end test "with 0 size with maximum size calls init/2 to get work that was shed before scheduling next flush and hibernates" do diff --git a/apps/indexer/test/indexer/fetcher/stats/hot_smart_contracts_test.exs b/apps/indexer/test/indexer/fetcher/stats/hot_smart_contracts_test.exs index 2afecaa7337..0e1be2c4d6e 100644 --- a/apps/indexer/test/indexer/fetcher/stats/hot_smart_contracts_test.exs +++ b/apps/indexer/test/indexer/fetcher/stats/hot_smart_contracts_test.exs @@ -356,6 +356,19 @@ defmodule Indexer.Fetcher.Stats.HotSmartContractsTest do end end + test "logs an unavailable date without an error" do + insert(:block, number: 0, timestamp: DateTime.add(DateTime.utc_now(), -40, :day)) + date = Date.add(Date.utc_today(), -1) + + log = + capture_log([level: :info], fn -> + assert {:noreply, :ok} = HotSmartContracts.handle_info({:fetch_for_date, date, false}, :ok) + end) + + assert log =~ "No indexed blocks for hot contracts on #{date}" + refute log =~ "Error fetching hot contracts" + end + describe "handle_continue/2" do test "processes chain age check on startup" do # Create blocks older than 30 days