Why does ZeroMQ's socket.recv call hang in the following code? - f#

I have encountered a problem with a simple pub-sub example in ZeroMQ. I have read plenty of documentation, but I cannot seem to find an answer.
I got libzmq and clrzmq from NuGet. For both the functions below the socket address is:
let sktAddr = "tcp://127.0.0.1:3456"
Here is a simple publisher, that queues a message every second.
// Publisher - this seems to work fine
let publisher () : unit =
let skt = (new ZMQ.Context()).Socket(ZMQ.SocketType.PUB)
skt.SetSockOpt(ZMQ.SocketOpt.LINGER, 0)
skt.Bind sktAddr
skt.SendMore("TEST_TOPIC", Text.Encoding.Unicode) |> ignore
let rec h1 () : unit =
let nv = DateTime.Now.ToUniversalTime().ToString()
printfn "Sending value: %s" nv
skt.Send(Text.Encoding.Unicode.GetBytes nv) |> ignore
Threading.Thread.Sleep 1000
let swt = new Threading.SpinWait()
swt.SpinOnce()
if Console.KeyAvailable then
match Console.ReadKey().Key with
| ConsoleKey.Q -> ()
| _ -> h1()
else
h1()
h1()
The following simple subscriber throws no error, but hangs at the line indicated below.
// Subscriber
let subscriber () : unit =
let skt = (new ZMQ.Context()).Socket(ZMQ.SocketType.SUB)
skt.Connect sktAddr
skt.Subscribe("TEST_TOPIC", Text.Encoding.Unicode)
let rec h1 () : unit =
let oDat = skt.Recv() // THE PROGRAMME HANGS HERE!
let strODat = (new Text.UnicodeEncoding()).GetString oDat
if oDat <> null then
printfn "Received: %s" strODat
else
printfn "No data received"
let swt = new System.Threading.SpinWait()
swt.SpinOnce()
if Console.KeyAvailable then
match Console.ReadKey().Key with
| ConsoleKey.Q -> ()
| _ -> h1()
else
h1()
h1()
I have read this question, but no solution is provided. So I am posting a new question here.
Thanks in advance for your help.

I believe the problem is in the publisher:
skt.SendMore("TEST_TOPIC", Text.Encoding.Unicode)
Not knowing F#, it appears the above statement happens outside the loop. If the subscriber is listening on TEST_TOPIC, any messages originating from the publisher require the topic name to precede content for each message, so the publisher must do this each time it sends:
skt.SendMore("TEST_TOPIC", Text.Encoding.Unicode)
skt.Send("some data here", Text.Encoding.Unicode)
..try this...
let publisher () : unit =
let skt = (new ZMQ.Context()).Socket(ZMQ.SocketType.PUB)
skt.SetSockOpt(ZMQ.SocketOpt.LINGER, 0)
skt.Bind sktAddr
let rec h1 () : unit =
let nv = DateTime.Now.ToUniversalTime().ToString()
printfn "Sending value: %s" nv
skt.SendMore("TEST_TOPIC", Text.Encoding.Unicode) |> ignore
skt.Send(Text.Encoding.Unicode.GetBytes nv) |> ignore
Threading.Thread.Sleep 1000
let swt = new Threading.SpinWait()
swt.SpinOnce()
if Console.KeyAvailable then
match Console.ReadKey().Key with
| ConsoleKey.Q -> ()
| _ -> h1()
else
h1()
h1()
..and the subscriber has to receive twice for each message:
// Subscriber
let subscriber () : unit =
let skt = (new ZMQ.Context()).Socket(ZMQ.SocketType.SUB)
skt.Connect sktAddr
skt.Subscribe("TEST_TOPIC", Text.Encoding.Unicode)
let rec h1 () : unit =
let topicName = skt.Recv()
let oDat = skt.Recv()
let strODat = (new Text.UnicodeEncoding()).GetString oDat
if oDat <> null then
printfn "Received: %s" strODat
else
printfn "No data received"
let swt = new System.Threading.SpinWait()
swt.SpinOnce()
if Console.KeyAvailable then
match Console.ReadKey().Key with
| ConsoleKey.Q -> ()
| _ -> h1()
else
h1()
h1()

Related

How to call an actor within itself in F# Akka

The code I have is --
let mySlaveActor (mailbox: Actor<_>) =
let rec loop() = actor {
let mutable actor_id = -1
let mutable rumor = ""
let! rcv = mailbox.Receive()
let sender = mailbox.Sender()
match rcv with
| MessageType2(idx) ->
actor_id <- idx
| MessageType8(neighbor) ->
if (neighbor <> -1) then
let neighbor_slave = spawn mailbox (sprintf "workerActor%i" neighbor) mySlaveActor
neighbor_slave <! MessageType5(actor_id)
The current object is of a mySlaveActor whose name is workerActor1 and I want to call WorkerActor2 when the match is MessageType8(..). But in the penultimate line, I get an error like --
The value or constructor `mySlaveActor` is not defined
Am I doing something wrong is my code missing something? Thanks for the help.

Suave and DotLiquid

edited for clarity
somehow this works:
path "/" >=> warbler (fun _ -> OK (string DateTime.Now))
but this one does not:
let txnAccA =
let sqlStr = "select JSON from Store.Txn"
let result = Db.execute sqlStr Config.oConnStr
match result with
| Some a ->
[for i in a do
let msg = JsonConvert.DeserializeObject<TxnAccA>(i)
yield msg
]
| _ ->
List.empty<TxnAccA>
let txnAmtA =
let sqlStr = "select JSON from Store.Amt"
let result = Db.execute sqlStr Config.oConnStr
match result with
| Some a ->
[for i in a do
let msg = JsonConvert.DeserializeObject<TxnAmtA>(i)
yield msg
]
| _ ->
List.empty<TxnAmtA>
let result ()= {Acc= txnAccA; Amt= txnAmtA}
path "/txn" >=> warbler (fun _ -> page "txn.html" (result()))
By "works" I mean that the page is not static, it displays latest data from database. Any idea why?
txnAccA and txnAmtA need to be functions (similar to result). They are defined as values now, so get assigned once and will not query the DB for every request. result will create a new record every time when called, but the values stay always the same.
let txnAccA () = //...
let txnAmtA () = //...
let result () = { Acc = txnAccA(); Amt = txnAmtA() }
path "/txn" >=> warbler (fun _ -> page "txn.html" (result()))

Unable to call a function from recursive f#

trying out F#, learnt a lot today not sure if I am doing this try but I have a pattern match and recursive for some reason I am unable to call this from recursive.
// Define my active recognizer for keywords
let(|MyGirlFriend|Bye|) input =
match input with
|"lonely|"love"|"friendship"
-> MyGirlFriend
|"goodbye"|"bye"|"go"|
-> Bye
|_
-> None
I think the above code that above looks right.
//recursive response function
let rec response (token: string) (str: string) =
match token with
| Bye
-> good_bye_response ()
| RoomLocation
-> sprintf "%s" "Your call is log. Do you wish to quit?"
|_ when token.Contains("yes") -> "good bye" 0
|_ when token.Contains("no") -> answer_response ()
| None when (str.IndexOf(" ") > 0)
-> response (str.Substring(0,str.IndexOf(" ")))
(str.Substring(str.IndexOf(" ")+1))
| None when (str.IndexOf(" ") < 0)
-> response str ""
my function is :
let rec chat () =
if Break = false then
let valueInput = Console.ReadLine()
printf "Helpdesk-BCU Response --> %s \n" (response "" valueInput)
if Break = false then
chat()
else
ChatEnd()
let BCU_response (str: string) =
if (str.IndexOf(" ") > 0) then
response (str.Substring(0,str.IndexOf(" "))) (str.Substring(str.IndexOf("
")+1)) + "\n"
else
response str "" + "\n"
a couple of issues here |_ when token.Contains("yes") -> "goodbye" 0 the zero that is used in F# as an exit on here I get a red line and it states expression should have type string but has type int, I know zero is an int.
so how do I exit the recursive loop?
any sugguestion would be most welcome
It is not entirely clear what part are you struggling with, because there is quite a lot of minor issues in the code. However, a minimal working example that shows how to do the recursion is something like this:
open System
let (|Bye|Other|) input =
match input with
| "goodbye" | "bye" | "go" -> Bye
| _ -> Other
let response (token: string) =
match token with
| Bye -> false, "bye!"
| Other -> true, "sorry, I didn't get that"
let rec chat () =
let input = Console.ReadLine()
let keepRunning, message = response input
printfn ">> %s" message
if keepRunning then chat ()
The response function now also returns a Boolean - if this is true, the chat function calls itself recursively to ask another question. Otherwise, it just returns without asking more questions.

Data being lost while sending messages form one actor to another

I have created an Agent say "A", which simply sends some bulky data to Agent "B".
Agent A Code :
let largeText = "some large text (around 30kb)"
InputData_Type =
{
//some code
Body : string
}
let default_InputData =
{
//some code
Body = largeText
}
type ActorMsg =
| InItServices
| Data of InputData_Type
| UpdateList
let system = ActorSystem.Create("A")
let actRef = system.ActorSelection("akka.tcp://B#localhost:9999/user/EchoServer")
actRef.Ask(JsonConvert.SerializeObject(InItServices)).Wait()
[1..1000000]
|> List.iter(fun x ->
actRef.Tell(JsonConvert.SerializeObject(Data (default_InputData))))
let listLength = string(actRef.Ask(JsonConvert.SerializeObject(UpdateList)).Result)
printfn "length is %A" listLength
Agent "B" is stores/maintains the data he received into a database.
Agent B code :
try
let echoServer =
spawn system "EchoServer"
<| fun mailbox ->
let rec loop( cnt : int32 ) =
actor {
let! message = mailbox.Receive()
let sender = mailbox.Sender()
let deserializedEmailData = JsonConvert.DeserializeObject<ActorMsg> (message)
match deserializedEmailData with
| InItServices ->
sender <! ""
return! loop (0)
| Data (textData)->
// some logic to maintain list
let count = cnt + 1
return! loop (count)
| UpdateList ->
//some logic to store list
sender <! ("Length is " + cnt.ToString())
return! loop (0)
}
loop(0)
()
with
|exc ->
printfn "%A" exc
Agent "A" and "B" are created on same machine but are on different ports.
I have observed that, number of records received by agent B are different each time when I execute above setup.
Means say If I sent 20000 messages to Agent B, Agent B is actually receiving only say 1600(number varies) messages.
What exactly going wrong in above scenario ?

Confusing F# compiler message

The following snippet illustrates the error I'm getting. Even though both match branches return the same thing; I get error, "This expression was expected to have type unit but here has type 'a -> unit" I have no clue what the compiler wants here...
open System.IO
let FileContent contents =
match contents with
| "" -> None
| c -> Some(c)
let WriteSomething (contents:string) =
let writer = new StreamWriter("")
writer.Write( contents ) |> ignore
let DoStuffWithFileContents =
let reader = new StreamReader( "" )
let stuff = reader.ReadToEnd()
match stuff |> FileContent with
| Some(c) -> WriteSomething c
|> ignore
| None -> ignore // <- error on "ignore"
The ignore operator is actually a function that takes a single input and returns the unit type (F#'s equivalent of void). So when you have -> ignore you're returning the ignore function.
Instead, use () to represent the value of the unit type:
| Some(c) -> WriteSomething c
|> ignore
| None -> ()
But actually, since StreamWriter.Write returns void, all these ignore's are unnecessary. You could just as easily write this as:
let WriteSomething (contents:string) =
let writer = new StreamWriter("")
writer.Write(contents)
let DoStuffWithFileContents =
let reader = new StreamReader("")
let stuff = reader.ReadToEnd()
match stuff |> FileContent with
| Some(c) -> WriteSomething c
| None -> ()
Or even better, use Option.iter:
let WriteSomething (contents:string) =
let writer = new StreamWriter("")
writer.Write(contents)
let DoStuffWithFileContents =
let reader = new StreamReader("")
let stuff = reader.ReadToEnd()
stuff |> FileContent |> Option.iter(WriteSomething)
By returning ignore on your last line you are returning a function, not a simple value.
The point of ignore is to convert things to (). Your last line can simply return () directly.

Resources