Skip to content

Commit

Permalink
Some updates to the Akka documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
derekwyatt committed Mar 1, 2011
1 parent aa46ea1 commit 362836e
Show file tree
Hide file tree
Showing 2 changed files with 285 additions and 11 deletions.
292 changes: 281 additions & 11 deletions doc/akka_info.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,37 @@ Copyright: (c) 2011 by Derek Wyatt
------------------------------------------------------------------------------

1. Actors..................................: |akka-actors|
1.1 Defining by Derivation...............: |akka-actor-derive|
1.2 Anonymous Creation...................: |akka-actor-anonymous|
1.3 Actor vs. ActorRef...................: |akka-actor-actorref|
1.1 Actor Lifecycle......................: |akka-actor-lifecycle|
1.2 Actor Companion Object...............: |akka-actor-object|
1.3 Defining by Derivation...............: |akka-actor-derive|
1.4 Anonymous Creation...................: |akka-actor-anonymous|
1.5 Actor vs. ActorRef...................: |akka-actor-actorref|
1.6 !, !!, and !!!.......................: |akka-actor-send-message|
1.6.1 !................................: |akka-actor-!|
1.6.2 !!...............................: |akka-actor-!!|
1.6.3 !!!..............................: |akka-actor-!!!|
1.7 Actor Control........................: |akka-actor-control|
1.7.1 Starting and Stopping............: |akka-actor-start-stop|
1.7.2 Poison Pill......................: |akka-actor-poisonpill|
1.7.3 Actor Murder.....................: |akka-actor-murder|
1.8 Hot-Swapping.........................: |akka-actor-hotswap|
1.8.1 Invoking the Hot-Swap............: |akka-actor-invoke-hotswap|
1.8.2 Reverting the Hot-Swap...........: |akka-actor-revert-hotswap|


==============================================================================
1. Actors *akka-actors* {{{1
------------------------------------------------------------------------------

1.1 Actor Companion Object *akka-actor-object* {{{2
1.1 Actor Lifecycle *akka-actor-lifecycle* {{{2
------------------------------------------------------------------------------

NEW (newly created actor) - can't receive messages (yet)
=> STARTED (when 'start' is invoked) - can receive messages
=> SHUT DOWN (when 'exit' or 'stop' is invoked) - can't do anything


1.2 Actor Companion Object *akka-actor-object* {{{2
------------------------------------------------------------------------------

The {Actor} object provides some convenience methods for constructing some
Expand Down Expand Up @@ -98,7 +119,7 @@ spawn(body: => Unit)(implicit dispatcher: MessageDispatcher = ...) : Unit
... // do stuff
}
!/sc!
1.2 Defining by Derivation *akka-actor-derive* {{{2
1.3 Defining by Derivation *akka-actor-derive* {{{2
------------------------------------------------------------------------------
!sc!
scala> import akka.actor._
Expand All @@ -119,7 +140,7 @@ spawn(body: => Unit)(implicit dispatcher: MessageDispatcher = ...) : Unit
scala> a.stop
!/sc!

1.3 Anonymous Creation *akka-actor-anonymous* {{{2
1.4 Anonymous Creation *akka-actor-anonymous* {{{2
------------------------------------------------------------------------------
!sc!
scala> var a = actorOf(new Actor {
Expand All @@ -135,7 +156,7 @@ spawn(body: => Unit)(implicit dispatcher: MessageDispatcher = ...) : Unit
scala> a.stop
!/sc!

1.4 Actor vs. ActorRef *akka-actor-actorref* {{{2
1.5 Actor vs. ActorRef *akka-actor-actorref* {{{2
------------------------------------------------------------------------------

One derives from {Actor} but the meat of things happens in the {ActorRef}, due
Expand All @@ -147,13 +168,60 @@ aspects that you no longer need to worry about.
The {actorOf} factory method available on the |akka-actor-object| provides the
ability to get an {ActorRef} from a derivation of {Actor}.

1.5 !, !!, and !!! *akka-actor-send-message* {{{2
The {Actor} trait itself has very little in it and is really only there to
give us a few points of extension:

receive()

The point of entry for incoming messages - this is the
message handler that gets called when someone makes a
call to:
- ! (|akka-actor-!|)
- !! (|akka-actor-!!|)
- !!! (|akka-actor-!!!|)

preStart()

Called before {Actor.start} (or {ActorRef.start}) is
called. Used to setup stuff before the /first/ call.

postStop()

Called before the {Actor} is stopped. This can happen
in a few different ways so it's not specifically called
before a call to {Actor.stop}.

preRestart()

Called before the {Actor} is restarted. When a supervisor
restarts the Actor, it will first call this method to
allow it to clear up some state first.

postRestart()

Called after the {Actor} is restarted. This might let you
get something going again after the core system is up and
running.

If you need access to the stuff held in the {self} field, you can import the
members directly, if you want:
!sc!
class MyActor extends Actor {
import self._
id = ...
dispatcher = ...
start
...
}
!/sc!

1.6 !, !!, and !!! *akka-actor-send-message* {{{2
------------------------------------------------------------------------------

Actors are all about passing messages around and the !, !! and !!! methods are
the {Actor}'s mechanisms for passing messages.

1.5.1 ! *akka-actor-bang* {{{3
1.6.1 ! *akka-actor-!* {{{3
------------------------------------------------------------------------------

The simple ! message is the best way to send something - it's the one-way
Expand Down Expand Up @@ -210,7 +278,7 @@ would always like to see one there, then it's easiest to simply force it in
the message and then it's there all the time.


1.5.2 !! *akka-actor-bang-bang* {{{3
1.6.2 !! *akka-actor-!!* {{{3
------------------------------------------------------------------------------

The !! method is a blocking call. The implication is that the reciever is
Expand Down Expand Up @@ -269,7 +337,7 @@ because it's easy, but we have to remember that it is an {Option} object, so
it may not be valid to do that.


1.5.3 !!! *akka-actor-bang-bang-bang* {{{3
1.6.3 !!! *akka-actor-!!!* {{{3
------------------------------------------------------------------------------

The !!! method returns a {Future}. This is a non-blocking call but requires
Expand All @@ -289,5 +357,207 @@ need not be an {Actor}, as is the case in the !! call. Using the exact same
Some(You said, 'Hithere, SyncServerActor', and I say 'Thanks')
!/sc!

1.7 Actor Control *akka-actor-control* {{{2
------------------------------------------------------------------------------

{Actor}s can be started easily enough and, in fact /must/ be started before
you can do anything with them. If you try to send a message to an {Actor}
that has not been started then you're going to get yourself a big fat
{akka.actor.ActorInitializationException}.

1.7.1 Starting and Stopping *akka-actor-start-stop* {{{3
------------------------------------------------------------------------------

Both {Actor} and {ActorRef} have a {start} method on them.
!sc!
scala> var a = actorOf(new Actor { def receive => } })
a: akka.actor.ActorRef =
Actor[$anonfun$1$$anon$1:3f434870-439f-11e0-8888-005056c00008]

scala> a.start

20:00:49.721 [main] DEBUG
a.d.Dispatchers$globalExecutorBasedEventDrivenDispatcher$ -
Starting up
Dispatchers$globalExecutorBasedEventDrivenDispatcher$[
akka:event-driven:dispatcher:global]
with throughput [5]
res2: akka.actor.ActorRef =
Actor[$anonfun$1$$anon$1:3f434870-439f-11e0-8888-005056c00008]

scala> a.stop

20:02:17.924 [main] INFO akka.actor.Scheduler$ - Starting up Scheduler
20:02:18.935 [akka:scheduler-0]
DEBUG a.d.Dispatchers$globalExecutorBasedEventDrivenDispatcher$ -
Shutting down Dispatchers$globalExecutorBasedEventDrivenDispatcher$[
akka:event-driven:dispatcher:global]
!/sc!

Note: You can't start an {Actor} that's already been stopped.

There's another way to shut down {Actor}s using the |akka-actor-registry|:
!sc!
scala> a.start

scala> Actor.registry.shutdownAll
20:05:04.055 [main] INFO akka.actor.ActorRegistry - Shutting down
all actors in the system...
20:05:04.063 [main] DEBUG akka.util.ReflectiveAccess$ - Could not
get object [akka.actor.TypedActor$]
20:05:04.119 [main] DEBUG akka.util.ReflectiveAccess$ - getObjectFor
java.lang.ClassNotFoundException: akka.actor.TypedActor$
at java.net.URLClassLoader$1.run(URLClassLoader.java:202) ~[na:1.6.0_22]
. . .
20:05:04.157 [main] INFO akka.actor.ActorRegistry - All actors have been
shut down and unregistered from ActorRegistry

scala> a.isRunning
res7: Boolean = false
!/sc!
Note the exception. I'm not sure exactly why that's happened but I definitely
don't have an {TypedActor}s running, so it may be trying to do some sort of
Class Loader nonsense without checking for them first. The bottom line
appears to be that the one {Actor} I had running is definitely stopped.


1.7.2 Poison Pill *akka-actor-poisonpill* {{{3
------------------------------------------------------------------------------

Another way to kill an {Actor} off is to send it a {PoisonPill}:
!sc!
scala> a.start
res9: akka.actor.ActorRef =
Actor[$anonfun$1$$anon$1:1330b630-43a1-11e0-8888-005056c00008]

scala> a ! PoisonPill
{ ... shutdown messages here ... }
!/sc!

1.7.3 Actor Murder *akka-actor-murder* {{{3
------------------------------------------------------------------------------

This was meant to hold the {Kill} message, but it looks like it's an old API
that's been removed in 1.0. {Kill} meant that the {Actor} should toss its
cookies and the {Supervisor} should restart it, so "Kill" was a pretty silly
name considering it didn't actually die.

It looks like this has been replaced with {Restart} and {Exit} but I'm not
sure why there are two of these... they both seem to do the same thing.

*Todo investigate this more by doing some experiments with the callbacks


1.8 Hot-Swapping *akka-actor-hotswap* {{{2
------------------------------------------------------------------------------

Hot-swapping allows the application to swap in new {Actor} message loops at
runtime. What you're doing is replacing the {PartialFunction[Any,Unit]}
function that is normally created statically by defining the {receive}
function. There are two ways you can do it:


1.8.1 Invoking the Hot-Swap *akka-actor-invoke-hotswap* {{{3
------------------------------------------------------------------------------

- Send a "HotSwap" message to the {Actor}
- Invoke the {become} method from within the {Actor}

The hot-swapped code is kept on a {Stack} so that it can be pushed and popped.
To hot-swap the {Actor} body using the "HotSwap" message:
!sc!
actor ! HotSwap(self => {
case message => self.reply("hot-swapped body")
})
!/sc!
To hot-swap the {Actor} using {become}:
!sc!
def angry: Receive = {
case "foo" => self reply "I am already angry!!!"
case "bar" => become(happy)
}

def happy: Receive = {
case "bar" => self reply "I am already happy :-)"
case "foo" => become(angry)
}

def receive = {
case "foo" => become(angry)
case "bar" => become(happy)
}
!/sc!
A decent use of hot-swapping is to implement a finite state machine. Here's
an example of using hot-swapping:
!sc!
case object Swap
class Swapper extends Actor {
def receive = {
case Swap =>
println("Hi")
become {
case Swap =>
println("Ho")
unbecome // resets the latest 'become' (just for fun)
}
}
}

val swap = actorOf[Swapper].start

swap ! Swap // prints Hi
swap ! Swap // prints Ho
swap ! Swap // prints Hi
swap ! Swap // prints Ho
swap ! Swap // prints Hi
swap ! Swap // prints Ho
!/sc!

1.8.2 Reverting the Hot-Swap *akka-actor-revert-hotswap* {{{3
------------------------------------------------------------------------------

Because the implementations are shoved on a {Stack}, you can also revert them.
You do this by doing the opposite of what you did before:

- Send a "RevertHotSwap" message to the {Actor}
- Invoke the {unbecome} method from within the {Actor}

To do it with the {RevertHotSwap} message:
!sc!
actor ! RevertHotSwap
!/sc!
and to do it with the {unbecome} method:
!sc!
def receive: Receive = {
case "revert" => unbecome
}
!/sc!

1.9 PartialFunction Chaining *akka-actor-partialfunc-chaining* {{{2
------------------------------------------------------------------------------

Here we can use the {orElse} method on {PartialFunction} to chain things
together and allow for some extensibility:
!sc!
abstract class GenericActor extends Actor {

// to be defined in subclassing actor
def specificMessageHandler: PartialFunction[Any, Unit]

// generic message handler
def genericMessageHandler = {
... // generic message handler
}

def receive = specificMessageHandler orElse genericMessageHandler
}

class SpecificActor extends GenericActor {
def specificMessageHandler = {
... // specific message handler
}
}
!/sc!

Modelines: {{{1
vim:tw=78:ts=4:ft=help:fdm=marker:fdl=0
4 changes: 4 additions & 0 deletions syntax/scala.vim
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ syn match scalaKeyword "=>"
syn match scalaKeyword "<-"
syn match scalaKeyword "\<_\>"

" well known 'names'
syn keyword scalaWellKnowns Actor ActorRef

syn match scalaOperator ":\{2,\}" "this is not a type

" package and import statements
Expand Down Expand Up @@ -139,6 +142,7 @@ hi link scalaClassName Special
hi link scalaClassSpecializer Special
hi link scalaConstructor Special
hi link scalaConstructorSpecializer scalaConstructor
hi link scalaWellKnowns Function

let b:current_syntax = "scala"

Expand Down

0 comments on commit 362836e

Please sign in to comment.