-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathProgram.fs
88 lines (76 loc) · 2.9 KB
/
Program.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// Learn more about F# at http://fsharp.org
open System
open System.Threading
open Suave
open Suave.Operators
open Suave.Successful
open Suave.Filters
/// Handler for /info - for demo purposes, so we can easily get the PID and a
/// little other infomation.
let info =
use p = System.Diagnostics.Process.GetCurrentProcess ()
let assemblies = AppDomain.CurrentDomain.GetAssemblies() |> Array.map(fun a -> sprintf "\t%s" a.FullName) |> String.concat "\n"
sprintf "PID: %d\nMemory: %d\nCPU: %O\nAssemblies:\n%s\n" p.Id p.WorkingSet64 p.TotalProcessorTime assemblies
let cts = new CancellationTokenSource ()
/// Don't normally create an endpoint that will kill the service. This is here
/// so we can create chaos and demonstrate resiliency.
let die () =
// lsof -i tcp:8080 # shows running socket
// curl -X POST http://localhost:8080/die
cts.Cancel ()
System.Environment.Exit (0)
"shutting down"
/// Don't normally create an endpoint that will zombie the service either.
/// This one kills the Suave listener, but the process still runs, illustrating
/// the need for an HTTP health check.
let zombie () =
cts.Cancel ()
"shutting down"
let rec fib (n:uint32) =
match n with
| 0u | 1u -> n
| _ -> fib (n-1u) + fib (n-2u)
/// Nice CPU eating service in case we want to show it die in the middle of
/// processing a request.
let fibHandler num =
fun (ctx:HttpContext) ->
async {
let result = fib num |> sprintf "%d"
return! OK result ctx
}
let app : WebPart =
choose [
path "/healthcheck" >=> GET >=> OK "OK"
path "/info" >=> GET >=> request (fun r -> OK info)
path "/die" >=> POST >=> request (fun r -> OK (die ()))
path "/zombie" >=> POST >=> request (fun r -> OK (zombie ()))
GET >=> pathScan "/fib/%d" fibHandler
RequestErrors.NOT_FOUND "nobody here"
]
[<EntryPoint>]
let main argv =
let config = {
defaultConfig with
cancellationToken = cts.Token
bindings = [HttpBinding.create HTTP (System.Net.IPAddress.Parse("0.0.0.0")) 8080us]
}
let listening, server = startWebServerAsync config app
Async.Start (server, cts.Token)
// How we wait is platform-specific
// dotnet catches SIGTERM:
#if !NET462
use wait = new ManualResetEventSlim ()
System.Runtime.Loader.AssemblyLoadContext.Default.add_Unloading(
fun ctx ->
printfn "Shutting down..."
wait.Set ()
)
wait.Wait ()
#else
// mono needs to be told to catch it (no System.Runtime.Loader).
let signals = [| new Mono.Unix.UnixSignal(Mono.Unix.Native.Signum.SIGTERM) |]
Mono.Unix.UnixSignal.WaitAny (signals, -1) |> ignore
#endif
// finally after a SIGTERM we fall through and cancel the service.
cts.Cancel ()
0