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
260
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
15
The World is a Network (and We Are Just Nodes)
whatyouhide
1
220
BEAM: The Perfect Fit for Networks
whatyouhide
1
200
Update from the Elixir team - 2022
whatyouhide
0
410
Testing Asynchronous OTP
whatyouhide
1
530
Elixir Sightseeing Tour
whatyouhide
0
440
Mint - Disrupting HTTP clients
whatyouhide
0
260
BEAM Architecture Handbook
whatyouhide
7
2.8k
The Evolution of a Language
whatyouhide
0
160
Other Decks in Programming
See All in Programming
AI時代のUIはどこへ行く?
yusukebe
18
8.8k
Kiroで始めるAI-DLC
kaonash
2
580
Tool Catalog Agent for Bedrock AgentCore Gateway
licux
6
2.4k
Ruby Parser progress report 2025
yui_knk
1
440
Android 16 × Jetpack Composeで縦書きテキストエディタを作ろう / Vertical Text Editor with Compose on Android 16
cc4966
1
200
テストコードはもう書かない:JetBrains AI Assistantに委ねる非同期処理のテスト自動設計・生成
makun
0
260
そのAPI、誰のため? Androidライブラリ設計における利用者目線の実践テクニック
mkeeda
2
290
AIと私たちの学習の変化を考える - Claude Codeの学習モードを例に
azukiazusa1
10
3.9k
機能追加とリーダー業務の類似性
rinchoku
2
1.3k
CJK and Unicode From a PHP Committer
youkidearitai
PRO
0
110
意外と簡単!?フロントエンドでパスキー認証を実現する WebAuthn
teamlab
PRO
2
740
Reading Rails 1.0 Source Code
okuramasafumi
0
110
Featured
See All Featured
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
358
30k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.4k
Build your cross-platform service in a week with App Engine
jlugia
231
18k
Navigating Team Friction
lara
189
15k
Designing for humans not robots
tammielis
253
25k
Thoughts on Productivity
jonyablonski
70
4.8k
BBQ
matthewcrist
89
9.8k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Building Flexible Design Systems
yeseniaperezcruz
328
39k
Making the Leap to Tech Lead
cromwellryan
135
9.5k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
22k
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