Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

F# + recieve message DU instead of object. #154

Closed
Neftedollar opened this issue Jun 13, 2019 · 3 comments
Closed

F# + recieve message DU instead of object. #154

Neftedollar opened this issue Jun 13, 2019 · 3 comments

Comments

@Neftedollar
Copy link
Contributor

Neftedollar commented Jun 13, 2019

Hey!
I've found that the Receive method takes only a few types of Messages.
So I've tried to find where can I insert DU wrapper. I want to grains looks like

type MyGrain<MyMsg> =
  member x.Recieve ( msg: GrainMsg<MyMsg>) = 
    match msg with 
    | Msg(MyMsgCase1 x) -> none()
    | Time t -> t.GetType()|> printfn "%O"; none() // Orleankka.Tymire message 
    | OnActivate a -> a.GetType() //Activate type from https://github.com/OrleansContrib/Orleankka/blob/master/Source/Orleankka.Runtime/ActorGrainMessages.cs . also
    /// ..etc

but I didn't find any place in the F# packages where can I put middlware that will wrap objects with DU.
Can you help me with ideas for it?

@yevhen
Copy link
Member

yevhen commented Jun 13, 2019

Just use nested match like here

P.S. Generic actor grains were deprecated since 2.x exactly due to this reason (we can’t have DU with system messages). DU are only for public interface, ie caller side type safety.

@Neftedollar
Copy link
Contributor Author

Neftedollar commented Jun 17, 2019

Ok, maybe I should write something like

type GrainMessage<'t> = | Msg of 't | Timer of Timer  | ..
type TypedGrain<'t> () =
 inherit  ActorGrain() 
 abstract member this.TypedReceive ( msg: GrainMessage<'t>)
 override this.Receive (message) =
  match message with 
  | :? 't as msg -> this.TypedReceive(GrainMessage(msg))
  | :? Timer as msg -> this.TypedReceive(GrainMessage ( msg))
 .. etc

and then use it like ActorGrain but with TypedReceive method instead of Receive.
🤔

@Neftedollar
Copy link
Contributor Author

I've created this

type ActorMsg<'t> =
    | Msg of 't
    | Timer of Orleankka.Timer
    | Reminder of Orleankka.Reminder
    | Activate of Orleankka.Activate
    | Deactivate of Orleankka.Deactivate

[<AbstractClass>]
type TypedActor<'a>() =
    inherit ActorGrain()
    abstract member ReceiveT: ActorMsg<'a> -> System.Threading.Tasks.Task<obj> 
    override this.Receive(msg:obj) = task {
      match msg with
      | :? 'a as m -> return! this.ReceiveT (Msg m)
      | :? Orleankka.Timer as t -> return! this.ReceiveT( Timer t)
      | :? Orleankka.Activate as a -> return! this.ReceiveT ( Activate a)
      | :? Orleankka.Deactivate as d -> return! this.ReceiveT( Deactivate d)
      | _ -> return unhandled() }

and use it like

type HelloGrain (loggerFactory:ILoggerFactory) =
  inherit TypedActor<HelloMessages>()
  let log = loggerFactory.CreateLogger(typeof<HelloGrain>)
  interface IHello
  override this.ReceiveT(msg) = task {
    match msg with
    | Msg(Hi)-> 
        log.LogInformation("Client asked to say Hi!")
        return some "Oh, hi!"
    | Msg(Hello s) ->
        log.LogInformation (sprintf "Client asked to say Hello to %s" s)
        return sprintf "Hello, %s" s |> some
    | Msg(Bue) -> 
        log.LogInformation ("Client wants to go")
        return none()
    | _ ->  return unhandled()
  }

and it's awesome!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants