I have F# function 'is_up' to ping the ip like below which works fine in FSI REPL(interactive), giving i.e. true for 8.8.8.8 and false for 8.8.8.1
let pingSender = new Ping()
let is_up (t:int) (ip:string) =
let reply = pingSender.Send(IPAddress.Parse(ip),t)
reply.Status = IPStatus.Success
but not from main. Here I am always getting 'is down'
[<EntryPoint>]
let main argv =
let mutable ip = argv.[0];
if is_up 3 ip then
printfn "Host %A is up" ip
else
printfn "Host %A is down" ip
1
The second parameter of your Ping.Send() overload is given in milliseconds (source). Google servers are fast, but I doubt they are that fast.
I bet you are getting the reply status as IPStatus.TimedOut (source). Try increasing the timeout value.
Related
I am using Playwright in F# for web scrapping and I noticed that result is returned randomly.
I have this code.
let getContent (url:string) =
task{
use! paywright = Playwright.CreateAsync()
let! browser = paywright.Chromium.LaunchAsync()
printfn "URL %A" url
let! page = browser.NewPageAsync()
page.SetDefaultTimeout(15000f)
let! goto = page.GotoAsync(url)
let! price = page.Locator("//span[#class='norm-price ng-binding']").AllInnerTextsAsync()
printfn "Price %A" price
}
When I run the console program sometimes it returns result (list of prices), but sometimes its just finished with empty result.
I really dont know what can be wrong. I also try use async wrapper instead of task but the output is same.
The delay I increase to 15s, but it also doesnt help.
Could it be that you do not await the task returned by getContent?
Maybe the program terminates before writing to the console. If the calling code is not asynchronous (and cannot propagate the task), you could try:
let printContent (url : string) =
task { ... } |> Task.RunSynchronously
Update 1:
Probably the page loads it's price data asynchronously.The default timeout on the page is there to specify a maximum timeout, not to wait that long for some data to arrive in the controlled browser instance. Most likely you'll have to wait for some request to finish or some element to appear on the page. Can you share the URL publicly?
I've spent hours combing through documentation and tutorials, but can't figure out how to use ReactiveX to poll an external resource, or anything for that matter, every at an interval. Below is some code I wrote to get information from a REST API at an interval.
open System
open System.Reactive.Linq
module MyObservable =
let getResources =
async {
use client = new HttpClient()
let! response = client.GetStringAsync("http://localhost:8080/items") |> Async.AwaitTask
return response
} |> Async.StartAsTask
let getObservable (interval: TimeSpan) =
let f () = getResources.Result
Observable.Interval(interval)
|> Observable.map(fun _ -> f ())
To test this out, I tried subscribing to the Observable and waiting five seconds. It does receive something every second for five seconds, but the getResources is only called the first time and then the result is just used at each interval. How can I modify this to make the REST call at each interval instead of just the result of the first call being used over and over again?
let mutable res = Seq.empty
getObservable (new TimeSpan(0,0,1))
|> Observable.subscribe(fun (x: seq<string>) -> res <- res |> Seq.append x;)
|> ignore
Threading.Thread.Sleep(5000)
Don't use a Task. Tasks are what we call "hot", meaning that if you have a value of type Task in your hand, it means that the task is already running, and there is nothing you can do about it. In particular, this means you cannot restart it, or start a second instance of it. Once a Task is created, it's too late.
In your particular case it means that getResources is not "a way to start a task", but just "a task". Already started, already running.
If you want to start a new task every time, you have two alternatives:
First (the worse alternative), you could make getResources a function rather than a value, which you can do by giving it a parameter:
let getResources () =
async { ...
And then call it with that parameter:
let f () = getResources().Result
This will run the getResources function afresh every time you call f(), which will create a new Task every time and start it.
Second (a better option), don't use a Task at all. You're creating a perfectly good async computation and then turning it into a Task only to block on getting its result. Why? You can block on an async's result just as well!
let getResources = async { ... }
let getObservable interval =
let f () = getResources |> Async.RunSynchronously
...
This works, even though getResources is not a function, because asyncs, unlike Tasks, are what we call "cold". This means that, if you have an async in your hand, it doesn't mean that it's already running. async, unlike Task, represents not an "already running" computation, but rather "a way to start a computation". A corollary is that you can start it multiple times from the same async value.
One way to start it is via Async.RunSynchronously as I'm doing in my example above. This is not the best way, because it blocks the current thread until the computation is done, but it's equivalent to what you were doing with accessing the Task.Result property, which also blocks until the Task is done.
Knowing an RPC call to a server method that returns unit is a message passing call, I want to force the call to be asynchronous and be able to fire the next server call only after the first one has gone to the server.
Server code:
[<Rpc>]
let FirstCall value =
printfn "%s" value
async.Zero()
[<Rpc>]
let SecondCall() =
"test"
Client code:
|>! OnClick (fun _ _ -> async {
do! Server.FirstCall "test"
do Server.SecondCall() |> ignore
} |> Async.Start)
This seems to crash on the client since returning unit, replacing the server and client code to:
[<Rpc>]
let FirstCall value =
printfn "%s" value
async { return () }
let! _ = Server.FirstCall "test"
Didn't fix the problem, while the following did:
[<Rpc>]
let FirstCall value =
printfn "%s" value
async { return "" }
let! _ = Server.FirstCall "test"
Is there another way to force a message passing call to be asynchronous instead?
This is most definitely a bug. I added it here:
https://bugs.intellifactory.com/websharper/show_bug.cgi?id=468
Your approach is completely legit. Your workaround is also probably the best for now, e.g. instead of returning Async<unit> return Async<int> with a zero and ignore it.
We are busy with preparing the 2.4 release due next week and the fix will make it there. Thanks!
Also, in 2.4 we'll be dropping synchronous calls, so you will have to use Async throughout for RPC, as discussed in https://bugs.intellifactory.com/websharper/show_bug.cgi?id=467 -- primarily motivated by new targets (Android and WP7) that do not support sync AJAX.
I was going through one of Don Syme's blog posts Async and Parallel Design Patterns in F#: Agents. However, the following seemingly extremely simple code did not generate output as expected.
type Agent<'T> = MailboxProcessor<'T>
let agent =
Agent.Start(fun inbox ->
async { while true do
let! msg = inbox.Receive()
printfn "got message '%s'" msg } )
for i in 1 .. 10000 do
agent.Post (sprintf "message %d" i)
Instead of expected 10,000 messages , I only got something around 3000 messages using Mono 2.8.1 under Ubuntu, or 15 messages using Visual F# under Windows XP. Am I missing anything here? BTW, I tried to replace the printfn statement with the following File op and ended up with same partial results.
open System.IO
type Agent<'T> = MailboxProcessor<'T>
let agent =
Agent.Start(fun inbox ->
async { while true do
let! msg = inbox.Receive()
use logger = new StreamWriter("a.log", true)
logger.WriteLine("got message '{0}'", msg.ToString())
logger.Close()
} )
for i in 1 .. 10000 do
agent.Post (sprintf "message %d" i)
Just run your code in Win machine - everything is OK. Try to add
ignore( System.Console.ReadKey() )
as a last line, because agent.Post is non-blocking and after posting 10000 messages control flow will move forward, possibly exiting the program.
I am new to F#. I am trying to communicate with java from F# using named pipe. The code below works but I am not sure if there is a better way to do this (I know the infinite loop is a bad idea but this is just a proof of concept) if anyone have any idea to improve this code please post your comments.
Thanks in advance
Sudaly
open System.IO
open System.IO.Pipes
exception OuterError of string
let continueLooping = true
while continueLooping do
let pipeServer = new NamedPipeServerStream("testpipe", PipeDirection.InOut, 4)
printfn "[F#] NamedPipeServerStream thread created."
//wait for connection
printfn "[F#] Wait for a client to connect"
pipeServer.WaitForConnection()
printfn "[F#] Client connected."
try
// Stream for the request.
let sr = new StreamReader(pipeServer)
// Stream for the response.
let sw = new StreamWriter(pipeServer)
sw.AutoFlush <- true;
// Read request from the stream.
let echo = sr.ReadLine();
printfn "[F#] Request message: %s" echo
// Write response to the stream.
sw.WriteLine("[F#]: " + echo)
pipeServer.Disconnect()
with
| OuterError(str) -> printfn "[F#]ERROR: %s" str
printfn "[F#] Client Closing."
pipeServer.Close()
Well, it doesn't look like anything is throwing OuterError, so I would remove that exception type and unused handling.
I am unsure about your experience level or what type of "better" you are looking for. You way want to read F# async on the server to learn more about async and avoiding blocking threads.
Below you can find a few modifications to your code. Your question is pretty vague so I can't tell exactly where you're wishing to improve your code, but my suggestion uses recursion instead of the while loop (don't worry about stack overflows, F# can handle recursion very well and the whole recursive bit will be optimized into a loop at compile time), makes use of the use keyword (like C#'s using) and will swallow any exception happening in the process of the communication with the client. If an exception occurs, the server will not listen for other connections.
open System.IO
open System.IO.Pipes
let main() =
printfn "[F#] NamedPipeServerStream thread created."
let pipeServer = new NamedPipeServerStream("testpipe", PipeDirection.InOut, 4)
let rec loop() =
//wait for connection
printfn "[F#] Wait for a client to connect"
pipeServer.WaitForConnection()
printfn "[F#] Client connected."
try
// Stream for the request.
use sr = new StreamReader(pipeServer)
// Stream for the response.
use sw = new StreamWriter(pipeServer, AutoFlush = true)
// Read request from the stream.
let echo = sr.ReadLine();
printfn "[F#] Request message: %s" echo
// Write response to the stream.
echo |> sprintf "[F#]: %s" |> sw.WriteLine
pipeServer.Disconnect()
if [A CONDITION WHICH TELLS YOU THAT YOU WANT ANOTHER CONNECTION FROM THE CLIENT] then loop()
with
| _ as e -> printfn "[F#]ERROR: %s" e.Message
loop()
printfn "[F#] Client Closing."
pipeServer.Close()
Also please notice how the AutoFlush is set within the call to the constructor and how the pipeline operator is used to write the echo to the pipe, resulting in what looks (in my opinion) like cleaner code.