Tak pro tebe mám ty příklady
Úplně nejjednodušší actor, jenom abys viděl, jak se v Elixiru spawnují procesy a posílají zprávy:
$ curl -O https://gist.githubusercontent.com/mprymek/0308d05d79237211dd732436f7887cd6/raw/da55a5fc4c9878405cc0da1dcf15ea8cc4759a3d/01-simplest.exs
$ elixir 01-simplest.exs
[main] My PID: #PID<0.92.0>
[main] Agent a1 runs with #PID<0.97.0>
[SimplestActor] Got message from #PID<0.92.0>: 1
[SimplestActor] Got message from #PID<0.92.0>: 2
Bezestavový actor poskytující službu "přičti jedničku":
$ curl -O https://gist.githubusercontent.com/mprymek/0308d05d79237211dd732436f7887cd6/raw/da55a5fc4c9878405cc0da1dcf15ea8cc4759a3d/02-stateless.exs
$ elixir 02-stateless.exs
[main] My PID: #PID<0.92.0>
[main] Agent a1 runs with #PID<0.97.0>
[StatelessActor] Got message from #PID<0.92.0>: 1
[main] Got reply from actor a1: 2
[StatelessActor] Got message from #PID<0.92.0>: 2
[main] Got reply from actor a1: 3
No a do třetice různý variace na stavovýho actora...
Tohle je úplně chybná implementace, která nepočítá s více klienty a proto zhavaruje:
$ curl -O https://gist.githubusercontent.com/mprymek/0308d05d79237211dd732436f7887cd6/raw/da55a5fc4c9878405cc0da1dcf15ea8cc4759a3d/03a-statefull.exs
$ elixir 03a-statefull.exs
[main] My PID: #PID<0.92.0>
[main] Agent a1 runs with #PID<0.97.0>
[ChitChatActor2] Got message from #PID<0.92.0>: :hello
[main] Got reply from actor a1: :hello
[ChitChatActor2] Got message from #PID<0.92.0>: :bye
[ChitChatActor2] Session closed
[ChitChatActor2] Got message from #PID<0.92.0>: :hello
[main] Got reply from actor a1: :hello
[ccc #PID<0.98.0>] Starting
[ccc #PID<0.99.0>] Starting
18:48:20.866 [error] Process #PID<0.98.0> raised an exception
** (RuntimeError) Timeout!
03a-statefull.exs:90: anonymous fn/1 in :elixir_compiler_0.__FILE__/1
18:48:20.870 [error] Process #PID<0.99.0> raised an exception
** (RuntimeError) Timeout!
03a-statefull.exs:90: anonymous fn/1 in :elixir_compiler_0.__FILE__/1
Tahle je o trošičku lepší - vybírá zprávy selektivně, takže protokol zpracuje správně, ale pořád je chybná, protože neumí rozlišit sessions (nezajímá ji, od koho která zpráva je, takže klienti by klidně mohli posílat zprávy na střídačku a server by si toho nevšiml):
$ curl -O https://gist.githubusercontent.com/mprymek/0308d05d79237211dd732436f7887cd6/raw/da55a5fc4c9878405cc0da1dcf15ea8cc4759a3d/03b-statefull.exs
$ elixir 03b-statefull.exs
[main] Agent a1 runs with #PID<0.97.0>
[ccc #PID<0.98.0>] Starting
[ccc #PID<0.99.0>] Starting
[ChitChatActor2] Got message from #PID<0.98.0>: :hello
[ChitChatActor2] Got message from #PID<0.98.0>: :bye
[ChitChatActor2] Session closed
[ChitChatActor2] Got message from #PID<0.99.0>: :hello
[ccc #PID<0.98.0>] Everything OK
[ChitChatActor2] Got message from #PID<0.99.0>: :bye
[ChitChatActor2] Session closed
[ccc #PID<0.99.0>] Everything OK
No a tohle je už docela slušá implementace, na které můžeš vidět právě to, že si actor drží informace o sessions "u sebe" - a není to nijak zvlášť komplikovaný:
$ curl -O https://gist.githubusercontent.com/mprymek/0308d05d79237211dd732436f7887cd6/raw/f00a01adaafb1623923c9e3469040b9976ce2906/03c-statefull.exs
$ elixir 03c-statefull.exs
[main] Agent a1 runs with #PID<0.97.0>
[ccc #PID<0.98.0>] Starting
[ccc #PID<0.99.0>] Starting
[ChitChatActor3] Got message from #PID<0.98.0>: :hello
[ChitChatActor3] New session #PID<0.98.0>
[ChitChatActor3] Got message from #PID<0.99.0>: :hello
[ChitChatActor3] New session #PID<0.99.0>
[ChitChatActor3] Got message from #PID<0.98.0>: :bye
[ChitChatActor3] session #PID<0.98.0> closed
[ChitChatActor3] Got message from #PID<0.99.0>: :bye
[ChitChatActor3] session #PID<0.99.0> closed
[ccc #PID<0.98.0>] Everything OK
[ccc #PID<0.99.0>] Everything OK
No a tohle už je taková vcelku standardní implementace, která odbavuje každýho klienta pomocí vlastního procesu. Ve skutečné praxi by se to sice psalo trošku jinak, ale všechny základní principy tam jsou implementované dobře (pokud jsem se někde neupsal
):
$ curl -O https://gist.githubusercontent.com/mprymek/0308d05d79237211dd732436f7887cd6/raw/da55a5fc4c9878405cc0da1dcf15ea8cc4759a3d/03d-statefull.exs
$ elixir 03d-statefull.exs
[main] Agent a1 runs with #PID<0.99.0>
[ccc #PID<0.100.0>] Starting
[ccc #PID<0.101.0>] Starting
[Proxy] Got message from #PID<0.100.0>: :hello
[Proxy] Creating handler Elixir.ChitChatHandler for session #PID<0.100.0>
[CCH #PID<0.100.0>] Starting
[CCH #PID<0.100.0>] got :hello from #PID<0.100.0>
[Proxy] handlers = %{#PID<0.100.0> => #PID<0.102.0>}
[Proxy] Got message from #PID<0.101.0>: :hello
[Proxy] Creating handler Elixir.ChitChatHandler for session #PID<0.101.0>
[Proxy] handlers = %{#PID<0.100.0> => #PID<0.102.0>, #PID<0.101.0> => #PID<0.103.0>}
[CCH #PID<0.101.0>] Starting
[CCH #PID<0.101.0>] got :hello from #PID<0.101.0>
[Proxy] Got message from #PID<0.100.0>: :bye
[CCH #PID<0.100.0>] got :bye from #PID<0.100.0>
[Proxy] Deleting handler for session #PID<0.100.0>
[Proxy] handlers = %{#PID<0.101.0> => #PID<0.103.0>}
[Proxy] Got message from #PID<0.101.0>: :bye
[CCH #PID<0.101.0>] got :bye from #PID<0.101.0>
[Proxy] Deleting handler for session #PID<0.101.0>
[Proxy] handlers = %{}
[ccc #PID<0.100.0>] Everything OK
[ccc #PID<0.101.0>] Everything OK