From 87ab56b33d868c8247dcc37e6916229a2c13530f Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 3 Sep 2019 15:46:47 +0300 Subject: [PATCH] fetch address counters async In this PR (https://github.com/poanetwork/blockscout/pull/2636) we started fetching transactions and rewards in parallel using elixir tasks. This PR uses similar approach to fetch validation and transaction counters on address page. --- .../address_contract_controller.ex | 8 ++++-- .../controllers/address_controller.ex | 28 +++++++++++++++++++ .../address_read_contract_controller.ex | 8 ++++-- .../address_transaction_controller.ex | 8 ++++-- 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_contract_controller.ex index 5db900b12b..4ff45fe101 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/address_contract_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_contract_controller.ex @@ -1,7 +1,7 @@ defmodule BlockScoutWeb.AddressContractController do use BlockScoutWeb, :controller - import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1] + import BlockScoutWeb.AddressController, only: [transaction_and_validation_count: 1] alias Explorer.{Chain, Market} alias Explorer.ExchangeRates.Token @@ -20,14 +20,16 @@ defmodule BlockScoutWeb.AddressContractController do with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), {:ok, address} <- Chain.find_contract_address(address_hash, address_options, true) do + {transaction_count, validation_count} = transaction_and_validation_count(address_hash) + render( conn, "index.html", address: address, coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address), exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), - transaction_count: transaction_count(address_hash), - validation_count: validation_count(address_hash) + transaction_count: transaction_count, + validation_count: validation_count ) else :error -> diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_controller.ex index 9f955fa672..5916359281 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/address_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_controller.ex @@ -69,6 +69,34 @@ defmodule BlockScoutWeb.AddressController do redirect(conn, to: address_transaction_path(conn, :index, id)) end + def transaction_and_validation_count(%Hash{byte_count: unquote(Hash.Address.byte_count())} = address_hash) do + transaction_count_task = + Task.async(fn -> + transaction_count(address_hash) + end) + + validation_count_task = + Task.async(fn -> + validation_count(address_hash) + end) + + [transaction_count_task, validation_count_task] + |> Task.yield_many(:timer.seconds(30)) + |> Enum.map(fn {_task, res} -> + case res do + {:ok, result} -> + result + + {:exit, reason} -> + raise "Query fetching address counters terminated: #{inspect(reason)}" + + nil -> + raise "Query fetching address counters timed out." + end + end) + |> List.to_tuple() + end + def transaction_count(%Hash{byte_count: unquote(Hash.Address.byte_count())} = address_hash) do Chain.total_transactions_sent_by_address(address_hash) end diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_read_contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_read_contract_controller.ex index 0849689dce..2625dbd47f 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/address_read_contract_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_read_contract_controller.ex @@ -12,7 +12,7 @@ defmodule BlockScoutWeb.AddressReadContractController do alias Explorer.ExchangeRates.Token alias Indexer.Fetcher.CoinBalanceOnDemand - import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1] + import BlockScoutWeb.AddressController, only: [transaction_and_validation_count: 1] def index(conn, %{"address_id" => address_hash_string}) do address_options = [ @@ -27,14 +27,16 @@ defmodule BlockScoutWeb.AddressReadContractController do with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), {:ok, address} <- Chain.find_contract_address(address_hash, address_options, true) do + {transaction_count, validation_count} = transaction_and_validation_count(address_hash) + render( conn, "index.html", address: address, coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address), exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), - transaction_count: transaction_count(address_hash), - validation_count: validation_count(address_hash) + transaction_count: transaction_count, + validation_count: validation_count ) else :error -> diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex index f30c3cb0cd..9236c433a7 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex @@ -5,7 +5,7 @@ defmodule BlockScoutWeb.AddressTransactionController do use BlockScoutWeb, :controller - import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1] + import BlockScoutWeb.AddressController, only: [transaction_and_validation_count: 1] import BlockScoutWeb.Chain, only: [current_filter: 1, paging_options: 1, next_page_params: 3, split_list_by_page: 1] alias BlockScoutWeb.TransactionView @@ -96,6 +96,8 @@ defmodule BlockScoutWeb.AddressTransactionController do def index(conn, %{"address_id" => address_hash_string} = params) do with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), {:ok, address} <- Chain.hash_to_address(address_hash) do + {transaction_count, validation_count} = transaction_and_validation_count(address_hash) + render( conn, "index.html", @@ -103,8 +105,8 @@ defmodule BlockScoutWeb.AddressTransactionController do coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address), exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), filter: params["filter"], - transaction_count: transaction_count(address_hash), - validation_count: validation_count(address_hash), + transaction_count: transaction_count, + validation_count: validation_count, current_path: current_path(conn) ) else