Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update cron schedule #274

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

pradykaushik
Copy link

Added a function Cron.UpdateSchedule(id, spec) that can be used
to update the schedule of the cron job associated with the given id.
The following changes/additions were made.

  1. To allow for constant time lookup, added a new member to Cron.
    entryLookupTable map[EntryID]*Entry

  2. Added a new function, addNewEntry(*Entry) that not only appends
    the entry to the list of entries but also adds it to the
    entryLookupTable.

  3. Retrofitted Cron.Schedule() and Cron.run() to now use
    Cron.addNewEntry() instead of directly appending Cron.entries.

  4. Retrofitted Cron.removeEntry() to also delete the entry from
    entryLookupTable.

Added test coverage for cron.UpdateSchedule(id, spec).
The following tests were added.

  1. Update the schedule without calling cron.Start() and verify if
    the schedule interval changed.
  2. Update the schedule while the cron job is running (after calling
    cron.Start()) and verify if the schedule interval changed.

Added a function Cron.UpdateSchedule(id, spec) that can be used
to update the schedule of the cron job associated with the given id.
The following changes/additions were made.
1. To allow for constant time lookup, added a new member to Cron.
	entryLookupTable map[EntryID]*Entry

2. Added a new function, addNewEntry(*Entry) that not only appends
the entry to the list of entries but also adds it to the
entryLookupTable.

3. Retrofitted Cron.Schedule() and Cron.run() to now use
Cron.addNewEntry() instead of directly appending Cron.entries.

4. Retrofitted Cron.removeEntry() to also delete the entry from
entryLookupTable.

Added test coverage for cron.UpdateSchedule(id, spec).
The following tests were added.
1. Update the schedule without calling cron.Start() and verify if
the schedule interval changed.
2. Update the schedule while the cron job is running (after calling
cron.Start()) and verify if the schedule interval changed.
cron.go Outdated Show resolved Hide resolved
cron.go Outdated
nextID EntryID
jobWaiter sync.WaitGroup
entries []*Entry
// entriesLookupTable can be used for constant time lookup of entries.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

entriesLookupTable is not necessary for your change, so I'd prefer to leave it out. Storing entries in a data structure other than a slice is a possible area for improvement, but it's not in scope for this change and has other considerations.

cron.go Outdated
return errors.Wrap(err, fmt.Sprintf("could not update schedule for job %d", id))
}
if entry, ok := c.entryLookupTable[id]; ok {
entry.Schedule = schedule
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a data race, because there is no synchronization between this and run(). (Is it caught by go test -race?) I think you will have to take a similar approach as in Schedule() and send the update on a channel if the cron is already running.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right! I have fixed this.

cron_test.go Outdated
@@ -3,6 +3,7 @@ package cron
import (
"bytes"
"fmt"
"github.com/stretchr/testify/assert"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No new dependencies, sorry

cron.go Outdated
} else {
c.add <- entry
}
return entry.ID
}

func (c *Cron) UpdateSchedule(id EntryID, spec string) error {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we may need to offer a way to Update using a Schedule instead of just a spec string, similar to how you can add a job using either.

Perhaps named Update and UpdateSchedule ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. I have added in the support for the same.

cron.go Outdated
if entry, ok := c.entryLookupTable[id]; ok {
entry.Schedule = schedule
// Updating entry.Next as it might now be stale.
entry.Next = entry.Schedule.Next(c.now())
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't work -- you can verify that by adding a job with a schedule that doesn't fire for a long time, and then update it to fire immediately. It will not be run. If cron is running already, it is blocked until the next time a schedule was active, expected to be at the beginning of the entries slice. That has to be recalculated when an update happens.

I think that also points to gaps in the test coverage.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch :) I have now made sure that the entries are reordered and that the timer is reinitialized so that the updated schedule is accommodated.

Made sure that the new schedule is forwarded via channels to ensure
that there isn't any race condition.
After updating entry.Schedule and entry.Next, the entries are reordered
as entries[0] might no longer be the next entry to run. With this,
the timer is also reinitialized.
Got rid of entriesLookupTable as it is not necessary for this change.

Added support for passing either a spec string or a Schedule when
updating the schedule of an entry.

Updated test code to test that the schedule indeed was updated and
that the timer was reinitialized.

Got rid of the following dependencies.
1. github.com/stretchr/testify/assert
2. github.com/pkg/errors

Ran "go test" and "go test -race" on the project.
@pradykaushik
Copy link
Author

@robfig I have made the changes you requested.

@pradykaushik
Copy link
Author

@robfig - this is a gentle reminder for reviewing this PR :).

@pradykaushik
Copy link
Author

@robfig let me know if you would want me to update the documentation to include UpdateSchedule(...) usage in the README.

@mghifariyusuf
Copy link

when people can use this method? ;)

@ahmagdy
Copy link

ahmagdy commented May 22, 2020

Hi @robfig
Can you take a look at the PR?
Thanks.

@l0010o0001l
Copy link

Bump.

@phpmaple
Copy link

why don't merge to master?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants