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

ScheduledReporter.start() starts with undesired delay #999

Merged
merged 11 commits into from
Jan 9, 2017

Conversation

sofax
Copy link
Contributor

@sofax sofax commented Aug 16, 2016

ScheduledReporter.start() incorrectly uses the interval size for the start delay, too:

    public void start(long period, TimeUnit unit) {
        executor.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                try {
                    report();
                } catch (RuntimeException ex) {
                    LOG.error("RuntimeException thrown from {}#report. Exception was suppressed.", ScheduledReporter.this.getClass().getSimpleName(), ex);
                }
            }
        }, period, period, unit);
    }

This is a serious problem when the interval is sufficiently big. I suggest to add an alternative version of ScheduledReporter.start() to fix the bug without affecting code that relies on this behavior:

    public void start(long period, long initialDelay, TimeUnit unit) {
        executor.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                try {
                    report();
                } catch (RuntimeException ex) {
                    LOG.error("RuntimeException thrown from {}#report. Exception was suppressed.", ScheduledReporter.this.getClass().getSimpleName(), ex);
                }
            }
        }, initialDelay, period, unit);
    }

@ryantenney ryantenney changed the title Pull request for https://github.com/dropwizard/metrics/issues/998 ScheduledReporter.start() starts with undesired delay Aug 16, 2016
@arteam
Copy link
Member

arteam commented Jan 5, 2017

Hello @sofax,

Sorry to get back to you late. I like your pull request, could you please rebase it against the 3.2-development branch? Due changes from another pull requests (respectively #1018), it now has merge conflicts and can't be merged. Thank you.

Copy link
Member

@arteam arteam left a comment

Choose a reason for hiding this comment

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

Thanks for actualizing your changes! I've added a couple of comments regarding the implementation.

* @param initialDelay the time to delay the first execution
* @param unit the unit for {@code period}
*/
public void start(long period, long initialDelay, TimeUnit unit) {
Copy link
Member

Choose a reason for hiding this comment

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

I think it would be better to change the order of parameters, so initialDelay comes first, to maintain the same order as in the scheduleAtFixedRate method.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed. :)

* @param unit the unit for {@code period}
*/
public void start(long period, long initialDelay, TimeUnit unit) {
executor.scheduleAtFixedRate(new Runnable() {
Copy link
Member

Choose a reason for hiding this comment

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

I think we could avoid duplication and implement the method as:

synchronized public void start(long initialDelay, long period, TimeUnit unit) {
        if (this.scheduledFuture != null) {
            throw new IllegalArgumentException("Reporter already started");
        }
        this.scheduledFuture = executor.scheduleAtFixedRate(new Runnable() {
           @Override
           public void run() {
               try {
                   report();
               } catch (RuntimeException ex) {
                   LOG.error("RuntimeException thrown from {}#report. Exception was suppressed.", ScheduledReporter.this.getClass().getSimpleName(), ex);
               }
           }
       }, initialDelay, period, unit);
   }

as then make the start(long period, TimeUnit unit) method to delegate to it as

start(period, period, unit)

Copy link
Contributor Author

@sofax sofax Jan 9, 2017

Choose a reason for hiding this comment

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

Again, agreed.

The lines

        if (this.scheduledFuture != null) {
            throw new IllegalArgumentException("Reporter already started");
        }

are new, but they do look reasonable to me.

@@ -64,6 +64,9 @@ protected String getAllowedOrigin() {

/**
* Returns the name of the parameter used to specify the jsonp callback, if any.
*
Copy link
Member

Choose a reason for hiding this comment

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

It seems to me as an unrelated change. Could you please revert it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry, already working on it - it got pushed too soon.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This change has been reverted.

@@ -145,6 +145,26 @@ public void run() {
}

/**
* Starts the reporter polling at the given period.
Copy link
Member

Choose a reason for hiding this comment

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

Could you add a simple unit test to ScheduledReporterTest? A simple test which verifies that the scheduler wakes up with a correct initial delay. Very similar to the pollsPeriodically test.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will do. All those tests are a little bit unreliable though, as the executor services rely on the system time instead of using a dedicated (mockable) clock.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, instead of waiting for the reporter to actually do its work, it would be much better to just verify that the method scheduleAtFixedRate() was called with the correct arguments. There is no need to test the executor itself, as that's a collaborator that has already been tested elsewhere.

Copy link
Member

Choose a reason for hiding this comment

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

Actually, instead of waiting for the reporter to actually do its work, it would be much better to just verify that the method scheduleAtFixedRate() was called with the correct arguments. There is no need to test the executor itself, as that's a collaborator that has already been tested elsewhere.

Agrred. This would work, too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also, the tests are not isolated. The collaborators (mocks) should be initialized per test method, not per class.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Gnnhhh ... my IDE is configured to replace ".*" imports with the explicit ones - but I did NOT want to push those changes, as they were not necessary for the fix.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Test cases have been added.

Copy link
Member

Choose a reason for hiding this comment

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

Gnnhhh ... my IDE is configured to replace ".*" imports with the explicit ones - but I did NOT want to push those changes, as they were not necessary for the fix.

I think expanding star imports is a good change, we can leave it.

@arteam arteam added this to the 3.2.0 milestone Jan 9, 2017
@arteam arteam merged commit 0ccce2c into dropwizard:3.2-development Jan 9, 2017
@arteam
Copy link
Member

arteam commented Jan 9, 2017

Thank you for your contribution!

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

Successfully merging this pull request may close these issues.

2 participants