Last active
November 13, 2016 00:53
-
-
Save kflu/0fe529507efe993e8af85f80c9056218 to your computer and use it in GitHub Desktop.
schedule.fsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(* 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