fetch token counters in parallel

the slowest part of the token overview page is
fetching of total token transfers and total token
holders counters queries. Sometimes they even cause
page load failures.

Now we will start fetching these counters in parallel and
limiting query execution to 40 seconds. If they fail
to load, we won't show these counters.
pull/2666/head
Ayrat Badykov 5 years ago
parent cf6592d168
commit 36c1aa9b67
No known key found for this signature in database
GPG Key ID: B44668E265E9396F
  1. 8
      apps/block_scout_web/lib/block_scout_web/controllers/tokens/holder_controller.ex
  2. 7
      apps/block_scout_web/lib/block_scout_web/controllers/tokens/inventory_controller.ex
  3. 8
      apps/block_scout_web/lib/block_scout_web/controllers/tokens/read_contract_controller.ex
  4. 34
      apps/block_scout_web/lib/block_scout_web/controllers/tokens/token_controller.ex
  5. 7
      apps/block_scout_web/lib/block_scout_web/controllers/tokens/transfer_controller.ex
  6. 4
      apps/block_scout_web/lib/block_scout_web/templates/tokens/overview/_details.html.eex

@ -12,6 +12,8 @@ defmodule BlockScoutWeb.Tokens.HolderController do
next_page_params: 3
]
import BlockScoutWeb.Tokens.TokenController, only: [fetch_token_counters: 2]
def index(conn, %{"token_id" => address_hash_string, "type" => "JSON"} = params) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, token} <- Chain.token_from_address_hash(address_hash),
@ -47,13 +49,15 @@ defmodule BlockScoutWeb.Tokens.HolderController do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, token} <- Chain.token_from_address_hash(address_hash, options) do
{total_token_transfers, total_token_holders} = fetch_token_counters(token, address_hash)
render(
conn,
"index.html",
current_path: current_path(conn),
token: Market.add_price(token),
total_token_holders: token.holder_count || Chain.count_token_holders_from_token_hash(address_hash),
total_token_transfers: Chain.count_token_transfers_from_token_hash(address_hash)
total_token_holders: total_token_holders,
total_token_transfers: total_token_transfers
)
else
:error ->

@ -7,6 +7,7 @@ defmodule BlockScoutWeb.Tokens.InventoryController do
alias Phoenix.View
import BlockScoutWeb.Chain, only: [split_list_by_page: 1, default_paging_options: 0]
import BlockScoutWeb.Tokens.TokenController, only: [fetch_token_counters: 2]
def index(conn, %{"token_id" => address_hash_string, "type" => "JSON"} = params) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
@ -64,13 +65,15 @@ defmodule BlockScoutWeb.Tokens.InventoryController do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, token} <- Chain.token_from_address_hash(address_hash, options) do
{total_token_transfers, total_token_holders} = fetch_token_counters(token, address_hash)
render(
conn,
"index.html",
current_path: current_path(conn),
token: Market.add_price(token),
total_token_transfers: Chain.count_token_transfers_from_token_hash(address_hash),
total_token_holders: token.holder_count || Chain.count_token_holders_from_token_hash(address_hash)
total_token_transfers: total_token_transfers,
total_token_holders: total_token_holders
)
else
:error ->

@ -3,17 +3,21 @@ defmodule BlockScoutWeb.Tokens.ReadContractController do
alias Explorer.{Chain, Market}
import BlockScoutWeb.Tokens.TokenController, only: [fetch_token_counters: 2]
def index(conn, %{"token_id" => address_hash_string}) do
options = [necessity_by_association: %{[contract_address: :smart_contract] => :optional}]
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, token} <- Chain.token_from_address_hash(address_hash, options) do
{total_token_transfers, total_token_holders} = fetch_token_counters(token, address_hash)
render(
conn,
"index.html",
token: Market.add_price(token),
total_token_transfers: token.holder_count || Chain.count_token_transfers_from_token_hash(address_hash),
total_token_holders: Chain.count_token_holders_from_token_hash(address_hash)
total_token_transfers: total_token_transfers,
total_token_holders: total_token_holders
)
else
:error ->

@ -1,7 +1,41 @@
defmodule BlockScoutWeb.Tokens.TokenController do
use BlockScoutWeb, :controller
require Logger
alias Explorer.Chain
def show(conn, %{"id" => address_hash_string}) do
redirect(conn, to: token_transfer_path(conn, :index, address_hash_string))
end
def fetch_token_counters(token, address_hash) do
total_token_transfers_task =
Task.async(fn ->
Chain.count_token_transfers_from_token_hash(address_hash)
end)
total_token_holders_task =
Task.async(fn ->
token.holder_count || Chain.count_token_holders_from_token_hash(address_hash)
end)
[total_token_transfers_task, total_token_holders_task]
|> Task.yield_many(:timer.seconds(40))
|> Enum.map(fn {_task, res} ->
case res do
{:ok, result} ->
result
{:exit, reason} ->
Logger.warn("Query fetching token counters terminated: #{inspect(reason)}")
0
nil ->
Logger.warn("Query fetching token counters timed out.")
0
end
end)
|> List.to_tuple()
end
end

@ -6,6 +6,7 @@ defmodule BlockScoutWeb.Tokens.TransferController do
alias Phoenix.View
import BlockScoutWeb.Chain, only: [split_list_by_page: 1, paging_options: 1, next_page_params: 3]
import BlockScoutWeb.Tokens.TokenController, only: [fetch_token_counters: 2]
def index(conn, %{"token_id" => address_hash_string, "type" => "JSON"} = params) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
@ -48,13 +49,15 @@ defmodule BlockScoutWeb.Tokens.TransferController do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, token} <- Chain.token_from_address_hash(address_hash, options) do
{total_token_transfers, total_token_holders} = fetch_token_counters(token, address_hash)
render(
conn,
"index.html",
current_path: current_path(conn),
token: Market.add_price(token),
total_token_transfers: Chain.count_token_transfers_from_token_hash(address_hash),
total_token_holders: token.holder_count || Chain.count_token_holders_from_token_hash(address_hash)
total_token_transfers: total_token_transfers,
total_token_holders: total_token_holders
)
else
:error ->

@ -57,8 +57,12 @@
</span>
<div class="d-flex flex-row justify-content-start text-muted">
<span class="mr-4"> <%= @token.type %> </span>
<%= if @total_token_holders > 0 do %>
<span class="mr-4"><%= @total_token_holders %> <%= gettext "Addresses" %></span>
<% end %>
<%= if @total_token_transfers > 0 do %>
<span class="mr-4"><%= @total_token_transfers %> <%= gettext "Transfers" %></span>
<% end %>
<%= if decimals?(@token) do %>
<span class="mr-4"><%= @token.decimals %> <%= gettext "Decimals" %></span>
<% end %>

Loading…
Cancel
Save