Merge pull request #31 from poanetwork/ferigis.30.Keep_last_stats

[#30] sending last metrics when the dashboard connects to the backend
This commit is contained in:
Joseph Yiasemides 2018-07-19 12:05:11 +02:00 committed by GitHub
commit dd1b2060d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 132 additions and 7 deletions

View File

@ -23,6 +23,11 @@ defmodule POABackend.Receivers.Dashboard do
use POABackend.Receiver
# we store the last metrics in a ETS table because when a dashboard is connected it can wait a lot until
# the stats get updated
@last_metrics_table :last_metrics_table
alias __MODULE__
alias POABackend.Protocol.Message
@ -95,6 +100,8 @@ defmodule POABackend.Receivers.Dashboard do
def init_receiver(opts) do
:ok = start_websockets_server(opts)
:ok = set_up_last_metrics_table()
{:ok, %{clients: []}}
end
@ -105,6 +112,17 @@ defmodule POABackend.Receivers.Dashboard do
end
def handle_message({:add_client, client}, %{clients: clients} = state) do
# we send the latest metrics in order to catch up
stored_metrics = :ets.tab2list(@last_metrics_table)
for {_, metrics} <- stored_metrics do
metrics_list = Map.to_list(metrics)
for {_, metric} <- metrics_list do
send(client, metric)
end
end
{:ok, %{state | clients: [client | clients]}}
end
@ -163,6 +181,8 @@ defmodule POABackend.Receivers.Dashboard do
end
end
save_metrics(metrics)
:ok
end
@ -170,4 +190,49 @@ defmodule POABackend.Receivers.Dashboard do
dispatch_metric([metric], clients)
end
defp save_metrics(metrics) do
for metric <- metrics do
case metric.data["type"] do
"information" ->
save_last_information(metric)
"statistics" ->
save_last_stats(metric)
_ ->
:continue
end
end
:ok
end
defp save_last_information(%Message{} = metric) do
case :ets.lookup(@last_metrics_table, metric.agent_id) do
[] ->
:ets.insert(@last_metrics_table, {metric.agent_id, %{information: metric}})
[{_, last_metrics}] ->
last_metrics = Map.put(last_metrics, :information, metric)
:ets.insert(@last_metrics_table, {metric.agent_id, last_metrics})
end
:ok
end
defp save_last_stats(%Message{} = metric) do
case :ets.lookup(@last_metrics_table, metric.agent_id) do
[] ->
:ets.insert(@last_metrics_table, {metric.agent_id, %{stats: metric}})
[{_, last_metrics}] ->
last_metrics = Map.put(last_metrics, :stats, metric)
:ets.insert(@last_metrics_table, {metric.agent_id, last_metrics})
end
:ok
end
defp set_up_last_metrics_table do
:ets.new(@last_metrics_table, [:named_table])
:ok
end
end

View File

@ -8,8 +8,9 @@ defmodule Receivers.DashboardTest do
defmodule Client do
use WebSockex
def send(client, message) do
def send(client, message, caller) do
WebSockex.send_frame(client, {:text, message})
Kernel.send(caller, :message_sent)
end
def start_link(address, state, opts \\ []) do
@ -45,10 +46,32 @@ defmodule Receivers.DashboardTest do
assert_receive ^expected_message, 20_000
end
test "When the Dashboard connects already exists last metrics in the Backend" do
# we send the metrics twice in order to complete all the cases in the Receiver
# when the ets doesn't have the agentid and when it already exists
POABackend.Metric.add(:ethereum_metrics, [information_message(), stats_message(), information_message()])
POABackend.Metric.add(:ethereum_metrics, [information_message2(), stats_message2()])
Client.start_link("http://localhost:8181/ws", self(), [{:extra_headers, [{"wssecret", "mywssecret"}]}])
expected_information_message = expected_information_message()
expected_stats_message = expected_stats_message()
expected_information_message2 = expected_information_message2()
expected_stats_message2 = expected_stats_message2()
assert_receive ^expected_information_message, 20_000
assert_receive ^expected_stats_message, 20_000
assert_receive ^expected_information_message2, 20_000
assert_receive ^expected_stats_message2, 20_000
end
test "handle messages from the client to the server (test coverage)" do
{:ok, client} = Client.start_link("http://localhost:8181/ws", self(), [{:extra_headers, [{"wssecret", "mywssecret"}]}])
Client.send(client, "hello")
Client.send(client, "hello", self())
assert_receive :message_sent, 20_000
end
test "http call to the server (test coverage)" do
@ -65,4 +88,35 @@ defmodule Receivers.DashboardTest do
Message.new("agentid1", :ethereum_metric, :data, %{a: "a", b: "b", c: "c"})
end
defp information_message do
Message.new("agentid", :ethereum_metric, :data, %{"type" => "information"})
end
defp stats_message do
Message.new("agentid", :ethereum_metric, :data, %{"type" => "statistics"})
end
defp information_message2 do
Message.new("agentid2", :ethereum_metric, :data, %{"type" => "information"})
end
defp stats_message2 do
Message.new("agentid2", :ethereum_metric, :data, %{"type" => "statistics"})
end
defp expected_information_message do
"{\"data\":{\"type\":\"information\"},\"agent_id\":\"agentid\"}"
end
defp expected_stats_message do
"{\"data\":{\"type\":\"statistics\"},\"agent_id\":\"agentid\"}"
end
defp expected_information_message2 do
"{\"data\":{\"type\":\"information\"},\"agent_id\":\"agentid2\"}"
end
defp expected_stats_message2 do
"{\"data\":{\"type\":\"statistics\"},\"agent_id\":\"agentid2\"}"
end
end

View File

@ -1,6 +1,8 @@
defmodule Receivers.ReceiversTest do
use ExUnit.Case
alias POABackend.Protocol.Message
test "__using__ Receiver" do
defmodule Receiver1 do
use POABackend.Receiver
@ -64,15 +66,19 @@ defmodule Receivers.ReceiversTest do
{:ok, _} = Receiver2.start_link(state)
POABackend.Metric.add(:ethereum_metrics, [:message1, :message2])
POABackend.Metric.add(:ethereum_metrics, :message3)
message1 = Message.new("agentID", :ethereum_metric, :data, %{"data" => :nodata})
message2 = Message.new("agentID2", :ethereum_metric, :data, %{"data" => :nodata})
message3 = Message.new("agentID3", :ethereum_metric, :data, %{"data" => :nodata})
POABackend.Metric.add(:ethereum_metrics, [message1, message2])
POABackend.Metric.add(:ethereum_metrics, message3)
metrics_pid = Process.whereis(:ethereum_metrics)
send(metrics_pid, :nothing_happens)
assert_receive {:metric_received, :message1}, 20_000
assert_receive {:metric_received, :message2}, 20_000
assert_receive {:metric_received, :message3}, 20_000
assert_receive {:metric_received, ^message1}, 20_000
assert_receive {:metric_received, ^message2}, 20_000
assert_receive {:metric_received, ^message3}, 20_000
end
end