Skip to content

Commit 6b55b3e

Browse files
author
Henrik Kirk
committed
Akka 1 slides update
1 parent 853fcd0 commit 6b55b3e

File tree

3 files changed

+104
-75
lines changed

3 files changed

+104
-75
lines changed

slides/11/actor-1.md

Lines changed: 73 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,23 @@
1919

2020
### What is Akka.Net
2121

22-
* An actor framework - (ported from Scala Akka)
22+
* An actor framework - (ported from Scala Akka)<!-- .element: class="fragment" data-fragment-index="2" -->
2323
* Actor model is from SmallTalk - OO done right :)
2424
* inspiration from Erlang
25-
* Consists of
25+
* Consists of<!-- .element: class="fragment" data-fragment-index="3" -->
2626
* actors
2727
* messages
2828

2929
----
3030

3131
#### Actor
3232

33-
* Actors are lightweight
33+
* are lightweight<!-- .element: class="fragment" data-fragment-index="1" -->
3434
* 2.5-3 mio. actors per GB ram
35-
* Can send and receive messages
35+
* can send and receive messages<!-- .element: class="fragment" data-fragment-index="2" -->
3636
* process one message at a time
3737
* synchronized
38-
* Exists within an actor system
38+
* exists within an actor system<!-- .element: class="fragment" data-fragment-index="3" -->
3939

4040
----
4141

@@ -68,30 +68,32 @@ Creating an actor
6868
open Akka.FSharp
6969
7070
// for the message-processor kind of actor
71-
spawn myActorSystem "name" (actorOf (fn : 'M -> unit))
71+
spawn myActorSystem "name" (actorOf (fn : 'Msg -> unit))
7272
7373
// for the message-sender kind of actor
7474
spawn myActorSystem "name" (actorOf2
75-
(fn : Actor<'M> -> 'M -> unit))
75+
(fn : Actor<'Msg> -> 'Msg -> unit))
7676
```
7777

78-
Note: `spawn` `actofOf` and `actorOf2` is functions from `Akka.FSharp`
78+
* Akka.FSharp nuget package contains<!-- .element: class="fragment" -->
79+
* `spawn` `actofOf` and `actorOf2`
7980

8081
----
8182

8283
#### Communications
8384

84-
* Actors can send messages to each other
85-
* Messages are immutable and strongly typed
86-
* Operators
87-
* Tell (`<!`)
88-
* sends an async message to the `actor` referenced - under the hood
89-
* Ask (`<?`)
85+
* Actors can send messages to each other<br/><!-- .element: class="fragment" -->
86+
* Messages are immutable and strongly typed<br/><!-- .element: class="fragment" -->
87+
* Operators<br/><!-- .element: class="fragment" -->
88+
* `<!` (tell)
89+
* sends an async message to the `actor`
90+
* `<?` (ask)
9091
* sends an async message and wait for response
9192

9293
```fsharp
9394
actor <! "This is a message"
9495
```
96+
<!-- .element: class="fragment" -->
9597

9698
note:
9799
`<!` - tell operator
@@ -153,7 +155,8 @@ This is of the type `'M -> unit`
153155

154156
#### Cont.
155157

156-
6. Below the creation of the actor system, create an actor instance
158+
1. Below the creation of the actor system, create an actor instance
159+
1. `actorSystem.WhenTerminated.Wait ()` just wait for the actor system to terminate.
157160

158161
```fsharp
159162
let actor = spawn actorSystem "HelloActor"
@@ -193,6 +196,8 @@ let test2Actor = spawn myActorSystem "test2Actor"
193196

194197
### Manually creating an actor
195198

199+
* Computational expression
200+
196201
```fsharp
197202
let firstActor (mailbox:Actor<_>) =
198203
let rec loop() = actor {
@@ -230,30 +235,33 @@ actor {
230235

231236
### Messages
232237

233-
* F# types: `tuples`, `records` and `discriminated unions` can be used as messages.
234-
* Messages are send with the `tell` command we saw above `<!`
235-
* How to handle messages is optional
238+
* F# types:<!-- .element: class="fragment" -->
239+
* `tuples`, `records` and `discriminated unions` can be used as messages.
240+
* Messages are send with the '<!' tell operator<br/><!-- .element: class="fragment" -->
241+
* How to handle messages is optional<!-- .element: class="fragment" -->
236242
* normally pattern matching is used
237243

238244
```fsharp
239245
match msg with
240246
| :? string as cmd -> // do something with cmd
241247
| :> InputResult as ir -> // do something with ir
242248
```
249+
<!-- .element: class="fragment" -->
243250

244251
----
245252

246253
#### Unknown messages
247254

248-
* If an actor receives an unknown messages it should be ignored and possibly logged
249-
* If we change the actor from above
255+
* if an actor receives an unknown messages it is ignored and possibly logged<br/><!-- .element: class="fragment" -->
256+
* if we change the actor from above<!-- .element: class="fragment" -->
250257

251258
```fsharp
252259
let helloActor (mailbox:Actor<_>) msg =
253260
match msg with
254261
| "hello" -> printfn "Hello back at you"
255262
| _ -> mailbox.Unhandled msg
256263
```
264+
<!-- .element: class="fragment" -->
257265

258266
Note: There exists an actor type `ReceiveActor` which `handles` unknown messages automatically
259267

@@ -315,34 +323,33 @@ And run the program - notice than first messages is handled by the actor system
315323

316324
### `IActorRef`
317325

318-
* Reference/handle to another actor
319-
* Used to send message through the `ActorSystem`
326+
* Reference/handle to another actor<br/><!-- .element: class="fragment" -->
327+
* Used to send message through the 'ActorSystem'<br/><!-- .element: class="fragment" -->
320328
* we never talk directly to an actor
321329
```fsharp
322330
let actor = actorOf2 helloActor
323331
```
324-
* `ActorSystem` helps communications between actors
332+
* 'ActorSystem' helps communications between actors<br/><!-- .element: class="fragment" -->
325333
* wraps messages in an envelope with metadata
326334
* allow location transparency
327-
* actor can lives on another machine
335+
* actor can live on another machines
328336
329337
----
330338
331339
#### Getting an `IActorRef`
332340
333-
1. Create an actor
341+
1. Create an actor<br/><!-- .element: class="fragment" -->
334342
```fsharp
335343
let myFirstActor = spawn myActorSystem "myFirstActor"
336344
(actorOf firstActor)
337345
```
338-
2. Get `parent`, `siblings` or `children`, etc. from context
339-
3. Look up the actor via the `ActorPath` - we will see this later
346+
2. Get 'parent', 'siblings' or 'children', etc. from mailbox <br/><!-- .element: class="fragment" -->
347+
3. Look up the actor via the 'ActorPath' - we will see this later<br/><!-- .element: class="fragment" -->
340348

341349
----
342350

343351
#### `IActorRef` types
344352

345-
* Different kinds exists
346353
* Access to different `IActorRef` through the actor context
347354
* Parent, Children, Sender
348355

@@ -387,7 +394,7 @@ let helloActor (mailbox: Actor<_>) msg =
387394
mailbox.Sender () <! Continue
388395
```
389396

390-
Notice we use the context to access the `Sender` actor ref
397+
Notice we use the mailbox to access the `Sender` actor ref
391398

392399
----
393400

@@ -414,8 +421,7 @@ let senderActor hello (mailbox: Actor<_>) _ =
414421

415422
1. We have changed the way we are creating `helloActor` since it is sending messages
416423
2. `senderActor` is a function "`ICanTell -> Actor<'M> -> 'M -> unit`" which is partially applied with the `hello` IActorRef
417-
3. `actorSystem.WhenTerminated.Wait ()` just wait for the actor system to terminate.
418-
```fsharp [1-2|3-4|6|8]
424+
```fsharp [1-2|3-4|6]
419425
let hello = spawn actorSystem "HelloActor"
420426
(actorOf2 helloActor)
421427
let sender = spawn actorSystem "SenderActor"
@@ -430,53 +436,53 @@ actorSystem.WhenTerminated.Wait ()
430436

431437
![Actor Hierarchy](./img/actor-hierarchy.png) <!-- .element style="height: 300px" -->
432438

433-
* To atomize work, turn large data quantities into manageble chunks
434-
* To make system reliable and ressilient
439+
* To atomize work, turn large data quantities into manageble chunks<br/><!-- .element: class="fragment" -->
440+
* To make system reliable and ressilient<!-- .element: class="fragment" -->
435441

436442
----
437443

438444
#### Atomize work
439445

440-
* Breaks data down into smaller and smaller pieces
446+
* breaks data down into smaller and smaller pieces<br/><!-- .element: class="fragment" -->
441447
* let actors lower in the hierarchy work on these
442-
* 'Leaf' actors can then be very specialized
443-
* E.g. break data down recursively until it is easy to handle
448+
* 'leaf' actors can then be very specialized<br/><!-- .element: class="fragment" -->
449+
* e.g. break data down recursively until it is easy to handle<br/><!-- .element: class="fragment" -->
444450

445451
----
446452

447453
#### Real world example
448454

449-
* Twitter (now X) (uses/used JVM Akka)
455+
* Twitter (uses/used JVM Akka)
450456
* breaks down the stream of all tweets down into smaller streams - for each user.
451457

452458
----
453459

454460
#### Hierarchies for resilience
455461

456-
* Different levels og risk and specialization
457-
* Like an army
462+
* different levels of risk and specialization<br/><!-- .element: class="fragment" -->
463+
* like an army<br/><!-- .element: class="fragment" -->
458464
* actors close to the root is doing strategy or
459465
* supervision
460466
* actors closer to the leafs is handling riskier tasks
461-
* If error occur in a child actor, it can be e.g restarted without effecting the rest of the sytem.
467+
* if error occur in a child actor, it can be e.g restarted without effecting the rest of the sytem.<br/><!-- .element: class="fragment" -->
462468

463469
----
464470

465471
### Supervision
466472

467-
* Every actor we create has a supervisor
468-
* Allows for an actor system to isolate and recover from failures
469-
* Errors are contained in parts of the hierarchy
473+
* every actor we create has a supervisor<br/><!-- .element: class="fragment" -->
474+
* allows for an actor system to isolate and recover from failures<br/><!-- .element: class="fragment" -->
475+
* errors are contained in parts of the hierarchy<br/><!-- .element: class="fragment" -->
470476
* other actors is not effected
471477

472478

473479
----
474480

475481
#### In practics
476482

477-
* Every actor has a parent
483+
* every actor has a parent<br/><!-- .element: class="fragment" -->
478484
* some has a child(ren)
479-
* Parents supervise the child(ren)
485+
* parents supervise the child(ren)<br/><!-- .element: class="fragment" -->
480486

481487
----
482488

@@ -488,12 +494,12 @@ actorSystem.WhenTerminated.Wait ()
488494

489495
#### Guardians
490496

491-
* `/` - root guardian actor.
497+
* '/' - root guardian actor.<br/><!-- .element: class="fragment" -->
492498
* Supervises `/user/` and `/system`
493-
* `/system` - system guardian
499+
* '/system' - system guardian<br/><!-- .element: class="fragment" -->
494500
* Responsible for closing down system
495501
* Utility functions like logging etc.
496-
* `/user` - Guardian actor / root actor
502+
* '/user' - Guardian actor / root actor<br/><!-- .element: class="fragment" -->
497503
* Parent to our actors
498504

499505
Note:
@@ -505,52 +511,43 @@ Note:
505511

506512
#### User actors
507513

508-
* `/a1` and `/a2` are essential actors like the ones we have made
514+
* '/a1' and '/a2' are essential actors like the ones we have made<br/><!-- .element: class="fragment" data-fragment-index="1" -->
509515

510516
```fsharp
511517
let sender = spawn actorSystem "a1"
512518
(actorOf2 (senderActor hello))
513519
```
520+
<!-- .element: class="fragment" data-fragment-index="1" -->
514521

515-
* Actors created with the `actorSystem` is children of `/user`
516-
* Creating child actors e.g. `/b1`
522+
* Actors created with the 'actorSystem' is children of '/user'<br/><!-- .element: class="fragment" data-fragment-index="2" -->
523+
* Creating child actors e.g. '/b1'<!-- .element: class="fragment" data-fragment-index="3" -->
517524

518525
```fsharp
519526
// From inside the /a2 actor
520527
let b1 = spawn mailbox.context "b1" basicActor
521528
```
522-
523-
----
524-
525-
#### Actor path
526-
527-
* Every actor has an actor path
528-
* Actor path can be used to send messages to an actor
529-
530-
![Actor path](./img/actor_path.png)
531-
532-
// TODO: Move down after supervision
529+
<!-- .element: class="fragment" data-fragment-index="3" -->
533530

534531
----
535532

536533
#### Supervision
537534

538-
* Actor only supervise children
539-
* Supervision 'starts' when something goes wrong e.g. an exception in a child actor
535+
* Actor only supervise children<br/><!-- .element: class="fragment" -->
536+
* Supervision 'starts' when something goes wrong e.g. an exception in a child actor<br/><!-- .element: class="fragment" -->
540537
* Errors is wrapped in a `Failure` message and send to parent.
541-
* Parent actor handle message based on
538+
* Parent actor handle message based on<br/><!-- .element: class="fragment" -->
542539
* 1. how the child failed
543540
* 2. what directive is executed - based on `SupervisionStrategy`
544541

545542
----
546543

547544
#### Example
548545

549-
1. `c1` experience an error and throws an exception
550-
2. `c1` suspends operations
551-
3. The system sends a `Failure` message to `c1`'s parent `b1`
552-
4. `b1` issues a directive to `c1` telling it what should happen
553-
5. System continue to work
546+
1. 'c1' experience an error and throws an exception<br/><!-- .element: class="fragment" -->
547+
2. 'c1' suspends operations<br/><!-- .element: class="fragment" -->
548+
3. The system sends a 'Failure' message to 'c1's' parent 'b1'<br/><!-- .element: class="fragment" -->
549+
4. 'b1' issues a directive to 'c1' telling it what should happen<br/><!-- .element: class="fragment" -->
550+
5. system continue to work<br/><!-- .element: class="fragment" -->
554551

555552
----
556553

@@ -621,7 +618,7 @@ type WriterMessages =
621618
<!-- .slide: data-background="#dcedc1" -->
622619

623620
2. And change our `helloActor` to a writer actor in `Actors.fs`
624-
```fsharp
621+
```fsharp [7-10]
625622
let writerActor (_: Actor<WriterMessages>) msg =
626623
let print color (txt:string) =
627624
Console.ForegroundColor <- color
@@ -642,7 +639,7 @@ This can now handle 3 types of messages and write these to the console
642639

643640
3. The responsibility of our sender actor is now to send text from console to the correct actor
644641

645-
```fsharp
642+
```fsharp[6, 11, 12]
646643
// In Actors.fs
647644
let senderActor writer coordinator
648645
(mailbox: Actor<SenderMessages>) msg =
@@ -686,7 +683,7 @@ type SenderMessages =
686683

687684
4. We then introduce a `fileCoordinatorActor` in `Actors.fs`
688685

689-
```fsharp
686+
```fsharp [6-7, 13-14 | 8-11 ]
690687
let fileCoordinatorActor writer
691688
(mailbox: Actor<CoordinatorMessages>) msg =
692689
match msg with
@@ -718,7 +715,7 @@ type CoordinatorMessages =
718715

719716
5. And finally we introduce the `fileWriterActor` which actually is responsible for writing to the file.
720717

721-
```fsharp
718+
```fsharp [8-14]
722719
// In Actors.fs
723720
let fileWriterActor path writer
724721
(mailbox: Actor<FileWriterMessage>) msg =
@@ -750,7 +747,7 @@ type FileWriterMessage =
750747

751748
6. Lastly we change `Program.fs` so we start the new actor with a strategy
752749

753-
```fsharp
750+
```fsharp [7-8|9-13|1-6, 13]
754751
let strategy () = Strategy.OneForOne(( fun error ->
755752
match error with
756753
| :? ArithmeticException -> Directive.Resume
@@ -769,6 +766,7 @@ let coordinator = spawnOpt actorSystem "FileCoordinator"
769766

770767
---
771768

769+
772770
### References
773771

774772
* [https://petabridge.com/](https://petabridge.com/)

0 commit comments

Comments
 (0)