19
19
20
20
### What is Akka.Net
21
21
22
- * An actor framework - (ported from Scala Akka)
22
+ * An actor framework - (ported from Scala Akka)<!-- .element: class="fragment" data-fragment-index="2" -->
23
23
* Actor model is from SmallTalk - OO done right :)
24
24
* inspiration from Erlang
25
- * Consists of
25
+ * Consists of<!-- .element: class="fragment" data-fragment-index="3" -->
26
26
* actors
27
27
* messages
28
28
29
29
----
30
30
31
31
#### Actor
32
32
33
- * Actors are lightweight
33
+ * are lightweight<!-- .element: class="fragment" data-fragment-index="1" -->
34
34
* 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" -->
36
36
* process one message at a time
37
37
* synchronized
38
- * Exists within an actor system
38
+ * exists within an actor system<!-- .element: class="fragment" data-fragment-index="3" -->
39
39
40
40
----
41
41
@@ -68,30 +68,32 @@ Creating an actor
68
68
open Akka.FSharp
69
69
70
70
// for the message-processor kind of actor
71
- spawn myActorSystem "name" (actorOf (fn : 'M -> unit))
71
+ spawn myActorSystem "name" (actorOf (fn : 'Msg -> unit))
72
72
73
73
// for the message-sender kind of actor
74
74
spawn myActorSystem "name" (actorOf2
75
- (fn : Actor<'M > -> 'M -> unit))
75
+ (fn : Actor<'Msg > -> 'Msg -> unit))
76
76
```
77
77
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 `
79
80
80
81
----
81
82
82
83
#### Communications
83
84
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 )
90
91
* sends an async message and wait for response
91
92
92
93
``` fsharp
93
94
actor <! "This is a message"
94
95
```
96
+ <!-- .element: class="fragment" -->
95
97
96
98
note:
97
99
` <! ` - tell operator
@@ -153,7 +155,8 @@ This is of the type `'M -> unit`
153
155
154
156
#### Cont.
155
157
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.
157
160
158
161
``` fsharp
159
162
let actor = spawn actorSystem "HelloActor"
@@ -193,6 +196,8 @@ let test2Actor = spawn myActorSystem "test2Actor"
193
196
194
197
### Manually creating an actor
195
198
199
+ * Computational expression
200
+
196
201
``` fsharp
197
202
let firstActor (mailbox:Actor<_>) =
198
203
let rec loop() = actor {
@@ -230,30 +235,33 @@ actor {
230
235
231
236
### Messages
232
237
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" -->
236
242
* normally pattern matching is used
237
243
238
244
``` fsharp
239
245
match msg with
240
246
| :? string as cmd -> // do something with cmd
241
247
| :> InputResult as ir -> // do something with ir
242
248
```
249
+ <!-- .element: class="fragment" -->
243
250
244
251
----
245
252
246
253
#### Unknown messages
247
254
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" -->
250
257
251
258
``` fsharp
252
259
let helloActor (mailbox:Actor<_>) msg =
253
260
match msg with
254
261
| "hello" -> printfn "Hello back at you"
255
262
| _ -> mailbox.Unhandled msg
256
263
```
264
+ <!-- .element: class="fragment" -->
257
265
258
266
Note: There exists an actor type ` ReceiveActor ` which ` handles ` unknown messages automatically
259
267
@@ -315,34 +323,33 @@ And run the program - notice than first messages is handled by the actor system
315
323
316
324
### ` IActorRef `
317
325
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" -->
320
328
* we never talk directly to an actor
321
329
``` fsharp
322
330
let actor = actorOf2 helloActor
323
331
```
324
- * ` ActorSystem` helps communications between actors
332
+ * ' ActorSystem' helps communications between actors<br/><!-- .element: class="fragment" -->
325
333
* wraps messages in an envelope with metadata
326
334
* allow location transparency
327
- * actor can lives on another machine
335
+ * actor can live on another machines
328
336
329
337
----
330
338
331
339
#### Getting an `IActorRef`
332
340
333
- 1. Create an actor
341
+ 1. Create an actor<br/><!-- .element: class="fragment" -->
334
342
```fsharp
335
343
let myFirstActor = spawn myActorSystem "myFirstActor"
336
344
(actorOf firstActor)
337
345
```
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" -->
340
348
341
349
----
342
350
343
351
#### ` IActorRef ` types
344
352
345
- * Different kinds exists
346
353
* Access to different ` IActorRef ` through the actor context
347
354
* Parent, Children, Sender
348
355
@@ -387,7 +394,7 @@ let helloActor (mailbox: Actor<_>) msg =
387
394
mailbox.Sender () <! Continue
388
395
```
389
396
390
- Notice we use the context to access the ` Sender ` actor ref
397
+ Notice we use the mailbox to access the ` Sender ` actor ref
391
398
392
399
----
393
400
@@ -414,8 +421,7 @@ let senderActor hello (mailbox: Actor<_>) _ =
414
421
415
422
1 . We have changed the way we are creating ` helloActor ` since it is sending messages
416
423
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]
419
425
let hello = spawn actorSystem "HelloActor"
420
426
(actorOf2 helloActor)
421
427
let sender = spawn actorSystem "SenderActor"
@@ -430,53 +436,53 @@ actorSystem.WhenTerminated.Wait ()
430
436
431
437
![ Actor Hierarchy] ( ./img/actor-hierarchy.png ) <!-- .element style="height: 300px" -->
432
438
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" -->
435
441
436
442
----
437
443
438
444
#### Atomize work
439
445
440
- * Breaks data down into smaller and smaller pieces
446
+ * breaks data down into smaller and smaller pieces< br /> <!-- .element: class="fragment" -->
441
447
* 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" -->
444
450
445
451
----
446
452
447
453
#### Real world example
448
454
449
- * Twitter (now X) ( uses/used JVM Akka)
455
+ * Twitter (uses/used JVM Akka)
450
456
* breaks down the stream of all tweets down into smaller streams - for each user.
451
457
452
458
----
453
459
454
460
#### Hierarchies for resilience
455
461
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" -->
458
464
* actors close to the root is doing strategy or
459
465
* supervision
460
466
* 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" -->
462
468
463
469
----
464
470
465
471
### Supervision
466
472
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" -->
470
476
* other actors is not effected
471
477
472
478
473
479
----
474
480
475
481
#### In practics
476
482
477
- * Every actor has a parent
483
+ * every actor has a parent< br /> <!-- .element: class="fragment" -->
478
484
* some has a child(ren)
479
- * Parents supervise the child(ren)
485
+ * parents supervise the child(ren)< br /> <!-- .element: class="fragment" -->
480
486
481
487
----
482
488
@@ -488,12 +494,12 @@ actorSystem.WhenTerminated.Wait ()
488
494
489
495
#### Guardians
490
496
491
- * ` / ` - root guardian actor.
497
+ * '/' - root guardian actor.< br /> <!-- .element: class="fragment" -->
492
498
* Supervises ` /user/ ` and ` /system `
493
- * ` /system ` - system guardian
499
+ * ' /system' - system guardian< br /> <!-- .element: class="fragment" -->
494
500
* Responsible for closing down system
495
501
* Utility functions like logging etc.
496
- * ` /user ` - Guardian actor / root actor
502
+ * ' /user' - Guardian actor / root actor< br /> <!-- .element: class="fragment" -->
497
503
* Parent to our actors
498
504
499
505
Note:
@@ -505,52 +511,43 @@ Note:
505
511
506
512
#### User actors
507
513
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" -->
509
515
510
516
``` fsharp
511
517
let sender = spawn actorSystem "a1"
512
518
(actorOf2 (senderActor hello))
513
519
```
520
+ <!-- .element: class="fragment" data-fragment-index="1" -->
514
521
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" -->
517
524
518
525
``` fsharp
519
526
// From inside the /a2 actor
520
527
let b1 = spawn mailbox.context "b1" basicActor
521
528
```
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" -->
533
530
534
531
----
535
532
536
533
#### Supervision
537
534
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" -->
540
537
* 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" -->
542
539
* 1 . how the child failed
543
540
* 2 . what directive is executed - based on ` SupervisionStrategy `
544
541
545
542
----
546
543
547
544
#### Example
548
545
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" -->
554
551
555
552
----
556
553
@@ -621,7 +618,7 @@ type WriterMessages =
621
618
<!-- .slide: data-background="#dcedc1" -->
622
619
623
620
2 . And change our ` helloActor ` to a writer actor in ` Actors.fs `
624
- ``` fsharp
621
+ ``` fsharp [7-10]
625
622
let writerActor (_: Actor<WriterMessages>) msg =
626
623
let print color (txt:string) =
627
624
Console.ForegroundColor <- color
@@ -642,7 +639,7 @@ This can now handle 3 types of messages and write these to the console
642
639
643
640
3 . The responsibility of our sender actor is now to send text from console to the correct actor
644
641
645
- ``` fsharp
642
+ ``` fsharp[6, 11, 12]
646
643
// In Actors.fs
647
644
let senderActor writer coordinator
648
645
(mailbox: Actor<SenderMessages>) msg =
@@ -686,7 +683,7 @@ type SenderMessages =
686
683
687
684
4 . We then introduce a ` fileCoordinatorActor ` in ` Actors.fs `
688
685
689
- ``` fsharp
686
+ ``` fsharp [6-7, 13-14 | 8-11 ]
690
687
let fileCoordinatorActor writer
691
688
(mailbox: Actor<CoordinatorMessages>) msg =
692
689
match msg with
@@ -718,7 +715,7 @@ type CoordinatorMessages =
718
715
719
716
5 . And finally we introduce the ` fileWriterActor ` which actually is responsible for writing to the file.
720
717
721
- ``` fsharp
718
+ ``` fsharp [8-14]
722
719
// In Actors.fs
723
720
let fileWriterActor path writer
724
721
(mailbox: Actor<FileWriterMessage>) msg =
@@ -750,7 +747,7 @@ type FileWriterMessage =
750
747
751
748
6 . Lastly we change ` Program.fs ` so we start the new actor with a strategy
752
749
753
- ``` fsharp
750
+ ``` fsharp [7-8|9-13|1-6, 13]
754
751
let strategy () = Strategy.OneForOne(( fun error ->
755
752
match error with
756
753
| :? ArithmeticException -> Directive.Resume
@@ -769,6 +766,7 @@ let coordinator = spawnOpt actorSystem "FileCoordinator"
769
766
770
767
---
771
768
769
+
772
770
### References
773
771
774
772
* [ https://petabridge.com/ ] ( https://petabridge.com/ )
0 commit comments