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

added a periodic worker #469

Merged
merged 5 commits into from Aug 13, 2014
Merged

added a periodic worker #469

merged 5 commits into from Aug 13, 2014

Conversation

mattyw
Copy link
Contributor

@mattyw mattyw commented Aug 5, 2014

The periodic worker will call a function periodically based on an input duration

w := &periodicWorker{}
go func() {
for {
err := doWork(w.tomb.Dying())
Copy link
Contributor

Choose a reason for hiding this comment

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

if err != nil we should kill the tomb and return immediately

@fwereade
Copy link
Contributor

fwereade commented Aug 6, 2014

Thanks, but needs a few tweaks.

for {
err := doWork(w.tomb.Dying())
select {
case <-time.Tick(sleepDuration):
Copy link
Contributor

Choose a reason for hiding this comment

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

time.Tick is wrong here - it creates a new Ticker which is never destroyed,
which could become a serious memory leak

You want to use time.Timer. Something like this, perhaps?

t := time.NewTimer(0)
w := &periodicWorker{}
go func() {
    defer w.tomb.Done()
    for {
        if err := doWork(w.tomb.Dying());  err != nil {
             w.tomb.Kill(err)
             return
        }
        t.Reset(sleepDuration)
        select {
        case <-t.C:
        case <-w.tomb.Dying()
            return
        }
   }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great catch @rogpeppe, thanks very much

@mattyw
Copy link
Contributor Author

mattyw commented Aug 6, 2014

@rogpeppe @fwereade thanks for the feedback. PTAL

case <-w.tomb.Dying():
w.tomb.Kill(tomb.ErrDying)
return
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This feels a little bit off. I'm thinking something more like:

type Callback func(stop <-chan struct{}) error

func NewPeriodicWorker(callback Callback, period time.Duration) Worker {
    w := periodicWorker{}
    go func() {
        defer w.tomb.Done()
        w.tomb.Kill(w.run(callback, period))
    }
    return w
}

func (w *periodicWorker) run(callback Callback, period time.Duration) error {
    tick := time.After(0)
    stop := w.tomb.Dying()
    for {
        select {
        case <-stop:
            return tomb.ErrDying
        case <-tick:
            if err := callback(stop); err != nil {
                return err
            }
            tick = time.After(period)
        }
    }
}

}

w := NewPeriodicWorker(doWork, time.Second)
defer func() { c.Assert(Stop(w), gc.Equals, testError) }()
Copy link
Contributor

Choose a reason for hiding this comment

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

your conscientiousness does you credit, I often get lazy and just skip error checking in those cases. I should stop doing that.

@fwereade
Copy link
Contributor

One significant concern re tomb behaviour, otherwise looking great.


// test we can kill again without a panic
w.Kill()
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This is just what I was looking for, but would you parameterise it on the test error and run it twice please? Just so we can verify the trivial effect of a nil return from a stopped work func.

@fwereade
Copy link
Contributor

LGTM with one trivial variation on a test.

@mattyw
Copy link
Contributor Author

mattyw commented Aug 13, 2014

$$merge$$

@jujubot
Copy link
Collaborator

jujubot commented Aug 13, 2014

Status: merge request accepted. Url: http://juju-ci.vapour.ws:8080/job/github-merge-juju

jujubot added a commit that referenced this pull request Aug 13, 2014
added a periodic worker

The periodic worker will call a function periodically based on an input duration
@jujubot jujubot merged commit 0d6e898 into juju:master Aug 13, 2014
@mattyw mattyw deleted the add-periodic-worker branch August 13, 2014 13:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants