Skip to content

Instantly share code, notes, and snippets.

@jtmueller
Last active December 23, 2015 08:04
Show Gist options
  • Save jtmueller/15e5c8dafbf5bada808b to your computer and use it in GitHub Desktop.
Save jtmueller/15e5c8dafbf5bada808b to your computer and use it in GitHub Desktop.
namespace Akka.FSharp
open System
/// The result of an Akka Ask operation, either a value or an exception.
type AskResult<'TResult> =
| Ok of result: 'TResult
| Err of exn
with
/// Retrieves the value on success, throws an exception if there was an error.
member x.Value =
match x with
| Ok result -> result
| Err err ->
raise <| InvalidOperationException("Accessed the Value of an AskResult in an error state.", err)
[<AutoOpen>]
module AkkaExtensions =
open System.Threading.Tasks
open Akka.Actor
open Akka.FSharp
let private taskOpts = TaskContinuationOptions.AttachedToParent ||| TaskContinuationOptions.ExecuteSynchronously
let private tryCast<'TResult> (t:Task<obj>) : AskResult<'TResult> =
if t.IsFaulted then Err t.Exception
else
try
match t.Result with
| :? 'TResult as res -> Ok res
| :? AskResult<'TResult> as res -> res
| :? Status.Failure as fail -> Err fail.Cause
| :? exn as ex -> Err ex
| other ->
let msg = sprintf "Ask expected type %s but received type %s: %A" (typeof<'TResult>.FullName) (other.GetType().FullName) other
Err(InvalidCastException msg)
with ex ->
Err ex
type ICanTell with
/// Ask overload that returns an AskResult discriminated union instead of throwing an exception.
member x.Ask<'TResult>(msg:obj, ?timeout:TimeSpan) =
let timeout = match timeout with Some t -> Nullable(t) | None -> Nullable()
x.Ask(msg, timeout).ContinueWith(tryCast<'TResult>, taskOpts)
|> Async.AwaitTask
/// Bidirectional send operator. Sends a message object directly to actor
/// tracked by actorRef and awaits for response send back from corresponding actor.
/// Returns an AskResult discriminated union instead of throwing an exception.
let (<?) (tell: #ICanTell) (msg: obj) : Async<AskResult<'TResult>> =
tell.Ask<'TResult>(msg)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment