Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
gen_statem - OTP's Unsung Hero
Search
Andrea Leopardi
April 04, 2025
Programming
2
220
gen_statem - OTP's Unsung Hero
Given at AlchemyConf 2025 in Braga, Portugal.
Andrea Leopardi
April 04, 2025
Tweet
Share
More Decks by Andrea Leopardi
See All by Andrea Leopardi
The World is a Network (and We Are Just Nodes)
whatyouhide
1
210
BEAM: The Perfect Fit for Networks
whatyouhide
1
190
Update from the Elixir team - 2022
whatyouhide
0
400
Testing Asynchronous OTP
whatyouhide
1
510
Elixir Sightseeing Tour
whatyouhide
0
420
Mint - Disrupting HTTP clients
whatyouhide
0
240
BEAM Architecture Handbook
whatyouhide
7
2.8k
The Evolution of a Language
whatyouhide
0
150
Elixir - functional, concurrent, distributed programming for the rest of us
whatyouhide
2
320
Other Decks in Programming
See All in Programming
今話題のMCPサーバーをFastAPIでサッと作ってみた
yuukis
0
130
KANNA Android の技術的課題と取り組み
watabee
1
510
M5UnitUnified 最新動向 2025/05
gob
0
140
エンジニアが挑む、限界までの越境
nealle
1
330
UMAPをざっくりと理解 / Overview of UMAP
kaityo256
PRO
3
1.5k
私のRubyKaigi 2025 Kaigi Effect / My RubyKaigi 2025 Kaigi Effect
chobishiba
1
120
The Missing Link in Angular’s Signal Story: Resource API and httpResource
manfredsteyer
PRO
0
150
KawaiiLT 登壇資料 キャリアとモチベーション
hiiragi
0
160
ComposeでのPicture in Picture
takathemax
0
140
Instrumentsを使用した アプリのパフォーマンス向上方法
hinakko
0
250
はじめてのPDFKit.pdf
shomakato
0
100
20250426 GDGoC 合同新歓 - GDGoC のススメ
getty708
0
110
Featured
See All Featured
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
53k
Building Adaptive Systems
keathley
41
2.5k
Reflections from 52 weeks, 52 projects
jeffersonlam
349
20k
How to Think Like a Performance Engineer
csswizardry
23
1.6k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
129
19k
Facilitating Awesome Meetings
lara
54
6.4k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
357
30k
Become a Pro
speakerdeck
PRO
28
5.3k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
32
5.6k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
227
22k
jQuery: Nuts, Bolts and Bling
dougneiner
63
7.7k
Imperfection Machines: The Place of Print at Facebook
scottboms
267
13k
Transcript
None
Andrea Leopardi @whatyouhide
None
None
None
gen_statem
but why?!
FSM
FSM initial state states state transitions
None
chilling_and_looking_sad_for_no_reason
None
None
Finite?
Age of AI
gen_statem
None
@behaviour :gen_statem
None
init/1 terminate/3 code_change/4 format_status/2
def callback_mode do :state_functions end
handle_call/3 handle_cast/2 handle_info/2
<state_name>/3
<state_name>( event_type, event_content, data )
<state_name>( event_type, event_content, data )
<state_name>( event_type, event_content, data )
def handle_cast( {:put_coin, coin}, state ) do {:noreply, update_in(state.credit, &add_coin/1)}
end
def accepting_coins( :cast, {:put_coin, coin}, data ) do {:keep_state, update_in(data.credit,
&add_coin/1)} end
None
None
def accepting_coins( {:call, from}, {:press_button, beverage}, data ) do if
enough_credit?(data, beverage) do dispense_beverage(data, beverage) actions = [{:reply, from, :ok}] {:next_state, :dispensing, data, actions} else # ... end end
actions = [{:reply, from, :ok}] {:next_state, :dispensing, data, actions}
that’s kind of it?
Feature tour
Postponing events State enter callbacks Timeouts (state, event, named) Internal
events Non-finite state machines
Postponing events
None
def dispensing(:cast, {:add_coin, _}, data) do actions = [:postpone] {:keep_state_and_data,
actions} end def accepting_coins(:cast, {:add_coin, _}, data) do # Normal implementation end
“State enter”
def callback_mode do [ :state_functions, :state_enter ] end
def accepting_coins(:enter, _old_state, data) do update_display(data.credit) :keep_state_and_data end
Timeouts
Event timeouts
def accepting_coins(:cast, {:put_coin, coin}, data) do {:keep_state, update_in(data.credit, &add_coin/1)} end
def accepting_coins(:cast, {:put_coin, coin}, data) do actions = [ {:timeout,
to_timeout(second: 30), :give_back_coins} ] {:keep_state, update_in(data.credit, &add_coin/1), actions} end def accepting_coins(:timeout, :give_back_coins, data)
{:timeout, to_timeout(second: 30), :give_back_coins} def accepting_coins(:timeout, :give_back_coins, data)
State timeouts
def dispensing(:enter, _old_state, _data) do actions = [ {:state_timeout, to_timeout(minute:
1), :stuck} ] {:keep_state_and_data, actions} end def dispensing(:state_timeout, :stuck, data) do # Call for help, the machine got stuck. end
Named timeouts
def init(options) do actions = [ {{:timeout, :self_health_check}, to_timeout(hour: 1),
:no_content} ] {:ok, :idle, data, actions} end def idle({:timeout, :self_health_check}, _content, data) do # ... end
def accepting_coins({:timeout, :self_health_check}, _, _) do {:keep_state_and_data, [:postpone]} end def
dispensing({:timeout, :self_health_check}, _, _) do {:keep_state_and_data, [:postpone]} end
{:timeout, ms, content} {:state_timeout, ms, content} {{:timeout, :some_name}, ms, content}
“Internal” events
def disconnected({:timeout, :reconnect}, _, _data) do {:keep_state_and_data, {:next_event, :internal, :connect}}
end
Non-finite state machines
def callback_mode do :handle_event_function end
def accepting_coins( :cast, {:put_coin, coin}, data ) do # ...
end
def handle_event( :cast, {:put_coin, coin}, :accepting_coins, data ) do #
... end
def handle_event( event_type, event_content, current_state, data )
def handle_event( :cast, {:put_coin, coin}, {:accepting_coins, credit}, data ) do
new_state = {:accepting_coins, credit + coin} {:next_state, new_state, data} end
Use cases
None
GenServer :gen_statem or
def handle_call(call, from, %{user: nil}) def handle_call(call, from, %{user: %User{}})
def handle_call(call, from, %{user: %Admin{}})
def no_user({:call, from}, _, _) def user({:call, from}, _, _)
def admin({:call, from}, _, _)
Connections!
DBConnection Redix HTTP/2 (?)
None
state/named timeouts -> reconnection w/ backoff event timeouts -> keepalive
postponed events -> retrying requests
Workflow engines IoT sensors …
Wrapping up
Timeouts
No Elixir wrapper it’s fine
Data structures Processes vs
HTTP/2 stream state machine diagram
Composability
None
Resources Wikipedia Docs
Thanks! @whatyouhide AlchemyConf 2025