SlideShare a Scribd company logo
GenServer in Action
 Elixir Club 11

Ternopil, 2018
Elixir Process
Process
iex(1)> spawn fn -> 1 + 1 end
#PID<0.90.0>
iex(2)> caller = self()
#PID<0.88.0>
iex(3)> spawn fn -> send caller, {:result, 1 + 1} end
#PID<0.93.0>
iex(4)> receive do
...(4)> {:result, result} -> result
...(4)> end
2
Process
iex(5)> spawn fn ->
...(5)> Process.sleep(6_000)
...(5)> send caller, {:result, 1 + 1}
...(5)> end
#PID<0.106.0>
iex(6)> receive do
...(6)> {:result, result} -> result
...(6)> end
⏳⏳⏳⏳⏳⌛
2
Process
iex(7)> spawn fn ->
...(7)> Process.sleep(666_666_666)
...(7)> send caller, {:result, 1 + 1}
...(7)> end
#PID<0.99.0>
iex(8)> spawn fn -> :nothing end
#PID<0.101.0>
iex(9)> spawn fn -> raise "error" end
#PID<0.103.0>
…
iex(11)> receive do
...(11)> {:result, result} -> result
...(11)> end
⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳
💤 💤 💤 CTRL+C
Process: timeout
iex(1)> caller = self()
#PID<0.88.0>
iex(2)> spawn fn ->
...(2)> Process.sleep(666_666_666)
...(2)> send caller, {:result, 1 + 1}
...(2)> end
#PID<0.94.0>
iex(3)> receive do
...(3)> {:result, result} -> {:ok, result}
...(3)> after
...(3)> 5_000 -> {:error, :timeout}
...(3)> end
⏳⏳⏳⏳⌛{:error, :timeout}
Process: message queue
iex(4)> send self(), {:message, 1}
iex(5)> send self(), {:another_message, 1}
iex(6)> send self(), {:message, 2}
iex(7)> send self(), {:another_message, 2}
iex(8)> send self(), {:message, 3}
iex(9)> send self(), {:another_message, 3}
iex(10)> Process.info(self(), :messages)
{:messages,
[
message: 1,
another_message: 1,
message: 2,
another_message: 2,
message: 3,
another_message: 3
]}
Process: message queue
{:messages,
[
message: 1,
another_message: 10,
message: 2,
another_message: 20,
message: 3,
another_message: 30
]}
iex(11)> receive do {:another_message, n} -> n end
10
iex(12)> receive do {:another_message, n} -> n end
20
iex(13)> Process.info(self(), :messages)
{:messages, [message: 1, message: 2, message: 3, another_message: 30]}
iex(14)> receive do {:message, n} -> n end
1
iex(15)> Process.info(self(), :messages)
{:messages, [message: 2, message: 3, another_message: 30]}
iex(16)> receive do {:something, n} -> n after 0 -> :no_matching_message end
:no_matching_message
When to use
processes?
Concurrent Tasks
Task.async / Task.await
ex(17)> task = Task.async(fn -> 1 + 1 end)
%Task{
owner: #PID<0.88.0>,
pid: #PID<0.106.0>,
ref: #Reference<0.1183799544.2034761732.30152>
}
iex(18)> Task.await(task)
2
Concurrent Tasks
Task.async / Task.await
iex(19)> tasks = Enum.map(1..10, &Task.async(fn ->
...(19)> Process.sleep(3_000)
...(19)> &1 * 100
...(19)> end))
[…]
iex(20)> Process.sleep(5_000)
:ok
iex(21)> Enum.map(tasks, &Task.await(&1))
[100, 200, 300, 400, 500, 600, 700, 800, 900, 1000]
Concurrent Tasks
Task.await timeout
await(task, timeout  5000)
…
A timeout, in milliseconds, can be given with default value
of 5000. If the timeout is exceeded, then the current
process will exit.
…
iex(22)> Task.async(fn -> Process.sleep(6_000) end) |> Task.await()
** (exit) exited in: Task.await(%Task{owner: #PID<0.88.0>, pid:
#PID<0.156.0>, ref: #Reference<0.891801449.431751175.151026>}, 5000)
** (EXIT) time out
(elixir) lib/task.ex:501: Task.await/2
Storing state
defmodule Storage do
def recursive(state) do
receive do
{:add, caller_pid, value} ->
new_state = state + value
send(caller_pid, {:result, new_state})
recursive(new_state)
end
end
end
iex(2)> storage_pid = spawn(fn -> Storage.recursive(0) end)
iex(3)> send(storage_pid, {:add, self(), 2})
iex(4)> send(storage_pid, {:add, self(), 2})
iex(5)> send(storage_pid, {:add, self(), 2})
iex(6)> flush()
{:result, 2}
{:result, 4}
{:result, 6}
Storing state
Agent
iex(7)> {:ok, pid} = Agent.start_link(fn -> 0 end)
{:ok, #PID<0.101.0>}
iex(8)> Agent.update(pid, fn state -> state + 1 end)
:ok
iex(9)> Agent.get(pid, fn state -> state end)
1
update(agent, fun, timeout  5000)
get(agent, module, fun, args, timeout  5000)
GenServer
GenServer
A behaviour module for implementing the server of a client-
server relation.

A GenServer is a process like any other Elixir process and it
can be used to keep state, execute code asynchronously
and so on. 
GenServer
defmodule Stack do
use GenServer
# Client
def start_link(default) do
GenServer.start_link(__MODULE__, default)
end
def push(pid, item) do
GenServer.cast(pid, {:push, item})
end
def pop(pid) do
GenServer.call(pid, :pop)
end
# Server (callbacks)
def handle_call(:pop, _from, [h | t]) do
{:reply, h, t}
end
def handle_cast({:push, item}, state) do
{:noreply, [item | state]}
end
end
GenServer
defmodule Stack do
use GenServer
# Client
def start_link(default) do
GenServer.start_link(__MODULE__, default)
end
def push(pid, item) do
GenServer.cast(pid, {:push, item})
end
def pop(pid) do
GenServer.call(pid, :pop)
end
# Server (callbacks)
def handle_call(:pop, _from, [h | t]) do
{:reply, h, t}
end
def handle_cast({:push, item}, state) do
{:noreply, [item | state]}
end
end
Executed in caller process
GenServer
defmodule Stack do
use GenServer
# Client
def start_link(default) do
GenServer.start_link(__MODULE__, default)
end
def push(pid, item) do
GenServer.cast(pid, {:push, item})
end
def pop(pid) do
GenServer.call(pid, :pop)
end
# Server (callbacks)
def handle_call(:pop, _from, [h | t]) do
{:reply, h, t}
end
def handle_cast({:push, item}, state) do
{:noreply, [item | state]}
end
end
Executed in server process
GenServer: timeout
call(server, request, timeout  5000)
def push(pid, item) do
GenServer.cast(pid, {:push, item})
end
def pop(pid) do
GenServer.call(pid, :pop)
end
# Server (callbacks)
@impl true
def handle_call(:pop, _from, [h | t]) do
Process.sleep(30_000)
{:reply, h, t}
end
@impl true
def handle_cast({:push, item}, state) do
{:noreply, [item | state]}
end
Executed in caller process
Executed in server process
GenServer: timeout
iex(2)> {:ok, pid} = Stack.start_link([])
{:ok, #PID<0.95.0>}
iex(3)> Enum.each(1..5, &Stack.push(pid, &1))
:ok
ex(4)> Stack.pop(pid)
** (exit) exited in: GenServer.call(#PID<0.95.0>, :pop, 5000)
** (EXIT) time out
(elixir) lib/gen_server.ex:836: GenServer.call/3
iex(4)> Stack.pop(pid)
** (exit) exited in: GenServer.call(#PID<0.95.0>, :pop, 5000)
** (EXIT) time out
(elixir) lib/gen_server.ex:836: GenServer.call/3
iex(4)> Stack.pop(pid)
** (exit) exited in: GenServer.call(#PID<0.95.0>, :pop, 5000)
** (EXIT) time out
(elixir) lib/gen_server.ex:836: GenServer.call/3
iex(4)> Stack.pop(pid)
** (exit) exited in: GenServer.call(#PID<0.95.0>, :pop, 5000)
** (EXIT) time out
(elixir) lib/gen_server.ex:836: GenServer.call/3
iex(4)> Process.info(pid, :messages)
{:messages,
[
{:"$gen_call", {#PID<0.88.0>, #Reference<0.3022523149.3093823489.83754>},
:pop},
{:"$gen_call", {#PID<0.88.0>, #Reference<0.3022523149.3093823489.83774>},
:pop},
{:"$gen_call", {#PID<0.88.0>, #Reference<0.3022523149.3093823489.83794>},
:pop}
]}
Executed in caller process
Executed in server process
GenServer: timeout
ex(5)> Process.info(pid, :messages)
{:messages,
[
{:"$gen_call", {#PID<0.88.0>,
#Reference<0.3022523149.3093823489.83794>},
:pop}
]}
ex(6)> Process.info(pid, :messages)
{:messages, []}
iex(7)> flush()
{#Reference<0.3022523149.3093823489.83730>, 5}
{#Reference<0.3022523149.3093823489.83754>, 4}
{#Reference<0.3022523149.3093823489.83774>, 3}
{#Reference<0.3022523149.3093823489.83794>, 2}
:ok
Digital Signature
Microservice
Digital Signature Microservice
• Microservice - part of the Ukrainian eHealth system
infrastructure

• Digital signature validation 

• Ukrainian standard DSTU 4145-2002

• Integration with proprietary C library via NIF
Digital Signature Microservice
Digital Signature
Microservice
NIF
Proprietary
DSTU
4145-2002
LIB
Digitally signed
content
< 5s
Decoded content
Signer info
Signature validation
Certificates
OSCP Server
{:ok, result} =
DigitalSignatureLib.processPKCS7Data(data, certs, true)
result ==
%{
content: "{"hello": "world"}",
is_valid: true,
signer: %{
common_name: "XXX YYY ZZZ",
country_name: "UA",
drfo: "1234567890",
edrpou: "",
given_name: "XX YY",
locality_name: "М. КИЇВ",
organization_name: "ФІЗИЧНА ОСОБА",
organizational_unit_name: "",
state_or_province_name: "",
surname: "XX",
title: ""
},
validation_error_message: ""
}
Sounds easy?
Digital Signature Microservice
DigitalSignatureLib.processPKCS7Data(…)
DigitalSignatureLib.processPKCS7Data(…)
DigitalSignatureLib.processPKCS7Data(…)
DigitalSignatureLib.processPKCS7Data(…)
Elixir Process
Elixir Process
Elixir Process
Elixir Process
Incoming Requests
200 OK
200 OK
200 OK
200 OK
Responses
Problem 1: concurrency
tasks =
Enum.map(1..25, fn _ ->
Task.async(fn ->
DigitalSignatureLib.processPKCS7Data(data, certs, true)
end)
end)
Enum.map(tasks, fn task ->
{:ok, result} = Task.await(task, 30000)
IO.inspect(result)
end)
%{
content: ***
}
%{
content: ***
}
%{
content: ***
}
%{
content: ***
}
*** Error in `/usr/local/lib/erlang/erts-9.3.3/bin/beam.smp': double free or corruption (fasttop): 0x00007f88e401d060 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x70bfb)[0x7f8962452bfb]
/lib/x86_64-linux-gnu/libc.so.6(+0x76fc6)[0x7f8962458fc6]
/lib/x86_64-linux-gnu/libc.so.6(+0x7780e)[0x7f896245980e]
/usr/local/lib/libUACryptoQ.so.1(_ZN9DataBlockaSERKS_+0x3c)[0x7f88a7bd785c]
/usr/local/lib/libUACryptoQ.so.1(_ZN4DataaSERKS_+0x11)[0x7f88a7bd6771]
/usr/local/lib/libUACryptoQ.so.1(_ZN7DataSet3NewERK4Data+0x3c)[0x7f88a7bd81cc]
/usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC16ObjectIdentifier10EncodeBodyEv+0x1fc)[0x7f88a7bf238c]
/usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC5Token6EncodeEv+0x46)[0x7f88a7bef236]
/usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11ObjectToken10EncodeBodyEv+0x17)[0x7f88a7bef3c7]
/usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC5Token6EncodeEv+0x46)[0x7f88a7bef236]
/usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11Constructed10EncodeBodyEv+0x45)[0x7f88a7be97d5]
/usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11Constructed6EncodeEv+0x39)[0x7f88a7bec089]
/usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11Constructed10EncodeBodyEv+0x45)[0x7f88a7be97d5]
/usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11Constructed6EncodeEv+0x39)[0x7f88a7bec089]
/usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC10CMSContent6EncodeEv+0x95)[0x7f88a7c0a2d5]
/usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11ObjectToken10EncodeBodyEv+0x3a)[0x7f88a7bef3ea]
/usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC5Token6EncodeEv+0x46)[0x7f88a7bef236]
/usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11Constructed10EncodeBodyEv+0x45)[0x7f88a7be97d5]
/usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11Constructed6EncodeEv+0x39)[0x7f88a7bec089]
/usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC10CMSContent6EncodeEv+0x95)[0x7f88a7c0a2d5]
/usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11ObjectToken10EncodeBodyEv+0x3a)[0x7f88a7bef3ea]
/usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC5Token6EncodeEv+0x46)[0x7f88a7bef236]
/usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11Constructed10EncodeBodyEv+0x45)[0x7f88a7be97d5]
/usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11Constructed6EncodeEv+0x39)[0x7f88a7bec089]
/usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC17ObjectWithContent6EncodeEv+0x1b)[0x7f88a7be946b]
/usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11ObjectToken10EncodeBodyEv+0x3a)[0x7f88a7bef3ea]
/usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC5Token6EncodeEv+0x46)[0x7f88a7bef236]
/usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11Constructed10EncodeBodyEv+0x45)[0x7f88a7be97d5]
/usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11Constructed6EncodeEv+0x39)[0x7f88a7bec089]
/usr/local/lib/libUACryptoQ.so.1(_ZN3UAC13CMSSignedData15VerifySignatureEPNS_11CertificateEP11_UAC_STREAM+0x9f5)[0x7f88a7c12965]
/usr/local/lib/libUACryptoQ.so.1(UAC_SignedDataVerify+0x2ba)[0x7f88a7c4ff1a]
/home/digital_signature.lib/_build/test/lib/digital_signature_lib/priv/digital_signature_lib_nif.so(Check+0x3c5)[0x7f891c0fc7f5]
/home/digital_signature.lib/_build/test/lib/digital_signature_lib/priv/digital_signature_lib_nif.so(+0x2bac)[0x7f891c0fbbac]
/usr/local/lib/erlang/erts-9.3.3/bin/beam.smp(erts_call_dirty_nif+0x19c)[0x5ce04c]
/usr/local/lib/erlang/erts-9.3.3/bin/beam.smp(erts_dirty_process_main+0x209)[0x445949]
/usr/local/lib/erlang/erts-9.3.3/bin/beam.smp[0x4f4a4d]
/usr/local/lib/erlang/erts-9.3.3/bin/beam.smp[0x675985]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x7494)[0x7f8962990494]
/lib/x86_64-linux-gnu/libc.so.6(clone+0x3f)[0x7f89624caacf]
======= Memory map: ========
00400000-0073b000 r-xp 00000000 08:01 2376229 /usr/local/lib/erlang/erts-9.3.3/bin/beam.smp
0093a000-0093b000 r--p 0033a000 08:01 2376229 /usr/local/lib/erlang/erts-9.3.3/bin/beam.smp
0093b000-00956000 rw-p 0033b000 08:01 2376229 /usr/local/lib/erlang/erts-9.3.3/bin/beam.smp
00956000-0097d000 rw-p 00000000 00:00 0
0231e000-02349000 rw-p 00000000 00:00 0 [heap]
Problem 1 solution: Gen Server
...
use GenServer
# Callbacks
...
def handle_call({:process_signed_content, signed_content, check}, _from,
{certs_cache_ttl, certs}) do
check = unless is_boolean(check), do: true
processing_result = do_process_signed_content(signed_content, certs, check,
SignedData.new())
{:reply, processing_result, {certs_cache_ttl, certs}}
end
...
# Client
...
def process_signed_content(signed_content, check) do
GenServer.call(__MODULE__, {:process_signed_content, signed_content, check})
end
Problem 1 solution: Gen Server
NifService (GenServer)
NifService.process_signed_content(…)
NifService.process_signed_content(…)
NifService.process_signed_content(…)
NifService.process_signed_content(…)
Requests
Message queue
DigitalSignatureLib.processPKCS7Data(…)
Responses
Problem 2: timeouts
NifService (GenServer)
Multiple concurrent
requests (processes)
2s
2s
2s
2s
Message queue
Sequential
responses
200 OK
2s
200 OK
4s
500 Error
5s
500 Error
5s
call(server, request, timeout  5000)
** (EXIT) time out
** (EXIT) time out
Problem 2: timeouts
NifService (GenServer)
Multiple concurrent
requests (processes)
2s
2s
Message queue
Sequential
responses
call(server, request, timeout  5000)
2s
2s
500 Error
5s
500 Error
5s
Problem 2 solution: architecture
DS
DS
DS
DS DS
DS
DS
DS
Load
Balancer
Reduce pressure on individual MS
Problem 2 solution: catch Exit
def process_signed_content(signed_content, check) do
gen_server_timeout =
Confex.fetch_env(:digital_signature_api,
:nif_service_timeout)
try do
GenServer.call(__MODULE__, {:process_signed_content,
signed_content, check}, gen_server_timeout)
catch
:exit, {:timeout, error} ->
{:error, {:nif_service_timeout, error}}
end
end
424 Failed Dependency
Problem 3: message queue
NifService (GenServer)
Processed requests
2s
2s
2s
2s
Message queue
Sequential
responses
200 OK
2s
200 OK
4s
424
5s
424
5s
2s
2s
Expired requests
New requests
Problem 3 solution: pass
message expiration time
...
# Callbacks
def handle_call({:process_signed_content, signed_content, check, message_exp_time}, _from, certs_cache_ttl, certs})
do
processing_result =
if NaiveDateTime.diff(message_exp_time, NaiveDateTime.utc_now(), :millisecond) > 250 do
check = unless is_boolean(check), do: true
do_process_signed_content(signed_content, certs, check, SignedData.new())
else
{:error, {:nif_service_timeout, "messaqe queue timeout"}}
end
{:reply, processing_result, {certs_cache_ttl, certs}}
End
...
# Client
def process_signed_content(signed_content, check) do
gen_server_timeout = Confex.fetch_env!(:digital_signature_api, :nif_service_timeout)
message_exp_time = NaiveDateTime.add(NaiveDateTime.utc_now(), gen_server_timeout, :millisecond)
try do
GenServer.call(__MODULE__, {:process_signed_content, signed_content, check, message_exp_time}, gen_server_timeout)
catch
:exit, {:timeout, error} ->
{:error, {:nif_service_timeout, error}}
end
end
...
Problem 3 solution: pass
message expiration time
NifService (GenServer)
…
Expired
Expired
Within threshold
Message queue
…
Problem 3 advanced solution:
QueueService
NifService
DigitalSignatureLib.
processPKCS7Data(…)
QueueService
:queue
Monitoring & Control
Memory management
Binary terms which are larger than 64 bytes are not stored in a process private
heap. 

They are called Refc Binary (Reference Counted Binary) and are stored in a
large Shared Heap which is accessible by all processes who have the pointer
of that Refc Binaries. 

That pointer is called ProcBin and is stored in a process private heap.

The GC for the shared heap is reference counting.

Collecting those Refc messages depends on collecting of all ProcBin objects
even ones that are inside the middleware process. 

Unfortunately because ProcBins are just a pointer hence they are so cheap
and it could take so long to happen a GC inside the middleware process.
NifService
Memory management
Shared Heap
Refc Binary
Refc Binary
Refc Binary
Requests Responses
ProcBin
ProcBin
ProcBin
ProcBin
ProcBin
ProcBin
ProcBin
ProcBin
ProcBin
GC
GC
GC
:erlang.garbage_collect(self())
Processes
Garbage Collect
...
# Callbacks
def init(certs_cache_ttl) do
certs = CertAPI.get_certs_map()
Process.send_after(self(), :refresh, certs_cache_ttl)
{:ok, {certs_cache_ttl, certs}}
end
...
def handle_info(:refresh, {certs_cache_ttl, _certs}) do
certs = CertAPI.get_certs_map()
# GC
:erlang.garbage_collect(self())
Process.send_after(self(), :refresh, certs_cache_ttl)
{:noreply, {certs_cache_ttl, certs}}
end
...
Garbage Collect
handle_call(request, from, state)
{:reply, reply, new_state, timeout() | :hibernate}
Hibernating a GenServer causes garbage collection and leaves
a continuous heap that minimises the memory used by the
process
Returning {:reply, reply, new_state, timeout} is similar to
{:reply, reply, new_state} except handle_info(:timeout,
new_state) will be called after timeout milliseconds if no
messages are received
Useful links
Saša Jurić "Elixir in Action, Second Edition”
https://www.manning.com/books/elixir-in-action-second-edition

Andrea Leopardi - Concurrent and Resilient Connections to Outside the
BEAM (ElixirConfEU 2016)
https://www.youtube.com/watch?time_continue=1884&v=U1Ry7STEFiY

GenServer call time-outs
https://cultivatehq.com/posts/genserver-call-timeouts/

Elixir Memory - Not Quite Free
https://stephenbussey.com/2018/05/09/elixir-memory-not-quite-free.html

Erlang Garbage Collection Details and Why It Matters
https://hamidreza-s.github.io/erlang%20garbage%20collection%20memory%20layout%20soft%20realtime/
2015/08/24/erlang-garbage-collection-details-and-why-it-matters.html
Thank You
Yurii Bodarev

https://github.com/ybod
Questions?

More Related Content

What's hot

The Ring programming language version 1.5.3 book - Part 19 of 194
The Ring programming language version 1.5.3 book - Part 19 of 194The Ring programming language version 1.5.3 book - Part 19 of 194
The Ring programming language version 1.5.3 book - Part 19 of 194
Mahmoud Samir Fayed
 
The Ring programming language version 1.6 book - Part 71 of 189
The Ring programming language version 1.6 book - Part 71 of 189The Ring programming language version 1.6 book - Part 71 of 189
The Ring programming language version 1.6 book - Part 71 of 189
Mahmoud Samir Fayed
 
The Ring programming language version 1.6 book - Part 55 of 189
The Ring programming language version 1.6 book - Part 55 of 189The Ring programming language version 1.6 book - Part 55 of 189
The Ring programming language version 1.6 book - Part 55 of 189
Mahmoud Samir Fayed
 
JavaScript ∩ WebAssembly
JavaScript ∩ WebAssemblyJavaScript ∩ WebAssembly
JavaScript ∩ WebAssembly
Tadeu Zagallo
 
The Ring programming language version 1.10 book - Part 89 of 212
The Ring programming language version 1.10 book - Part 89 of 212The Ring programming language version 1.10 book - Part 89 of 212
The Ring programming language version 1.10 book - Part 89 of 212
Mahmoud Samir Fayed
 
The Ring programming language version 1.8 book - Part 84 of 202
The Ring programming language version 1.8 book - Part 84 of 202The Ring programming language version 1.8 book - Part 84 of 202
The Ring programming language version 1.8 book - Part 84 of 202
Mahmoud Samir Fayed
 
Erlang/OTP in Riak
Erlang/OTP in RiakErlang/OTP in Riak
Erlang/OTP in Riak
Sargun Dhillon
 
The Ring programming language version 1.5.2 book - Part 26 of 181
The Ring programming language version 1.5.2 book - Part 26 of 181The Ring programming language version 1.5.2 book - Part 26 of 181
The Ring programming language version 1.5.2 book - Part 26 of 181
Mahmoud Samir Fayed
 
Rのスコープとフレームと環境と
Rのスコープとフレームと環境とRのスコープとフレームと環境と
Rのスコープとフレームと環境と
Takeshi Arabiki
 
Rデバッグあれこれ
RデバッグあれこれRデバッグあれこれ
Rデバッグあれこれ
Takeshi Arabiki
 
The Ring programming language version 1.4 book - Part 18 of 30
The Ring programming language version 1.4 book - Part 18 of 30The Ring programming language version 1.4 book - Part 18 of 30
The Ring programming language version 1.4 book - Part 18 of 30
Mahmoud Samir Fayed
 
QA Fest 2019. Saar Rachamim. Developing Tools, While Testing
QA Fest 2019. Saar Rachamim. Developing Tools, While TestingQA Fest 2019. Saar Rachamim. Developing Tools, While Testing
QA Fest 2019. Saar Rachamim. Developing Tools, While Testing
QAFest
 
The Ring programming language version 1.9 book - Part 48 of 210
The Ring programming language version 1.9 book - Part 48 of 210The Ring programming language version 1.9 book - Part 48 of 210
The Ring programming language version 1.9 book - Part 48 of 210
Mahmoud Samir Fayed
 
C++ practical
C++ practicalC++ practical
C++ practical
Rahul juneja
 
Dts x dicoding #2 memulai pemrograman kotlin
Dts x dicoding #2 memulai pemrograman kotlinDts x dicoding #2 memulai pemrograman kotlin
Dts x dicoding #2 memulai pemrograman kotlin
Ahmad Arif Faizin
 
The Ring programming language version 1.6 book - Part 15 of 189
The Ring programming language version 1.6 book - Part 15 of 189The Ring programming language version 1.6 book - Part 15 of 189
The Ring programming language version 1.6 book - Part 15 of 189
Mahmoud Samir Fayed
 
The Ring programming language version 1.2 book - Part 16 of 84
The Ring programming language version 1.2 book - Part 16 of 84The Ring programming language version 1.2 book - Part 16 of 84
The Ring programming language version 1.2 book - Part 16 of 84
Mahmoud Samir Fayed
 
The Ring programming language version 1.10 book - Part 94 of 212
The Ring programming language version 1.10 book - Part 94 of 212The Ring programming language version 1.10 book - Part 94 of 212
The Ring programming language version 1.10 book - Part 94 of 212
Mahmoud Samir Fayed
 
The Ring programming language version 1.5.3 book - Part 25 of 184
The Ring programming language version 1.5.3 book - Part 25 of 184The Ring programming language version 1.5.3 book - Part 25 of 184
The Ring programming language version 1.5.3 book - Part 25 of 184
Mahmoud Samir Fayed
 
The Ring programming language version 1.7 book - Part 16 of 196
The Ring programming language version 1.7 book - Part 16 of 196The Ring programming language version 1.7 book - Part 16 of 196
The Ring programming language version 1.7 book - Part 16 of 196
Mahmoud Samir Fayed
 

What's hot (20)

The Ring programming language version 1.5.3 book - Part 19 of 194
The Ring programming language version 1.5.3 book - Part 19 of 194The Ring programming language version 1.5.3 book - Part 19 of 194
The Ring programming language version 1.5.3 book - Part 19 of 194
 
The Ring programming language version 1.6 book - Part 71 of 189
The Ring programming language version 1.6 book - Part 71 of 189The Ring programming language version 1.6 book - Part 71 of 189
The Ring programming language version 1.6 book - Part 71 of 189
 
The Ring programming language version 1.6 book - Part 55 of 189
The Ring programming language version 1.6 book - Part 55 of 189The Ring programming language version 1.6 book - Part 55 of 189
The Ring programming language version 1.6 book - Part 55 of 189
 
JavaScript ∩ WebAssembly
JavaScript ∩ WebAssemblyJavaScript ∩ WebAssembly
JavaScript ∩ WebAssembly
 
The Ring programming language version 1.10 book - Part 89 of 212
The Ring programming language version 1.10 book - Part 89 of 212The Ring programming language version 1.10 book - Part 89 of 212
The Ring programming language version 1.10 book - Part 89 of 212
 
The Ring programming language version 1.8 book - Part 84 of 202
The Ring programming language version 1.8 book - Part 84 of 202The Ring programming language version 1.8 book - Part 84 of 202
The Ring programming language version 1.8 book - Part 84 of 202
 
Erlang/OTP in Riak
Erlang/OTP in RiakErlang/OTP in Riak
Erlang/OTP in Riak
 
The Ring programming language version 1.5.2 book - Part 26 of 181
The Ring programming language version 1.5.2 book - Part 26 of 181The Ring programming language version 1.5.2 book - Part 26 of 181
The Ring programming language version 1.5.2 book - Part 26 of 181
 
Rのスコープとフレームと環境と
Rのスコープとフレームと環境とRのスコープとフレームと環境と
Rのスコープとフレームと環境と
 
Rデバッグあれこれ
RデバッグあれこれRデバッグあれこれ
Rデバッグあれこれ
 
The Ring programming language version 1.4 book - Part 18 of 30
The Ring programming language version 1.4 book - Part 18 of 30The Ring programming language version 1.4 book - Part 18 of 30
The Ring programming language version 1.4 book - Part 18 of 30
 
QA Fest 2019. Saar Rachamim. Developing Tools, While Testing
QA Fest 2019. Saar Rachamim. Developing Tools, While TestingQA Fest 2019. Saar Rachamim. Developing Tools, While Testing
QA Fest 2019. Saar Rachamim. Developing Tools, While Testing
 
The Ring programming language version 1.9 book - Part 48 of 210
The Ring programming language version 1.9 book - Part 48 of 210The Ring programming language version 1.9 book - Part 48 of 210
The Ring programming language version 1.9 book - Part 48 of 210
 
C++ practical
C++ practicalC++ practical
C++ practical
 
Dts x dicoding #2 memulai pemrograman kotlin
Dts x dicoding #2 memulai pemrograman kotlinDts x dicoding #2 memulai pemrograman kotlin
Dts x dicoding #2 memulai pemrograman kotlin
 
The Ring programming language version 1.6 book - Part 15 of 189
The Ring programming language version 1.6 book - Part 15 of 189The Ring programming language version 1.6 book - Part 15 of 189
The Ring programming language version 1.6 book - Part 15 of 189
 
The Ring programming language version 1.2 book - Part 16 of 84
The Ring programming language version 1.2 book - Part 16 of 84The Ring programming language version 1.2 book - Part 16 of 84
The Ring programming language version 1.2 book - Part 16 of 84
 
The Ring programming language version 1.10 book - Part 94 of 212
The Ring programming language version 1.10 book - Part 94 of 212The Ring programming language version 1.10 book - Part 94 of 212
The Ring programming language version 1.10 book - Part 94 of 212
 
The Ring programming language version 1.5.3 book - Part 25 of 184
The Ring programming language version 1.5.3 book - Part 25 of 184The Ring programming language version 1.5.3 book - Part 25 of 184
The Ring programming language version 1.5.3 book - Part 25 of 184
 
The Ring programming language version 1.7 book - Part 16 of 196
The Ring programming language version 1.7 book - Part 16 of 196The Ring programming language version 1.7 book - Part 16 of 196
The Ring programming language version 1.7 book - Part 16 of 196
 

Similar to GenServer in action

Gevent rabbit rpc
Gevent rabbit rpcGevent rabbit rpc
Gevent rabbit rpc
Aleksandr Mokrov
 
Elixir -Tolerância a Falhas para Adultos - GDG Campinas
Elixir  -Tolerância a Falhas para Adultos - GDG CampinasElixir  -Tolerância a Falhas para Adultos - GDG Campinas
Elixir -Tolerância a Falhas para Adultos - GDG Campinas
Fabio Akita
 
Introducción a Elixir
Introducción a ElixirIntroducción a Elixir
Introducción a Elixir
Svet Ivantchev
 
Python profiling
Python profilingPython profiling
Python profiling
dreampuf
 
شرح مقرر البرمجة 2 لغة جافا - الوحدة الثالثة
شرح مقرر البرمجة 2   لغة جافا - الوحدة الثالثةشرح مقرر البرمجة 2   لغة جافا - الوحدة الثالثة
شرح مقرر البرمجة 2 لغة جافا - الوحدة الثالثة
جامعة القدس المفتوحة
 
Gevent be or not to be
Gevent be or not to beGevent be or not to be
Gevent be or not to be
Aleksandr Mokrov
 
«Gevent — быть или не быть?» Александр Мокров, Positive Technologies
«Gevent — быть или не быть?» Александр Мокров, Positive Technologies«Gevent — быть или не быть?» Александр Мокров, Positive Technologies
«Gevent — быть или не быть?» Александр Мокров, Positive Technologies
it-people
 
Django Celery
Django Celery Django Celery
Django Celery
Mat Clayton
 
A deep dive into PEP-3156 and the new asyncio module
A deep dive into PEP-3156 and the new asyncio moduleA deep dive into PEP-3156 and the new asyncio module
A deep dive into PEP-3156 and the new asyncio module
Saúl Ibarra Corretgé
 
Unix Programs
Unix ProgramsUnix Programs
Unix Programs
Griffinder VinHai
 
22-SE-77 OS_lab_labotary assignmnet#2.pdf
22-SE-77 OS_lab_labotary assignmnet#2.pdf22-SE-77 OS_lab_labotary assignmnet#2.pdf
22-SE-77 OS_lab_labotary assignmnet#2.pdf
EngTariq2
 
Part 3-functions1-120315220356-phpapp01
Part 3-functions1-120315220356-phpapp01Part 3-functions1-120315220356-phpapp01
Part 3-functions1-120315220356-phpapp01
Abdul Samee
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJS
Adam L Barrett
 
Promise: async programming hero
Promise: async programming heroPromise: async programming hero
Promise: async programming hero
The Software House
 
PythonOOP
PythonOOPPythonOOP
PythonOOP
Veera Pendyala
 
how to reuse code
how to reuse codehow to reuse code
how to reuse code
jleed1
 
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
GeeksLab Odessa
 
Can you fix the errors- It isn't working when I try to run import s.pdf
Can you fix the errors- It isn't working when I try to run    import s.pdfCan you fix the errors- It isn't working when I try to run    import s.pdf
Can you fix the errors- It isn't working when I try to run import s.pdf
aksachdevahosymills
 
FS2 for Fun and Profit
FS2 for Fun and ProfitFS2 for Fun and Profit
FS2 for Fun and Profit
Adil Akhter
 
JavaScript Advanced - Useful methods to power up your code
JavaScript Advanced - Useful methods to power up your codeJavaScript Advanced - Useful methods to power up your code
JavaScript Advanced - Useful methods to power up your code
Laurence Svekis ✔
 

Similar to GenServer in action (20)

Gevent rabbit rpc
Gevent rabbit rpcGevent rabbit rpc
Gevent rabbit rpc
 
Elixir -Tolerância a Falhas para Adultos - GDG Campinas
Elixir  -Tolerância a Falhas para Adultos - GDG CampinasElixir  -Tolerância a Falhas para Adultos - GDG Campinas
Elixir -Tolerância a Falhas para Adultos - GDG Campinas
 
Introducción a Elixir
Introducción a ElixirIntroducción a Elixir
Introducción a Elixir
 
Python profiling
Python profilingPython profiling
Python profiling
 
شرح مقرر البرمجة 2 لغة جافا - الوحدة الثالثة
شرح مقرر البرمجة 2   لغة جافا - الوحدة الثالثةشرح مقرر البرمجة 2   لغة جافا - الوحدة الثالثة
شرح مقرر البرمجة 2 لغة جافا - الوحدة الثالثة
 
Gevent be or not to be
Gevent be or not to beGevent be or not to be
Gevent be or not to be
 
«Gevent — быть или не быть?» Александр Мокров, Positive Technologies
«Gevent — быть или не быть?» Александр Мокров, Positive Technologies«Gevent — быть или не быть?» Александр Мокров, Positive Technologies
«Gevent — быть или не быть?» Александр Мокров, Positive Technologies
 
Django Celery
Django Celery Django Celery
Django Celery
 
A deep dive into PEP-3156 and the new asyncio module
A deep dive into PEP-3156 and the new asyncio moduleA deep dive into PEP-3156 and the new asyncio module
A deep dive into PEP-3156 and the new asyncio module
 
Unix Programs
Unix ProgramsUnix Programs
Unix Programs
 
22-SE-77 OS_lab_labotary assignmnet#2.pdf
22-SE-77 OS_lab_labotary assignmnet#2.pdf22-SE-77 OS_lab_labotary assignmnet#2.pdf
22-SE-77 OS_lab_labotary assignmnet#2.pdf
 
Part 3-functions1-120315220356-phpapp01
Part 3-functions1-120315220356-phpapp01Part 3-functions1-120315220356-phpapp01
Part 3-functions1-120315220356-phpapp01
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJS
 
Promise: async programming hero
Promise: async programming heroPromise: async programming hero
Promise: async programming hero
 
PythonOOP
PythonOOPPythonOOP
PythonOOP
 
how to reuse code
how to reuse codehow to reuse code
how to reuse code
 
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
 
Can you fix the errors- It isn't working when I try to run import s.pdf
Can you fix the errors- It isn't working when I try to run    import s.pdfCan you fix the errors- It isn't working when I try to run    import s.pdf
Can you fix the errors- It isn't working when I try to run import s.pdf
 
FS2 for Fun and Profit
FS2 for Fun and ProfitFS2 for Fun and Profit
FS2 for Fun and Profit
 
JavaScript Advanced - Useful methods to power up your code
JavaScript Advanced - Useful methods to power up your codeJavaScript Advanced - Useful methods to power up your code
JavaScript Advanced - Useful methods to power up your code
 

Recently uploaded

What is an RPA CoE? Session 1 – CoE Vision
What is an RPA CoE?  Session 1 – CoE VisionWhat is an RPA CoE?  Session 1 – CoE Vision
What is an RPA CoE? Session 1 – CoE Vision
DianaGray10
 
Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)
Jakub Marek
 
Crafting Excellence: A Comprehensive Guide to iOS Mobile App Development Serv...
Crafting Excellence: A Comprehensive Guide to iOS Mobile App Development Serv...Crafting Excellence: A Comprehensive Guide to iOS Mobile App Development Serv...
Crafting Excellence: A Comprehensive Guide to iOS Mobile App Development Serv...
Pitangent Analytics & Technology Solutions Pvt. Ltd
 
"Scaling RAG Applications to serve millions of users", Kevin Goedecke
"Scaling RAG Applications to serve millions of users",  Kevin Goedecke"Scaling RAG Applications to serve millions of users",  Kevin Goedecke
"Scaling RAG Applications to serve millions of users", Kevin Goedecke
Fwdays
 
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
Edge AI and Vision Alliance
 
A Deep Dive into ScyllaDB's Architecture
A Deep Dive into ScyllaDB's ArchitectureA Deep Dive into ScyllaDB's Architecture
A Deep Dive into ScyllaDB's Architecture
ScyllaDB
 
AppSec PNW: Android and iOS Application Security with MobSF
AppSec PNW: Android and iOS Application Security with MobSFAppSec PNW: Android and iOS Application Security with MobSF
AppSec PNW: Android and iOS Application Security with MobSF
Ajin Abraham
 
Northern Engraving | Modern Metal Trim, Nameplates and Appliance Panels
Northern Engraving | Modern Metal Trim, Nameplates and Appliance PanelsNorthern Engraving | Modern Metal Trim, Nameplates and Appliance Panels
Northern Engraving | Modern Metal Trim, Nameplates and Appliance Panels
Northern Engraving
 
Connector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectors
Connector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectorsConnector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectors
Connector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectors
DianaGray10
 
Skybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoptionSkybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoption
Tatiana Kojar
 
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
saastr
 
Fueling AI with Great Data with Airbyte Webinar
Fueling AI with Great Data with Airbyte WebinarFueling AI with Great Data with Airbyte Webinar
Fueling AI with Great Data with Airbyte Webinar
Zilliz
 
Mutation Testing for Task-Oriented Chatbots
Mutation Testing for Task-Oriented ChatbotsMutation Testing for Task-Oriented Chatbots
Mutation Testing for Task-Oriented Chatbots
Pablo Gómez Abajo
 
Choosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptxChoosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptx
Brandon Minnick, MBA
 
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge GraphGraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
Neo4j
 
"Frontline Battles with DDoS: Best practices and Lessons Learned", Igor Ivaniuk
"Frontline Battles with DDoS: Best practices and Lessons Learned",  Igor Ivaniuk"Frontline Battles with DDoS: Best practices and Lessons Learned",  Igor Ivaniuk
"Frontline Battles with DDoS: Best practices and Lessons Learned", Igor Ivaniuk
Fwdays
 
Monitoring and Managing Anomaly Detection on OpenShift.pdf
Monitoring and Managing Anomaly Detection on OpenShift.pdfMonitoring and Managing Anomaly Detection on OpenShift.pdf
Monitoring and Managing Anomaly Detection on OpenShift.pdf
Tosin Akinosho
 
Session 1 - Intro to Robotic Process Automation.pdf
Session 1 - Intro to Robotic Process Automation.pdfSession 1 - Intro to Robotic Process Automation.pdf
Session 1 - Intro to Robotic Process Automation.pdf
UiPathCommunity
 
[OReilly Superstream] Occupy the Space: A grassroots guide to engineering (an...
[OReilly Superstream] Occupy the Space: A grassroots guide to engineering (an...[OReilly Superstream] Occupy the Space: A grassroots guide to engineering (an...
[OReilly Superstream] Occupy the Space: A grassroots guide to engineering (an...
Jason Yip
 
High performance Serverless Java on AWS- GoTo Amsterdam 2024
High performance Serverless Java on AWS- GoTo Amsterdam 2024High performance Serverless Java on AWS- GoTo Amsterdam 2024
High performance Serverless Java on AWS- GoTo Amsterdam 2024
Vadym Kazulkin
 

Recently uploaded (20)

What is an RPA CoE? Session 1 – CoE Vision
What is an RPA CoE?  Session 1 – CoE VisionWhat is an RPA CoE?  Session 1 – CoE Vision
What is an RPA CoE? Session 1 – CoE Vision
 
Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)
 
Crafting Excellence: A Comprehensive Guide to iOS Mobile App Development Serv...
Crafting Excellence: A Comprehensive Guide to iOS Mobile App Development Serv...Crafting Excellence: A Comprehensive Guide to iOS Mobile App Development Serv...
Crafting Excellence: A Comprehensive Guide to iOS Mobile App Development Serv...
 
"Scaling RAG Applications to serve millions of users", Kevin Goedecke
"Scaling RAG Applications to serve millions of users",  Kevin Goedecke"Scaling RAG Applications to serve millions of users",  Kevin Goedecke
"Scaling RAG Applications to serve millions of users", Kevin Goedecke
 
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
“Temporal Event Neural Networks: A More Efficient Alternative to the Transfor...
 
A Deep Dive into ScyllaDB's Architecture
A Deep Dive into ScyllaDB's ArchitectureA Deep Dive into ScyllaDB's Architecture
A Deep Dive into ScyllaDB's Architecture
 
AppSec PNW: Android and iOS Application Security with MobSF
AppSec PNW: Android and iOS Application Security with MobSFAppSec PNW: Android and iOS Application Security with MobSF
AppSec PNW: Android and iOS Application Security with MobSF
 
Northern Engraving | Modern Metal Trim, Nameplates and Appliance Panels
Northern Engraving | Modern Metal Trim, Nameplates and Appliance PanelsNorthern Engraving | Modern Metal Trim, Nameplates and Appliance Panels
Northern Engraving | Modern Metal Trim, Nameplates and Appliance Panels
 
Connector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectors
Connector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectorsConnector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectors
Connector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectors
 
Skybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoptionSkybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoption
 
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
 
Fueling AI with Great Data with Airbyte Webinar
Fueling AI with Great Data with Airbyte WebinarFueling AI with Great Data with Airbyte Webinar
Fueling AI with Great Data with Airbyte Webinar
 
Mutation Testing for Task-Oriented Chatbots
Mutation Testing for Task-Oriented ChatbotsMutation Testing for Task-Oriented Chatbots
Mutation Testing for Task-Oriented Chatbots
 
Choosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptxChoosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptx
 
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge GraphGraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
 
"Frontline Battles with DDoS: Best practices and Lessons Learned", Igor Ivaniuk
"Frontline Battles with DDoS: Best practices and Lessons Learned",  Igor Ivaniuk"Frontline Battles with DDoS: Best practices and Lessons Learned",  Igor Ivaniuk
"Frontline Battles with DDoS: Best practices and Lessons Learned", Igor Ivaniuk
 
Monitoring and Managing Anomaly Detection on OpenShift.pdf
Monitoring and Managing Anomaly Detection on OpenShift.pdfMonitoring and Managing Anomaly Detection on OpenShift.pdf
Monitoring and Managing Anomaly Detection on OpenShift.pdf
 
Session 1 - Intro to Robotic Process Automation.pdf
Session 1 - Intro to Robotic Process Automation.pdfSession 1 - Intro to Robotic Process Automation.pdf
Session 1 - Intro to Robotic Process Automation.pdf
 
[OReilly Superstream] Occupy the Space: A grassroots guide to engineering (an...
[OReilly Superstream] Occupy the Space: A grassroots guide to engineering (an...[OReilly Superstream] Occupy the Space: A grassroots guide to engineering (an...
[OReilly Superstream] Occupy the Space: A grassroots guide to engineering (an...
 
High performance Serverless Java on AWS- GoTo Amsterdam 2024
High performance Serverless Java on AWS- GoTo Amsterdam 2024High performance Serverless Java on AWS- GoTo Amsterdam 2024
High performance Serverless Java on AWS- GoTo Amsterdam 2024
 

GenServer in action

  • 1. GenServer in Action  Elixir Club 11 Ternopil, 2018
  • 3. Process iex(1)> spawn fn -> 1 + 1 end #PID<0.90.0> iex(2)> caller = self() #PID<0.88.0> iex(3)> spawn fn -> send caller, {:result, 1 + 1} end #PID<0.93.0> iex(4)> receive do ...(4)> {:result, result} -> result ...(4)> end 2
  • 4. Process iex(5)> spawn fn -> ...(5)> Process.sleep(6_000) ...(5)> send caller, {:result, 1 + 1} ...(5)> end #PID<0.106.0> iex(6)> receive do ...(6)> {:result, result} -> result ...(6)> end ⏳⏳⏳⏳⏳⌛ 2
  • 5. Process iex(7)> spawn fn -> ...(7)> Process.sleep(666_666_666) ...(7)> send caller, {:result, 1 + 1} ...(7)> end #PID<0.99.0> iex(8)> spawn fn -> :nothing end #PID<0.101.0> iex(9)> spawn fn -> raise "error" end #PID<0.103.0> … iex(11)> receive do ...(11)> {:result, result} -> result ...(11)> end ⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳ 💤 💤 💤 CTRL+C
  • 6. Process: timeout iex(1)> caller = self() #PID<0.88.0> iex(2)> spawn fn -> ...(2)> Process.sleep(666_666_666) ...(2)> send caller, {:result, 1 + 1} ...(2)> end #PID<0.94.0> iex(3)> receive do ...(3)> {:result, result} -> {:ok, result} ...(3)> after ...(3)> 5_000 -> {:error, :timeout} ...(3)> end ⏳⏳⏳⏳⌛{:error, :timeout}
  • 7. Process: message queue iex(4)> send self(), {:message, 1} iex(5)> send self(), {:another_message, 1} iex(6)> send self(), {:message, 2} iex(7)> send self(), {:another_message, 2} iex(8)> send self(), {:message, 3} iex(9)> send self(), {:another_message, 3} iex(10)> Process.info(self(), :messages) {:messages, [ message: 1, another_message: 1, message: 2, another_message: 2, message: 3, another_message: 3 ]}
  • 8. Process: message queue {:messages, [ message: 1, another_message: 10, message: 2, another_message: 20, message: 3, another_message: 30 ]} iex(11)> receive do {:another_message, n} -> n end 10 iex(12)> receive do {:another_message, n} -> n end 20 iex(13)> Process.info(self(), :messages) {:messages, [message: 1, message: 2, message: 3, another_message: 30]} iex(14)> receive do {:message, n} -> n end 1 iex(15)> Process.info(self(), :messages) {:messages, [message: 2, message: 3, another_message: 30]} iex(16)> receive do {:something, n} -> n after 0 -> :no_matching_message end :no_matching_message
  • 10. Concurrent Tasks Task.async / Task.await ex(17)> task = Task.async(fn -> 1 + 1 end) %Task{ owner: #PID<0.88.0>, pid: #PID<0.106.0>, ref: #Reference<0.1183799544.2034761732.30152> } iex(18)> Task.await(task) 2
  • 11. Concurrent Tasks Task.async / Task.await iex(19)> tasks = Enum.map(1..10, &Task.async(fn -> ...(19)> Process.sleep(3_000) ...(19)> &1 * 100 ...(19)> end)) […] iex(20)> Process.sleep(5_000) :ok iex(21)> Enum.map(tasks, &Task.await(&1)) [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000]
  • 12. Concurrent Tasks Task.await timeout await(task, timeout 5000) … A timeout, in milliseconds, can be given with default value of 5000. If the timeout is exceeded, then the current process will exit. … iex(22)> Task.async(fn -> Process.sleep(6_000) end) |> Task.await() ** (exit) exited in: Task.await(%Task{owner: #PID<0.88.0>, pid: #PID<0.156.0>, ref: #Reference<0.891801449.431751175.151026>}, 5000) ** (EXIT) time out (elixir) lib/task.ex:501: Task.await/2
  • 13. Storing state defmodule Storage do def recursive(state) do receive do {:add, caller_pid, value} -> new_state = state + value send(caller_pid, {:result, new_state}) recursive(new_state) end end end iex(2)> storage_pid = spawn(fn -> Storage.recursive(0) end) iex(3)> send(storage_pid, {:add, self(), 2}) iex(4)> send(storage_pid, {:add, self(), 2}) iex(5)> send(storage_pid, {:add, self(), 2}) iex(6)> flush() {:result, 2} {:result, 4} {:result, 6}
  • 14. Storing state Agent iex(7)> {:ok, pid} = Agent.start_link(fn -> 0 end) {:ok, #PID<0.101.0>} iex(8)> Agent.update(pid, fn state -> state + 1 end) :ok iex(9)> Agent.get(pid, fn state -> state end) 1 update(agent, fun, timeout 5000) get(agent, module, fun, args, timeout 5000)
  • 16. GenServer A behaviour module for implementing the server of a client- server relation. A GenServer is a process like any other Elixir process and it can be used to keep state, execute code asynchronously and so on. 
  • 17. GenServer defmodule Stack do use GenServer # Client def start_link(default) do GenServer.start_link(__MODULE__, default) end def push(pid, item) do GenServer.cast(pid, {:push, item}) end def pop(pid) do GenServer.call(pid, :pop) end # Server (callbacks) def handle_call(:pop, _from, [h | t]) do {:reply, h, t} end def handle_cast({:push, item}, state) do {:noreply, [item | state]} end end
  • 18. GenServer defmodule Stack do use GenServer # Client def start_link(default) do GenServer.start_link(__MODULE__, default) end def push(pid, item) do GenServer.cast(pid, {:push, item}) end def pop(pid) do GenServer.call(pid, :pop) end # Server (callbacks) def handle_call(:pop, _from, [h | t]) do {:reply, h, t} end def handle_cast({:push, item}, state) do {:noreply, [item | state]} end end Executed in caller process
  • 19. GenServer defmodule Stack do use GenServer # Client def start_link(default) do GenServer.start_link(__MODULE__, default) end def push(pid, item) do GenServer.cast(pid, {:push, item}) end def pop(pid) do GenServer.call(pid, :pop) end # Server (callbacks) def handle_call(:pop, _from, [h | t]) do {:reply, h, t} end def handle_cast({:push, item}, state) do {:noreply, [item | state]} end end Executed in server process
  • 20. GenServer: timeout call(server, request, timeout 5000) def push(pid, item) do GenServer.cast(pid, {:push, item}) end def pop(pid) do GenServer.call(pid, :pop) end # Server (callbacks) @impl true def handle_call(:pop, _from, [h | t]) do Process.sleep(30_000) {:reply, h, t} end @impl true def handle_cast({:push, item}, state) do {:noreply, [item | state]} end Executed in caller process Executed in server process
  • 21. GenServer: timeout iex(2)> {:ok, pid} = Stack.start_link([]) {:ok, #PID<0.95.0>} iex(3)> Enum.each(1..5, &Stack.push(pid, &1)) :ok ex(4)> Stack.pop(pid) ** (exit) exited in: GenServer.call(#PID<0.95.0>, :pop, 5000) ** (EXIT) time out (elixir) lib/gen_server.ex:836: GenServer.call/3 iex(4)> Stack.pop(pid) ** (exit) exited in: GenServer.call(#PID<0.95.0>, :pop, 5000) ** (EXIT) time out (elixir) lib/gen_server.ex:836: GenServer.call/3 iex(4)> Stack.pop(pid) ** (exit) exited in: GenServer.call(#PID<0.95.0>, :pop, 5000) ** (EXIT) time out (elixir) lib/gen_server.ex:836: GenServer.call/3 iex(4)> Stack.pop(pid) ** (exit) exited in: GenServer.call(#PID<0.95.0>, :pop, 5000) ** (EXIT) time out (elixir) lib/gen_server.ex:836: GenServer.call/3 iex(4)> Process.info(pid, :messages) {:messages, [ {:"$gen_call", {#PID<0.88.0>, #Reference<0.3022523149.3093823489.83754>}, :pop}, {:"$gen_call", {#PID<0.88.0>, #Reference<0.3022523149.3093823489.83774>}, :pop}, {:"$gen_call", {#PID<0.88.0>, #Reference<0.3022523149.3093823489.83794>}, :pop} ]} Executed in caller process Executed in server process
  • 22. GenServer: timeout ex(5)> Process.info(pid, :messages) {:messages, [ {:"$gen_call", {#PID<0.88.0>, #Reference<0.3022523149.3093823489.83794>}, :pop} ]} ex(6)> Process.info(pid, :messages) {:messages, []} iex(7)> flush() {#Reference<0.3022523149.3093823489.83730>, 5} {#Reference<0.3022523149.3093823489.83754>, 4} {#Reference<0.3022523149.3093823489.83774>, 3} {#Reference<0.3022523149.3093823489.83794>, 2} :ok
  • 24. Digital Signature Microservice • Microservice - part of the Ukrainian eHealth system infrastructure • Digital signature validation • Ukrainian standard DSTU 4145-2002 • Integration with proprietary C library via NIF
  • 25. Digital Signature Microservice Digital Signature Microservice NIF Proprietary DSTU 4145-2002 LIB Digitally signed content < 5s Decoded content Signer info Signature validation Certificates OSCP Server
  • 26. {:ok, result} = DigitalSignatureLib.processPKCS7Data(data, certs, true) result == %{ content: "{"hello": "world"}", is_valid: true, signer: %{ common_name: "XXX YYY ZZZ", country_name: "UA", drfo: "1234567890", edrpou: "", given_name: "XX YY", locality_name: "М. КИЇВ", organization_name: "ФІЗИЧНА ОСОБА", organizational_unit_name: "", state_or_province_name: "", surname: "XX", title: "" }, validation_error_message: "" }
  • 27. Sounds easy? Digital Signature Microservice DigitalSignatureLib.processPKCS7Data(…) DigitalSignatureLib.processPKCS7Data(…) DigitalSignatureLib.processPKCS7Data(…) DigitalSignatureLib.processPKCS7Data(…) Elixir Process Elixir Process Elixir Process Elixir Process Incoming Requests 200 OK 200 OK 200 OK 200 OK Responses
  • 28.
  • 29. Problem 1: concurrency tasks = Enum.map(1..25, fn _ -> Task.async(fn -> DigitalSignatureLib.processPKCS7Data(data, certs, true) end) end) Enum.map(tasks, fn task -> {:ok, result} = Task.await(task, 30000) IO.inspect(result) end)
  • 30. %{ content: *** } %{ content: *** } %{ content: *** } %{ content: *** } *** Error in `/usr/local/lib/erlang/erts-9.3.3/bin/beam.smp': double free or corruption (fasttop): 0x00007f88e401d060 *** ======= Backtrace: ========= /lib/x86_64-linux-gnu/libc.so.6(+0x70bfb)[0x7f8962452bfb] /lib/x86_64-linux-gnu/libc.so.6(+0x76fc6)[0x7f8962458fc6] /lib/x86_64-linux-gnu/libc.so.6(+0x7780e)[0x7f896245980e] /usr/local/lib/libUACryptoQ.so.1(_ZN9DataBlockaSERKS_+0x3c)[0x7f88a7bd785c] /usr/local/lib/libUACryptoQ.so.1(_ZN4DataaSERKS_+0x11)[0x7f88a7bd6771] /usr/local/lib/libUACryptoQ.so.1(_ZN7DataSet3NewERK4Data+0x3c)[0x7f88a7bd81cc] /usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC16ObjectIdentifier10EncodeBodyEv+0x1fc)[0x7f88a7bf238c] /usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC5Token6EncodeEv+0x46)[0x7f88a7bef236] /usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11ObjectToken10EncodeBodyEv+0x17)[0x7f88a7bef3c7] /usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC5Token6EncodeEv+0x46)[0x7f88a7bef236] /usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11Constructed10EncodeBodyEv+0x45)[0x7f88a7be97d5] /usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11Constructed6EncodeEv+0x39)[0x7f88a7bec089] /usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11Constructed10EncodeBodyEv+0x45)[0x7f88a7be97d5] /usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11Constructed6EncodeEv+0x39)[0x7f88a7bec089] /usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC10CMSContent6EncodeEv+0x95)[0x7f88a7c0a2d5] /usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11ObjectToken10EncodeBodyEv+0x3a)[0x7f88a7bef3ea] /usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC5Token6EncodeEv+0x46)[0x7f88a7bef236] /usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11Constructed10EncodeBodyEv+0x45)[0x7f88a7be97d5] /usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11Constructed6EncodeEv+0x39)[0x7f88a7bec089] /usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC10CMSContent6EncodeEv+0x95)[0x7f88a7c0a2d5] /usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11ObjectToken10EncodeBodyEv+0x3a)[0x7f88a7bef3ea] /usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC5Token6EncodeEv+0x46)[0x7f88a7bef236] /usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11Constructed10EncodeBodyEv+0x45)[0x7f88a7be97d5] /usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11Constructed6EncodeEv+0x39)[0x7f88a7bec089] /usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC17ObjectWithContent6EncodeEv+0x1b)[0x7f88a7be946b] /usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11ObjectToken10EncodeBodyEv+0x3a)[0x7f88a7bef3ea] /usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC5Token6EncodeEv+0x46)[0x7f88a7bef236] /usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11Constructed10EncodeBodyEv+0x45)[0x7f88a7be97d5] /usr/local/lib/libUACryptoQ.so.1(_ZNK3UAC11Constructed6EncodeEv+0x39)[0x7f88a7bec089] /usr/local/lib/libUACryptoQ.so.1(_ZN3UAC13CMSSignedData15VerifySignatureEPNS_11CertificateEP11_UAC_STREAM+0x9f5)[0x7f88a7c12965] /usr/local/lib/libUACryptoQ.so.1(UAC_SignedDataVerify+0x2ba)[0x7f88a7c4ff1a] /home/digital_signature.lib/_build/test/lib/digital_signature_lib/priv/digital_signature_lib_nif.so(Check+0x3c5)[0x7f891c0fc7f5] /home/digital_signature.lib/_build/test/lib/digital_signature_lib/priv/digital_signature_lib_nif.so(+0x2bac)[0x7f891c0fbbac] /usr/local/lib/erlang/erts-9.3.3/bin/beam.smp(erts_call_dirty_nif+0x19c)[0x5ce04c] /usr/local/lib/erlang/erts-9.3.3/bin/beam.smp(erts_dirty_process_main+0x209)[0x445949] /usr/local/lib/erlang/erts-9.3.3/bin/beam.smp[0x4f4a4d] /usr/local/lib/erlang/erts-9.3.3/bin/beam.smp[0x675985] /lib/x86_64-linux-gnu/libpthread.so.0(+0x7494)[0x7f8962990494] /lib/x86_64-linux-gnu/libc.so.6(clone+0x3f)[0x7f89624caacf] ======= Memory map: ======== 00400000-0073b000 r-xp 00000000 08:01 2376229 /usr/local/lib/erlang/erts-9.3.3/bin/beam.smp 0093a000-0093b000 r--p 0033a000 08:01 2376229 /usr/local/lib/erlang/erts-9.3.3/bin/beam.smp 0093b000-00956000 rw-p 0033b000 08:01 2376229 /usr/local/lib/erlang/erts-9.3.3/bin/beam.smp 00956000-0097d000 rw-p 00000000 00:00 0 0231e000-02349000 rw-p 00000000 00:00 0 [heap]
  • 31. Problem 1 solution: Gen Server ... use GenServer # Callbacks ... def handle_call({:process_signed_content, signed_content, check}, _from, {certs_cache_ttl, certs}) do check = unless is_boolean(check), do: true processing_result = do_process_signed_content(signed_content, certs, check, SignedData.new()) {:reply, processing_result, {certs_cache_ttl, certs}} end ... # Client ... def process_signed_content(signed_content, check) do GenServer.call(__MODULE__, {:process_signed_content, signed_content, check}) end
  • 32. Problem 1 solution: Gen Server NifService (GenServer) NifService.process_signed_content(…) NifService.process_signed_content(…) NifService.process_signed_content(…) NifService.process_signed_content(…) Requests Message queue DigitalSignatureLib.processPKCS7Data(…) Responses
  • 33. Problem 2: timeouts NifService (GenServer) Multiple concurrent requests (processes) 2s 2s 2s 2s Message queue Sequential responses 200 OK 2s 200 OK 4s 500 Error 5s 500 Error 5s call(server, request, timeout 5000) ** (EXIT) time out ** (EXIT) time out
  • 34. Problem 2: timeouts NifService (GenServer) Multiple concurrent requests (processes) 2s 2s Message queue Sequential responses call(server, request, timeout 5000) 2s 2s 500 Error 5s 500 Error 5s
  • 35. Problem 2 solution: architecture DS DS DS DS DS DS DS DS Load Balancer Reduce pressure on individual MS
  • 36. Problem 2 solution: catch Exit def process_signed_content(signed_content, check) do gen_server_timeout = Confex.fetch_env(:digital_signature_api, :nif_service_timeout) try do GenServer.call(__MODULE__, {:process_signed_content, signed_content, check}, gen_server_timeout) catch :exit, {:timeout, error} -> {:error, {:nif_service_timeout, error}} end end 424 Failed Dependency
  • 37. Problem 3: message queue NifService (GenServer) Processed requests 2s 2s 2s 2s Message queue Sequential responses 200 OK 2s 200 OK 4s 424 5s 424 5s 2s 2s Expired requests New requests
  • 38. Problem 3 solution: pass message expiration time ... # Callbacks def handle_call({:process_signed_content, signed_content, check, message_exp_time}, _from, certs_cache_ttl, certs}) do processing_result = if NaiveDateTime.diff(message_exp_time, NaiveDateTime.utc_now(), :millisecond) > 250 do check = unless is_boolean(check), do: true do_process_signed_content(signed_content, certs, check, SignedData.new()) else {:error, {:nif_service_timeout, "messaqe queue timeout"}} end {:reply, processing_result, {certs_cache_ttl, certs}} End ... # Client def process_signed_content(signed_content, check) do gen_server_timeout = Confex.fetch_env!(:digital_signature_api, :nif_service_timeout) message_exp_time = NaiveDateTime.add(NaiveDateTime.utc_now(), gen_server_timeout, :millisecond) try do GenServer.call(__MODULE__, {:process_signed_content, signed_content, check, message_exp_time}, gen_server_timeout) catch :exit, {:timeout, error} -> {:error, {:nif_service_timeout, error}} end end ...
  • 39. Problem 3 solution: pass message expiration time NifService (GenServer) … Expired Expired Within threshold Message queue …
  • 40. Problem 3 advanced solution: QueueService NifService DigitalSignatureLib. processPKCS7Data(…) QueueService :queue Monitoring & Control
  • 41.
  • 42. Memory management Binary terms which are larger than 64 bytes are not stored in a process private heap. They are called Refc Binary (Reference Counted Binary) and are stored in a large Shared Heap which is accessible by all processes who have the pointer of that Refc Binaries. That pointer is called ProcBin and is stored in a process private heap. The GC for the shared heap is reference counting. Collecting those Refc messages depends on collecting of all ProcBin objects even ones that are inside the middleware process. Unfortunately because ProcBins are just a pointer hence they are so cheap and it could take so long to happen a GC inside the middleware process.
  • 43. NifService Memory management Shared Heap Refc Binary Refc Binary Refc Binary Requests Responses ProcBin ProcBin ProcBin ProcBin ProcBin ProcBin ProcBin ProcBin ProcBin GC GC GC :erlang.garbage_collect(self()) Processes
  • 44. Garbage Collect ... # Callbacks def init(certs_cache_ttl) do certs = CertAPI.get_certs_map() Process.send_after(self(), :refresh, certs_cache_ttl) {:ok, {certs_cache_ttl, certs}} end ... def handle_info(:refresh, {certs_cache_ttl, _certs}) do certs = CertAPI.get_certs_map() # GC :erlang.garbage_collect(self()) Process.send_after(self(), :refresh, certs_cache_ttl) {:noreply, {certs_cache_ttl, certs}} end ...
  • 45. Garbage Collect handle_call(request, from, state) {:reply, reply, new_state, timeout() | :hibernate} Hibernating a GenServer causes garbage collection and leaves a continuous heap that minimises the memory used by the process Returning {:reply, reply, new_state, timeout} is similar to {:reply, reply, new_state} except handle_info(:timeout, new_state) will be called after timeout milliseconds if no messages are received
  • 46. Useful links Saša Jurić "Elixir in Action, Second Edition” https://www.manning.com/books/elixir-in-action-second-edition Andrea Leopardi - Concurrent and Resilient Connections to Outside the BEAM (ElixirConfEU 2016) https://www.youtube.com/watch?time_continue=1884&v=U1Ry7STEFiY GenServer call time-outs https://cultivatehq.com/posts/genserver-call-timeouts/ Elixir Memory - Not Quite Free https://stephenbussey.com/2018/05/09/elixir-memory-not-quite-free.html Erlang Garbage Collection Details and Why It Matters https://hamidreza-s.github.io/erlang%20garbage%20collection%20memory%20layout%20soft%20realtime/ 2015/08/24/erlang-garbage-collection-details-and-why-it-matters.html