Ejemplo n.º 1
0
func nextRun(schedule string) (int64, error) {
	sched, err := cron.Parse(schedule)
	if err != nil {
		return 0, err
	}
	return sched.Next(time.Now().UTC()).UnixNano(), nil
}
//create a schdule with the cmd ID (overrides old ones) and
func (sched *Scheduler) Add(cmd *core.Command) (interface{}, error) {
	defer sched.restart()

	db := sched.pool.Get()
	defer db.Close()

	job := &SchedulerJob{}

	err := json.Unmarshal([]byte(cmd.Data), job)

	if err != nil {
		log.Println("Failed to load command spec", cmd.Data, err)
		return nil, err
	}

	_, err = cron.Parse(job.Cron)
	if err != nil {
		return nil, err
	}

	job.ID = cmd.ID
	//we can safely push the command to the hashset now.
	db.Do("HSET", hashScheduleKey, cmd.ID, cmd.Data)

	return true, nil
}
Ejemplo n.º 3
0
// ValidCron checks if the syntax of value is valid for a cron job
func ValidCron(value string) error {
	_, err := cron.Parse(value)
	if err != nil {
		return errors.New(notValidCron)
	}
	return nil
}
Ejemplo n.º 4
0
Archivo: main.go Proyecto: rach/pome
func (c *CronValue) Set(value string) error {
	_, err := cron.Parse(value)
	if err != nil {
		return fmt.Errorf("expected cron expression or '@every DURATION' got '%s'", value)
	}
	*c = (CronValue)(value)
	return nil
}
Ejemplo n.º 5
0
func validateScheduleFormat(schedule string, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}
	_, err := cron.Parse(schedule)
	if err != nil {
		allErrs = append(allErrs, field.Invalid(fldPath, schedule, err.Error()))
	}

	return allErrs
}
Ejemplo n.º 6
0
// Validate returns error if cron entry dosn't match crontab format
func (c *CronSchedule) Validate() error {
	if c.entry == "" {
		return ErrMissingCronEntry
	}
	_, err := cron.Parse(c.entry)
	if err != nil {
		return err
	}
	return nil
}
Ejemplo n.º 7
0
func Schedule(spec string, job cron.Job) {
	// Look to see if given spec is a key from the Config.
	if strings.HasPrefix(spec, "cron.") {
		confSpec, found := revel.Config.String(spec)
		if !found {
			panic("Cron spec not found: " + spec)
		}
		spec = confSpec
	}
	MainCron.Schedule(cron.Parse(spec), New(job))
}
Ejemplo n.º 8
0
func newJob(id string, pri int) *Job {
	sch, _ := cron.Parse("* * * * *")
	// subtract priority from fixed last run, so higher priority jobs were last run further back in time
	t_last_run := time.Unix(1437856044-int64(pri), 0)
	return &Job{
		Id:                  id,
		t_schedule:          sch,
		t_last_run:          &t_last_run,
		scheduling_priority: NormalPriority,
	}
}
Ejemplo n.º 9
0
func (k *Keeper) PutTask(name string, t Task) error {
	k.tkmu.Lock()
	defer k.tkmu.Unlock()
	if name != t.Name {
		return errors.New("Task name not correct")
	}
	if _, err := cron.Parse(t.Schedule); err != nil {
		return err
	}
	k.tasks[name] = t
	k.reloadCron()
	return k.save()
}
Ejemplo n.º 10
0
func validateScheduleFormat(schedule string, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}
	// TODO soltysh: this should be removed when https://github.com/robfig/cron/issues/58 is fixed
	tmpSchedule := schedule
	if len(schedule) > 0 && schedule[0] != '@' {
		tmpSchedule = "0 " + schedule
	}
	if _, err := cron.Parse(tmpSchedule); err != nil {
		allErrs = append(allErrs, field.Invalid(fldPath, schedule, err.Error()))
	}

	return allErrs
}
Ejemplo n.º 11
0
func UpdateSchedule(s *spec.Schedule) error {
	_, err := cron.Parse(s.String())
	if err != nil {
		return err
	}

	if err = gDb.UpdateSchedule(s); err != nil {
		return err
	}

	schedules.Stop()
	return initCron()
}
Ejemplo n.º 12
0
// getRecentUnmetScheduleTimes gets a slice of times (from oldest to latest) that have passed when a Job should have started but did not.
//
// If there are too many (>100) unstarted times, just give up and return an empty slice.
// If there were missed times prior to the last known start time, then those are not returned.
func getRecentUnmetScheduleTimes(sj batch.ScheduledJob, now time.Time) ([]time.Time, error) {
	starts := []time.Time{}
	tmpSched := addSeconds(sj.Spec.Schedule)
	sched, err := cron.Parse(tmpSched)
	if err != nil {
		return starts, fmt.Errorf("Unparseable schedule: %s : %s", sj.Spec.Schedule, err)
	}
	var earliestTime time.Time
	if sj.Status.LastScheduleTime != nil {
		earliestTime = sj.Status.LastScheduleTime.Time
	} else {
		// If none found, then this is either a recently created scheduledJob,
		// or the active/completed info was somehow lost (contract for status
		// in kubernetes says it may need to be recreated), or that we have
		// started a job, but have not noticed it yet (distributed systems can
		// have arbitrary delays).  In any case, use the creation time of the
		// ScheduledJob as last known start time.
		earliestTime = sj.ObjectMeta.CreationTimestamp.Time
	}

	if earliestTime.After(now) {
		return []time.Time{}, nil
	}

	for t := sched.Next(earliestTime); !t.After(now); t = sched.Next(t) {
		starts = append(starts, t)
		// An object might miss several starts.  For example, if
		// controller gets wedged on friday at 5:01pm when everyone has
		// gone home, and someone comes in on tuesday AM and discovers
		// the problem and restarts the controller, then all the hourly
		// jobs, more than 80 of them for one hourly scheduledJob, should
		// all start running with no further intervention (if the scheduledJob
		// allows concurrency and late starts).
		//
		// However, if there is a bug somewhere, or incorrect clock
		// on controller's server or apiservers (for setting creationTimestamp)
		// then there could be so many missed start times (it could be off
		// by decades or more), that it would eat up all the CPU and memory
		// of this controller. In that case, we want to not try to list
		// all the misseded start times.
		//
		// I've somewhat arbitrarily picked 100, as more than 80, but
		// but less than "lots".
		if len(starts) > 100 {
			// We can't get the most recent times so just return an empty slice
			return []time.Time{}, fmt.Errorf("Too many missed start times to list")
		}
	}
	return starts, nil
}
Ejemplo n.º 13
0
func (k *Keeper) AddTask(t Task) error {
	k.tkmu.Lock()
	defer k.tkmu.Unlock()
	if _, exists := k.tasks[t.Name]; exists {
		return errors.New("Task name duplicate: " + t.Name)
	}
	if _, err := cron.Parse(t.Schedule); err != nil {
		return err
	}
	t.Enabled = true
	k.tasks[t.Name] = t
	k.reloadCron()
	return k.save()
}
Ejemplo n.º 14
0
// getNextStartTimeAfter gets the latest scheduled start time that is less than "now", or an error.
func getNextStartTimeAfter(schedule string, now time.Time) (time.Time, error) {
	// Using robfig/cron for cron scheduled parsing and next runtime
	// computation. Not using the entire library because:
	// - I want to detect when we missed a runtime due to being down.
	//   - How do I set the time such that I can detect the last known runtime?
	// - I guess the functions could launch a go-routine to start the job and
	// then return.
	// How to handle concurrency control.
	// How to detect changes to schedules or deleted schedules and then
	// update the jobs?
	sched, err := cron.Parse(schedule)
	if err != nil {
		return time.Unix(0, 0), fmt.Errorf("Unparseable schedule: %s : %s", schedule, err)
	}
	return sched.Next(now), nil
}
Ejemplo n.º 15
0
func Schedule(spec string, job cron.Job) error {
	// Look to see if given spec is a key from the Config.
	if strings.HasPrefix(spec, "cron.") {
		confSpec, found := revel.Config.String(spec)
		if !found {
			panic("Cron spec not found: " + spec)
		}
		spec = confSpec
	}
	sched, err := cron.Parse(spec)
	if err != nil {
		return err
	}
	MainCron.Schedule(sched, New(job))
	return nil
}
Ejemplo n.º 16
0
Archivo: job.go Proyecto: kapalhq/mozo
func NewJob(
	id string,
	exec string,
	disabled bool,
	timesToRepeat int64,
	retries uint,
	cronExp string) *Job {
	trigger, _ := cron.Parse(cronExp) // TODO(javier): error handling here

	return &Job{
		Id:               id,
		Exec:             exec,
		Disabled:         disabled,
		TimesToRepeat:    timesToRepeat,
		TimeToRepeatLeft: timesToRepeat,
		TotalRetries:     retries - 1,
		CurrentRetries:   0,
		Trigger:          trigger,
		NextRunAt:        trigger.Next(time.Now().Add(-1 * time.Second)),
	}
}
Ejemplo n.º 17
0
func createTaskUsingWFManifest(ctx *cli.Context) {
	// Get the workflow
	path := ctx.String("workflow-manifest")
	ext := filepath.Ext(path)
	file, e := ioutil.ReadFile(path)

	if !ctx.IsSet("interval") && !ctx.IsSet("i") {
		fmt.Println("Workflow manifest requires interval to be set via flag.")
		os.Exit(1)
	}
	if e != nil {
		fmt.Printf("File error [%s]- %v\n", ext, e)
		os.Exit(1)
	}

	var wf *wmap.WorkflowMap
	switch ext {
	case ".yaml", ".yml":
		// e = yaml.Unmarshal(file, &t)
		wf, e = wmap.FromYaml(file)
		if e != nil {
			fmt.Printf("Error parsing YAML file input - %v\n", e)
			os.Exit(1)
		}
	case ".json":
		wf, e = wmap.FromJson(file)
		// e = json.Unmarshal(file, &t)
		if e != nil {
			fmt.Printf("Error parsing JSON file input - %v\n", e)
			os.Exit(1)
		}
	}
	// Get the task name
	name := ctx.String("name")
	// Get the interval
	isCron := false
	i := ctx.String("interval")
	_, err := time.ParseDuration(i)
	if err != nil {
		// try interpreting interval as cron entry
		_, e := cron.Parse(i)
		if e != nil {
			fmt.Printf("Bad interval format:\nfor simple schedule: %v\nfor cron schedule: %v\n", err, e)
			os.Exit(1)
		}
		isCron = true
	}

	// Deadline for a task
	dl := ctx.String("deadline")

	var sch *client.Schedule
	// None of these mean it is a simple schedule
	if !ctx.IsSet("start-date") && !ctx.IsSet("start-time") && !ctx.IsSet("stop-date") && !ctx.IsSet("stop-time") {
		// Check if duration was set
		if ctx.IsSet("duration") && !isCron {
			d, err := time.ParseDuration(ctx.String("duration"))
			if err != nil {
				fmt.Printf("Bad duration format:\n%v\n", err)
				os.Exit(1)
			}
			start := time.Now().Add(createTaskNowPad)
			stop := start.Add(d)
			sch = &client.Schedule{
				Type:      "windowed",
				Interval:  i,
				StartTime: &start,
				StopTime:  &stop,
			}
		} else {
			// No start or stop and no duration == simple schedule
			t := "simple"
			if isCron {
				// It's a cron schedule, ignore "duration" if set
				t = "cron"
			}
			sch = &client.Schedule{
				Type:     t,
				Interval: i,
			}
		}
	} else {
		// We have some form of windowed schedule
		start := mergeDateTime(
			strings.ToUpper(ctx.String("start-time")),
			strings.ToUpper(ctx.String("start-date")),
		)
		stop := mergeDateTime(
			strings.ToUpper(ctx.String("stop-time")),
			strings.ToUpper(ctx.String("stop-date")),
		)

		// Use duration to create missing start or stop
		if ctx.IsSet("duration") {
			d, err := time.ParseDuration(ctx.String("duration"))
			if err != nil {
				fmt.Printf("Bad duration format:\n%v\n", err)
				os.Exit(1)
			}
			// if start is set and stop is not then use duration to create stop
			if start != nil && stop == nil {
				t := start.Add(d)
				stop = &t
			}
			// if stop is set and start is not then use duration to create start
			if stop != nil && start == nil {
				t := stop.Add(d * -1)
				start = &t
			}
		}
		sch = &client.Schedule{
			Type:      "windowed",
			Interval:  i,
			StartTime: start,
			StopTime:  stop,
		}
	}
	// Create task
	r := pClient.CreateTask(sch, wf, name, dl, !ctx.IsSet("no-start"))
	if r.Err != nil {
		errors := strings.Split(r.Err.Error(), " -- ")
		fmt.Println("Error creating task:")
		for _, err := range errors {
			fmt.Printf("%v\n", err)
		}
		os.Exit(1)
	}
	fmt.Println("Task created")
	fmt.Printf("ID: %s\n", r.ID)
	fmt.Printf("Name: %s\n", r.Name)
	fmt.Printf("State: %s\n", r.State)
}
Ejemplo n.º 18
0
// parse the command-line options and use them to setup a new schedule for this task
func (t *task) setScheduleFromCliOptions(ctx *cli.Context) error {
	// check the start, stop, and duration values to see if we're looking at a windowed schedule (or not)
	// first, get the parameters that define the windowed schedule
	start := mergeDateTime(
		strings.ToUpper(ctx.String("start-time")),
		strings.ToUpper(ctx.String("start-date")),
	)
	stop := mergeDateTime(
		strings.ToUpper(ctx.String("stop-time")),
		strings.ToUpper(ctx.String("stop-date")),
	)
	// Grab the duration string (if one was passed in) and parse it
	durationStr := ctx.String("duration")
	var duration *time.Duration
	if ctx.IsSet("duration") || durationStr != "" {
		d, err := time.ParseDuration(durationStr)
		if err != nil {
			return fmt.Errorf("Usage error (bad duration format); %v", err)
		}
		duration = &d
	}
	// Grab the interval for the schedule (if one was provided). Note that if an
	// interval value was not passed in and there is no interval defined for the
	// schedule associated with this task, it's an error
	interval := ctx.String("interval")
	if !ctx.IsSet("interval") && interval == "" && t.Schedule.Interval == "" {
		return fmt.Errorf("Usage error (missing interval value); when constructing a new task schedule an interval must be provided")
	}
	// if a start, stop, or duration value was provided, or if the existing schedule for this task
	// is 'windowed', then it's a 'windowed' schedule
	isWindowed := (start != nil || stop != nil || duration != nil || t.Schedule.Type == "windowed")
	// if an interval was passed in, then attempt to parse it (first as a duration,
	// then as the definition of a cron job)
	isCron := false
	if interval != "" {
		// first try to parse it as a duration
		_, err := time.ParseDuration(interval)
		if err != nil {
			// if that didn't work, then try parsing the interval as cron job entry
			_, e := cron.Parse(interval)
			if e != nil {
				return fmt.Errorf("Usage error (bad interval value): cannot parse interval value '%v' either as a duration or a cron entry", interval)
			}
			// if it's a 'windowed' schedule, then return an error (we can't use a
			// cron entry interval with a 'windowed' schedule)
			if isWindowed {
				return fmt.Errorf("Usage error; cannot use a cron entry ('%v') as the interval for a 'windowed' schedule", interval)
			}
			isCron = true
		}
		t.Schedule.Interval = interval
	}
	// if it's a 'windowed' schedule, then create a new 'windowed' schedule and add it to
	// the current task; the existing schedule (if on exists) will be replaced by the new
	// schedule in this method (note that it is an error to try to replace an existing
	// schedule with a new schedule of a different type, so an error will be returned from
	// this method call if that is the case)
	if isWindowed {
		return t.setWindowedSchedule(start, stop, duration)
	}
	// if it's not a 'windowed' schedule, then set the schedule type based on the 'isCron' flag,
	// which was set above.
	if isCron {
		// make sure the current schedule type (if there is one) matches; if not it is an error
		if t.Schedule.Type != "" && t.Schedule.Type != "cron" {
			return fmt.Errorf("Usage error; cannot replace existing schedule of type '%v' with a new, 'cron' schedule", t.Schedule.Type)
		}
		t.Schedule.Type = "cron"
		return nil
	}
	// if it wasn't a 'windowed' schedule and it's not a 'cron' schedule, then it must be a 'simple'
	// schedule, so first make sure the current schedule type (if there is one) matches; if not
	// then it's an error
	if t.Schedule.Type != "" && t.Schedule.Type != "simple" {
		return fmt.Errorf("Usage error; cannot replace existing schedule of type '%v' with a new, 'simple' schedule", t.Schedule.Type)
	}
	// if we get this far set the schedule type and return a nil error (indicating success)
	t.Schedule.Type = "simple"
	return nil
}
Ejemplo n.º 19
0
func ParseExpression(expression string) error {
	_, err := cron.Parse(expression)
	return err
}
Ejemplo n.º 20
0
func main() {
	flag.Usage = usage
	flag.Parse()
	args := flag.Args()

	if ver {
		fmt.Println("Version:", version)
		os.Exit(0)
	}
	if hlp {
		usage()
	}

	runMode := run_mode_default
	if cronT != default_cron {
		runMode = run_mode_cron
	} else if timeD != default_time {
		runMode = run_mode_time
	} else if loop != default_loop {
		runMode = run_mode_loop
	} else {
		fmt.Println("do not set -loop, -time or -cron. ant wiil run with default mode(loop once).")
	}
	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, syscall.SIGINT, syscall.SIGKILL)
	defer close(sigCh)
	c := cron.New()

	w, err := filter(args)
	if err != nil {
		fmt.Println(err)
		os.Exit(0)
	}

	if runMode == run_mode_cron {
		// crontab
		schedule, err := cron.Parse(cronT)
		if err != nil {
			fmt.Println(err)
			os.Exit(0)
		}

		c.Schedule(schedule, &moveJob{w})
		c.Start()
		defer c.Stop()
	} else if runMode == run_mode_time {
		// time
		schedule := cron.Every(timeD)
		c := cron.New()
		c.Schedule(schedule, &moveJob{w})
		c.Start()
		defer c.Stop()
	} else if runMode == run_mode_loop {
		// loop
		job := &moveJob{w}
		for i := 0; i < loop; i++ {
			job.Run()
			time.Sleep(5 * time.Second)
		}
		os.Exit(0)
	} else if runMode == run_mode_default {
		// default
		job := &moveJob{w}
		job.Run()
		os.Exit(0)
	} else {
		fmt.Printf("run mode [%d] unknown.\n", runMode)
		os.Exit(0)
	}

	sig := <-sigCh
	fmt.Println("Got signal:", sig)
}