Skip to content

Commit

Permalink
Merge pull request akkadotnet#682 from Horusiath/fsapi-defer-fun
Browse files Browse the repository at this point in the history
F# API: added mailbox.Defer
  • Loading branch information
rogeralsing committed Feb 27, 2015
2 parents 0039248 + 023edc2 commit 07a0216
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 2 deletions.
15 changes: 13 additions & 2 deletions src/core/Akka.FSharp/FsApi.fs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ module Actors =
/// </summary>
abstract Log : Lazy<Akka.Event.LoggingAdapter>

/// <summary>
/// Defers provided function to be invoked when actor stops, regardless of reasons.
/// </summary>
abstract Defer : (unit -> unit) -> unit

[<AbstractClass>]
type Actor() =
inherit UntypedActor()
Expand Down Expand Up @@ -180,6 +185,7 @@ module Actors =
type FunActor<'Message, 'Returned>(actor : Actor<'Message> -> Cont<'Message, 'Returned>) as this =
inherit Actor()

let mutable deferables = []
let mutable state =
let self' = this.Self
let context = UntypedActor.Context :> IActorContext
Expand All @@ -194,7 +200,8 @@ module Actors =
member __.ActorSelection(path : ActorPath) = context.ActorSelection(path)
member __.Watch(aref:ActorRef) = context.Watch aref
member __.Unwatch(aref:ActorRef) = context.Unwatch aref
member __.Log = lazy (Akka.Event.Logging.GetLogger(context)) }
member __.Log = lazy (Akka.Event.Logging.GetLogger(context))
member __.Defer fn = deferables <- fn::deferables }

new(actor : Expr<Actor<'Message> -> Cont<'Message, 'Returned>>) = FunActor(actor.Compile () ())
member __.Sender() : ActorRef = base.Sender
Expand All @@ -203,9 +210,13 @@ module Actors =
match state with
| Func f -> state <- f (msg :?> 'Message)
| Return _ -> x.PostStop()
override x.PostStop() =
base.PostStop ()
List.iter (fun fn -> fn()) deferables


/// Builds an actor message handler using an actor expression syntax.
let actor = ActorBuilder()
let actor = ActorBuilder()

[<AutoOpen>]
module Logging =
Expand Down
18 changes: 18 additions & 0 deletions src/core/Akka.FSharp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,24 @@ Paragraph above already has shown, how actors may be created with help of the sp

All of these functions may be used with either actor system or actor itself. In the first case spawned actor will be placed under */user* root guardian of the current actor system hierarchy. In second option spawned actor will become child of the actor used as [actorFactory] parameter of the spawning function.

#### Dealing with disposable resources

When executing application logic inside receive function, be aware of a constant threat of stopping a current actor at any time for various reasons. This is an especially problematic situation when you're using a resource allocation - when actor will be stopped suddenly, you may be left with potentially heavy resources still waiting for being released.

Use `mailbox.Defer (deferredFunc)` in situations when you must ensure operation to be executed at the end of the actor lifecycle.

Example:

let disposableActor (mailbox:Actor<_>) =
let resource = new DisposableResource()
mailbox.Defer ((resource :> IDisposable).Dispose)
let rec loop () =
actor {
let! msg = mailbox.Receive()
return! loop ()
}
loop()

### Actor spawning options

To be able to specifiy more precise actor creation behavior, you may use `spawnOpt` and `spawne` methods, both taking a list of `SpawnOption` values. Each specific option should be present only once in the collection. When a conflict occurs (more than one option of specified type has been found), the latest value found inside the list will be chosen.
Expand Down

0 comments on commit 07a0216

Please sign in to comment.