Skip to content

Instantly share code, notes, and snippets.

@kflu
Last active November 13, 2016 00:53
Show Gist options
  • Save kflu/0fe529507efe993e8af85f80c9056218 to your computer and use it in GitHub Desktop.
Save kflu/0fe529507efe993e8af85f80c9056218 to your computer and use it in GitHub Desktop.
schedule.fsx
(* Run process on a schedule
Given a process (and arguments) and a schedule, it ensures that the process is run on the schedule:
If the process is not run when it should, it's started
If the process is running when it shouldn't, it's killed
*)
module Schedule =
open System
open System.Diagnostics
open System.IO
let DUARTION = 60*1000;
module Schedules =
let schedule_midnight (time: DateTime) =
let time = time.TimeOfDay
if (TimeSpan.FromHours(1.5) < time && time < TimeSpan.FromHours(6.5)) then true else false
let schedule_always (time: DateTime) = true
let schedule_toggle () =
let mutable state = true
fun (time:DateTime) ->
let res = state
state <- (not state)
res
module Apps =
let run_rclone () = new ProcessStartInfo("rclone", "copy G:\\album amazon:/albumn --verbose --retries 999")
let run_rclone_mypassport () = new ProcessStartInfo("rclone", "copy H:\\album amazon:/backup/MYPASSPORT --verbose --retries 999")
let run_notepad () = new ProcessStartInfo("notepad")
let run_foo () = new ProcessStartInfo("powershell", "foo.ps1")
module Utils =
let log msg = printfn "[%A] %s" (DateTime.Now) msg
let configProc (proc: ProcessStartInfo) =
proc.RedirectStandardError <- true
proc.RedirectStandardOutput <- true
proc.UseShellExecute <- false
proc
let getProc (id: int) =
try
Process.GetProcessById id |> Some
with
| ex ->
sprintf "Error getting proc by ID (%A): %A" id ex |> log
None
let out = Console.OpenStandardOutput()
let err = Console.OpenStandardError()
let bufsize = 1024
let handleIO (reader : StreamReader) (writer : TextWriter) =
async {
let buf = Array.zeroCreate<char>(bufsize)
let! count = reader.ReadAsync(buf, 0, bufsize) |> Async.AwaitTask
do! writer.WriteAsync(buf, 0, count) |> Async.AwaitTask
}
type State = {ShouldRun: bool; PID: int option}
open Utils
let rec run schedule target pid =
async {
let now = DateTime.Now
let shouldRun = schedule now
sprintf "%A" {ShouldRun = shouldRun; PID = pid} |> log
let pid =
if shouldRun then
if pid.IsNone then
let proc = Process.Start(target() |> configProc)
sprintf "Process started: %A" proc.Id |> log
async {
while (not proc.HasExited) do
do! handleIO proc.StandardOutput Console.Out
try proc.Dispose() with _ -> ()
} |> Async.Start
async {
while (not proc.HasExited) do
do! handleIO proc.StandardError Console.Error
try proc.Dispose() with _ -> ()
} |> Async.Start
Some (proc.Id)
else
match getProc pid.Value with
| None ->
log "Couldn't find process by ID. Will start one on next checkpoint"
None
| _ -> pid
else // should NOT run:
if pid.IsSome then
match getProc pid.Value with
| Some proc ->
log "killing process"
proc.Kill()
proc.WaitForExit()
| None -> ()
None
sprintf "Sleeping %A ms" DUARTION |> log
do! Async.Sleep (DUARTION)
do! run schedule target pid
}
//run (Schedules.schedule_toggle()) Apps.run_rclone None |> Async.RunSynchronously
//run (Schedules.schedule_midnight) Apps.run_rclone None |> Async.RunSynchronously
run (Schedules.schedule_midnight) Apps.run_rclone_mypassport None |> Async.RunSynchronously
//run (Schedules.schedule_always) Apps.run_rclone None |> Async.RunSynchronously
//run (Schedules.schedule_toggle()) Apps.run_notepad None |> Async.RunSynchronously
//run (Schedules.schedule_toggle()) Apps.run_foo None |> Async.RunSynchronously
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment