├── History.md ├── Readme.md └── every.go /History.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | 2 | # go-every 3 | 4 | Run some command at a given interval. Mostly because CRON drives me nuts. 5 | 6 | ## Installation 7 | 8 | ``` 9 | $ go get github.com/visionmedia/go-every 10 | ``` 11 | 12 | ## Usage 13 | 14 | ``` 15 | 16 | Usage: every [options] 17 | 18 | Options: 19 | 20 | --no-stdout suppress command stdout 21 | --no-stderr suppress command stderr 22 | --quiet implies --no-{stdout,stderr} 23 | --exit exit on error 24 | 25 | ``` 26 | 27 | ## Examples 28 | 29 | Running a backup: 30 | 31 | ``` 32 | $ every 1h do-redis-backup /data/dump.rdb 33 | ``` 34 | 35 | Commands are passed through `sh(1)` so you may utilize 36 | shell features such as globbing. 37 | 38 | ``` 39 | $ every 1m "sudo rm -fr /tmp/something/*" 40 | ``` 41 | 42 | ## Options 43 | 44 | By default command stdio is piped through for display, and command failures are simply logged and ignored. If you wish to exit on failure use `--exit`. 45 | 46 | ``` 47 | $ every 500ms echo hello 48 | 2014/06/19 09:33:42 every 500ms running `echo [hello]` 49 | 2014/06/19 09:33:42 exec `echo [hello]` 50 | hello 51 | 2014/06/19 09:33:42 pid 2850 completed in 3.705087ms 52 | 2014/06/19 09:33:43 exec `echo [hello]` 53 | hello 54 | 2014/06/19 09:33:43 pid 2851 completed in 3.306653ms 55 | 2014/06/19 09:33:43 exec `echo [hello]` 56 | hello 57 | 2014/06/19 09:33:43 pid 2852 completed in 3.379814ms 58 | 2014/06/19 09:33:44 exec `echo [hello]` 59 | hello 60 | 2014/06/19 09:33:44 pid 2853 completed in 3.744ms 61 | 2014/06/19 09:33:44 exec `echo [hello]` 62 | hello 63 | 2014/06/19 09:33:44 pid 2854 completed in 4.0207ms 64 | 2014/06/19 09:33:45 exec `echo [hello]` 65 | hello 66 | 2014/06/19 09:33:45 pid 2855 completed in 4.276799ms 67 | 2014/06/19 09:33:45 exec `echo [hello]` 68 | hello 69 | 2014/06/19 09:33:45 pid 2856 completed in 3.821379ms 70 | 2014/06/19 09:33:46 exec `echo [hello]` 71 | hello 72 | 2014/06/19 09:33:46 pid 2857 completed in 3.712612ms 73 | ``` 74 | 75 | # License 76 | 77 | MIT -------------------------------------------------------------------------------- /every.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "strings" 4 | import "os/exec" 5 | import "flag" 6 | import "time" 7 | import "log" 8 | import "fmt" 9 | import "os" 10 | 11 | // 12 | // Usage 13 | // 14 | 15 | const usage = ` 16 | Usage: every [options] 17 | 18 | Options: 19 | 20 | --no-stdout suppress command stdout 21 | --no-stderr suppress command stderr 22 | --quiet implies --no-{stdout,stderr} 23 | --exit exit on error 24 | 25 | Examples: 26 | 27 | $ every 5s redis-backup /data/dump.rdb 28 | ` 29 | 30 | // 31 | // Options 32 | // 33 | 34 | var flags = flag.NewFlagSet("every", flag.ContinueOnError) 35 | var nostdout = flags.Bool("no-stdout", false, "") 36 | var nostderr = flags.Bool("no-stderr", false, "") 37 | var quiet = flags.Bool("quiet", false, "") 38 | var exit = flags.Bool("exit", false, "") 39 | 40 | // 41 | // Print usage and exit 42 | // 43 | 44 | func printUsage() { 45 | fmt.Println(usage) 46 | os.Exit(0) 47 | } 48 | 49 | // 50 | // Check `err` 51 | // 52 | 53 | func check(err error) { 54 | if err != nil { 55 | log.Fatalf("Error: %s", err) 56 | } 57 | } 58 | 59 | // 60 | // Main. 61 | // 62 | 63 | func main() { 64 | flags.Usage = printUsage 65 | flags.Parse(os.Args[1:]) 66 | argv := flags.Args() 67 | 68 | // quiet 69 | if *quiet { 70 | *nostdout = true 71 | *nostderr = true 72 | } 73 | 74 | // interval 75 | if len(argv) < 1 { 76 | check(fmt.Errorf(" required")) 77 | } 78 | 79 | interval, err := time.ParseDuration(argv[0]) 80 | check(err) 81 | 82 | // command 83 | if len(argv) < 2 { 84 | check(fmt.Errorf(" required")) 85 | } 86 | 87 | // command name and args 88 | cmd := strings.Join(argv[1:], " ") 89 | 90 | // run 91 | log.Printf("every %s running `%s`", interval, cmd) 92 | 93 | for { 94 | time.Sleep(interval) 95 | start := time.Now() 96 | log.Printf("exec `%s`", cmd) 97 | proc := exec.Command("/bin/sh", "-c", cmd) 98 | 99 | if !*nostdout { 100 | proc.Stdout = os.Stdout 101 | } 102 | 103 | if !*nostderr { 104 | proc.Stderr = os.Stderr 105 | } 106 | 107 | proc.Start() 108 | err := proc.Wait() 109 | ps := proc.ProcessState 110 | 111 | if err != nil { 112 | log.Printf("pid %d failed with %s", ps.Pid(), ps.String()) 113 | if *exit { 114 | os.Exit(1) 115 | } 116 | continue 117 | } 118 | 119 | log.Printf("pid %d completed in %s", ps.Pid(), time.Since(start)) 120 | } 121 | } 122 | --------------------------------------------------------------------------------