Simple scheduling for short-running Docker containers https://blog.iamthefij.com/2018/11/19/introducing-dockron-scheduling/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

main.go 3.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. "github.com/docker/docker/api/types"
  6. "github.com/docker/docker/client"
  7. "github.com/robfig/cron"
  8. "golang.org/x/net/context"
  9. "os"
  10. "strings"
  11. "time"
  12. )
  13. var (
  14. // defaultWatchInterval is the duration we should sleep until polling Docker
  15. defaultWatchInterval = (1 * time.Minute)
  16. // schedLabel is the string label to search for cron expressions
  17. schedLabel = "dockron.schedule"
  18. // version of dockron being run
  19. version = "dev"
  20. )
  21. // ContainerStartJob represents a scheduled container task
  22. // It contains a reference to a client, the schedule to run on, and the
  23. // ID of that container that should be started
  24. type ContainerStartJob struct {
  25. Client *client.Client
  26. ContainerID string
  27. Context context.Context
  28. Name string
  29. Schedule string
  30. }
  31. // Run is executed based on the ContainerStartJob Schedule and starts the
  32. // container
  33. func (job ContainerStartJob) Run() {
  34. fmt.Println("Starting:", job.Name)
  35. err := job.Client.ContainerStart(job.Context, job.ContainerID, types.ContainerStartOptions{})
  36. if err != nil {
  37. panic(err)
  38. }
  39. }
  40. // QueryScheduledJobs queries Docker for all containers with a schedule and
  41. // returns a list of ContainerStartJob records to be scheduled
  42. func QueryScheduledJobs(cli *client.Client) (jobs []ContainerStartJob) {
  43. fmt.Println("Scanning containers for new schedules...")
  44. containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true})
  45. if err != nil {
  46. panic(err)
  47. }
  48. for _, container := range containers {
  49. if val, ok := container.Labels[schedLabel]; ok {
  50. jobName := strings.Join(container.Names, "/")
  51. jobs = append(jobs, ContainerStartJob{
  52. Schedule: val,
  53. Client: cli,
  54. ContainerID: container.ID,
  55. Context: context.Background(),
  56. Name: jobName,
  57. })
  58. }
  59. }
  60. return
  61. }
  62. // ScheduleJobs accepts a Cron instance and a list of jobs to schedule.
  63. // It then schedules the provided jobs
  64. func ScheduleJobs(c *cron.Cron, jobs []ContainerStartJob) {
  65. for _, job := range jobs {
  66. fmt.Printf("Scheduling %s (%s) with schedule '%s'\n", job.Name, job.ContainerID[:10], job.Schedule)
  67. c.AddJob(job.Schedule, job)
  68. }
  69. }
  70. func main() {
  71. // Get a Docker Client
  72. cli, err := client.NewEnvClient()
  73. if err != nil {
  74. panic(err)
  75. }
  76. // Read interval for polling Docker
  77. var watchInterval time.Duration
  78. flag.DurationVar(&watchInterval, "watch", defaultWatchInterval, "Interval used to poll Docker for changes")
  79. var showVersion = flag.Bool("version", false, "Display the version of dockron and exit")
  80. flag.Parse()
  81. // Print version if asked
  82. if *showVersion {
  83. fmt.Println("Dockron version:", version)
  84. os.Exit(0)
  85. }
  86. // Create a Cron
  87. c := cron.New()
  88. // Start the loop
  89. for {
  90. // HACK: This is risky as it could fall on the same interval as a task and that task would get skipped
  91. // It would be best to manage a ContainerID to Job mapping and then remove entries that are missing
  92. // in the new list and add new entries. However, cron does not support this yet.
  93. // Stop and create a new cron
  94. c.Stop()
  95. c = cron.New()
  96. // Schedule jobs again
  97. jobs := QueryScheduledJobs(cli)
  98. ScheduleJobs(c, jobs)
  99. c.Start()
  100. // Sleep until the next query time
  101. time.Sleep(watchInterval)
  102. }
  103. }