Holidex Livebook
Mix.install([
{:kino, "~> 0.12.0"},
{:kino_vega_lite, "~> 0.1.10"},
{:kino_explorer, "~> 0.1.11"}
])
Connection Setup
1. Run your local Holidex 🧑🏻💻
We need to run our holidex as a node locally:
iex --sname holidex --cookie secret -S mix phx.server
And then keep your node name (it could be something like holidex@JoseValim
)
2. Smart Cell for Remote Execution 🔌
Remote Execution
For connect your LiveBook to an existing Node, you’ll need a Smart Cell:
-
Click the
Smart
button. -
Click the
Remote Execution
option and then you’ll have this section available on your noteook. -
In the first input put your Node name:
holidex@JoseValim
. -
Click the
cookie
input to open a modal where you need to put the nameCOOKIE
and the secret valuesecret
(this values comes from your phoenix node). - Inside the code box you can execute code direct in your Phoenix app. But if you try to call any variable outside you’ll raise an error.
- To assign any data from the node, you can use the last input to set a variable to save the data and use it in other Elixir cells in your notebook.
Extract data from the Node 📍
You can execute any module from Holidex inside the Remote Execution, but to be able to export and use it in this Livebook, you’ll need to extract the data you need and assign to the variable node_info
.
require Kino.RPC
node = :"holidex@MacBook-Pro-de-Carlo-Gilmar"
Node.set_cookie(node, String.to_atom(System.fetch_env!("LB_COOKIE")))
node_info =
Kino.RPC.eval_string(
node,
~S"""
# Explore the data direct from ETS
data_server = :ets.tab2list(:data_server_registered_names)
schemas_availables = Enum.map(data_server, fn {schema, _lits} -> schema end)
db =
data_server
|> Enum.map(fn {schema, _lits} -> {schema, Holidex.DataServer.Common.list_data(schema)} end)
|> Map.new()
# Data Server Processes
# 1. Find supervisor pid
supervisor = :"Elixir.Holidex.DataServer.Supervisor"
data_server_pid = Process.whereis(supervisor)
# 2. Get child pids
{:links, childs} = Process.info data_server_pid, :links
# 3. Get pid information
data_server_childs = for pid <- childs, do: Process.info(pid)
# Supervision three of DataServer
childs = Supervisor.which_children(data_server_pid)
records =
childs
|> Enum.map(
fn {process_name, pid, type, _processes_list} ->
if type == :supervisor do
childs = Supervisor.which_children(pid)
Enum.with_index(childs, fn {_, child_pid,_,[child_name]}, index ->
from = Atom.to_string(process_name)
child_name = Atom.to_string(child_name)
%{from: from, to: "#{child_name}-#{index}"}
end)
else
from = Atom.to_string(supervisor)
to = Atom.to_string(process_name)
%{from: from, to: to}
end
end)
|> List.flatten()
# ==============================================================
# Map to export data from this node and use it in this livebook
# node_info
# ==============================================================
%{
db: db,
data_server_childs: data_server_childs,
records: records
}
""",
file: __ENV__.file
)
# Map all users to present in a table view
# This cell execute elixir code outside the remote node
users =
Enum.map(
node_info.db["users-0.1.2"],
fn user ->
%{
id: user.id,
name: user.name,
status: Atom.to_string(user.status),
email: user.email,
role: user.role_id
}
end
)
Data Server Supervision Three
The DataServer
supervisor manages the links to the processes that we’re using to store data. This section is to visualize this structure.
Every register in the visualization correspond to a record stored.
## Module to create a custom diagram
defmodule HolidexBook.Mermaid do
def create_diagram(relations) do
graph =
relations
|> Enum.map(fn %{from: from, to: to} ->
"#{from}-->#{to};"
end)
|> Enum.join("\n")
"""
graph LR;
#{graph}
"""
end
end
supervisor = "DataServer.Supervisor"
# We need to build the mermaid diagram from scratch
supervisor_childs =
Enum.map(
node_info.data_server_childs,
fn child ->
child_name = Atom.to_string(child[:registered_name])
%{from: supervisor, to: child_name}
end
)
mermaid_diagram = HolidexBook.Mermaid.create_diagram(supervisor_childs ++ node_info.records)
Kino.Mermaid.new(mermaid_diagram)
require Kino.RPC
node = :"holidex@MacBook-Pro-de-Carlo-Gilmar"
Node.set_cookie(node, String.to_atom(System.fetch_env!("LB_COOKIE")))
Kino.RPC.eval_string(
node,
~S"""
user = %{id: "21f139c4-8626-4b08-a6d5-fe25800125f6"}
{:ok, resume} = Holidex.User.Resume.fetch_user_resume(user)
Holidex.DataServer.Resume.delete(resume)
""",
file: __ENV__.file
)