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
270
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 Umbrella and the Range
whatyouhide
0
19
The World is a Network (and We Are Just Nodes)
whatyouhide
1
230
BEAM: The Perfect Fit for Networks
whatyouhide
1
210
Update from the Elixir team - 2022
whatyouhide
0
420
Testing Asynchronous OTP
whatyouhide
1
530
Elixir Sightseeing Tour
whatyouhide
0
440
Mint - Disrupting HTTP clients
whatyouhide
0
270
BEAM Architecture Handbook
whatyouhide
7
2.9k
The Evolution of a Language
whatyouhide
0
170
Other Decks in Programming
See All in Programming
Dive into Triton Internals
appleparan
0
450
CSC509 Lecture 08
javiergs
PRO
0
280
Vueのバリデーション、結局どれを選べばいい? ― 自作バリデーションの限界と、脱却までの道のり ― / Which Vue Validation Library Should We Really Use? The Limits of Self-Made Validation and How I Finally Moved On
neginasu
3
1.8k
業務でAIを使いたい話
hnw
0
240
TransformerからMCPまで(現代AIを理解するための羅針盤)
mickey_kubo
7
6k
「10分以内に機能を消せる状態」 の実現のためにやっていること
togishima
1
120
AI駆動開発カンファレンスAutumn2025 _AI駆動開発にはAI駆動品質保証
autifyhq
0
130
Researchlyの開発で参考にしたデザイン
adsholoko
0
110
Bakuraku E2E Scenario Test System Architecture #bakuraku_qa_study
teyamagu
PRO
0
440
チームのテスト力を総合的に鍛えてシフトレフトを推進する/Shifting Left with Software Testing Improvements
goyoki
4
2.1k
NIKKEI Tech Talk#38
cipepser
0
400
One Enishi After Another
snoozer05
PRO
0
180
Featured
See All Featured
VelocityConf: Rendering Performance Case Studies
addyosmani
333
24k
A Modern Web Designer's Workflow
chriscoyier
697
190k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
46
7.8k
Principles of Awesome APIs and How to Build Them.
keavy
127
17k
Code Review Best Practice
trishagee
72
19k
Building Flexible Design Systems
yeseniaperezcruz
329
39k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
9
960
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
16k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
116
20k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.2k
Optimizing for Happiness
mojombo
379
70k
The Invisible Side of Design
smashingmag
302
51k
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