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

Fix pseudo heartbeating when HB file missing #15483

Merged
merged 1 commit into from
Jun 30, 2017

Conversation

NickLaMuro
Copy link
Member

With the previous version of this code, the validate_heartbeat code:

def validate_heartbeat(w)
  last_heartbeat = workers_last_heartbeat(w)

  if w.last_heartbeat.nil?
    last_heartbeat ||= Time.now.utc
    w.update_attributes(:last_heartbeat => last_heartbeat)
  elsif !last_heartbeat.nil? && last_heartbeat > w.last_heartbeat
    w.update_attributes(:last_heartbeat => last_heartbeat)
  end
end

Would update the last_heartbeat value for the worker every time validate_heartbeat was called, which is not the intent.

When working correctly, the validate_heartbeat code should:

  • If no value is set in the DB, initialize it to either the time pulled from workers_last_heartbeat, or the current time (this should only happen the first time this method is called for this worker)
  • If workers_last_heartbeat is not nil, and it is a more resent heartbeat time, update the DB with the new value

Otherwise, assume we have the most up to date heartbeat value in the DB.

This change just returns nil if we don't have anything to provide from the heartbeat file. This is fine since the validate_heartbeat method will take care of any initialization of the last_heartbeat value in the DB, so workers_last_heartbeat_to_file is just an existence check, plus a value if there is one.

Links

@NickLaMuro
Copy link
Member Author

@miq-bot assign @gtanzillo
@miq-bot assign @jrafanie
@miq-bot add_label bug

@miq-bot miq-bot assigned gtanzillo and jrafanie and unassigned gtanzillo Jun 29, 2017
@miq-bot miq-bot added the bug label Jun 29, 2017
@chessbyte chessbyte changed the title Fix psuedo heartbeating when HB file missing Fix pseudo heartbeating when HB file missing Jun 29, 2017

around do |example|
ENV["WORKER_HEARTBEAT_METHOD"] = "file"
ENV["WORKER_HEARTBEAT_FILE"] = "/path/to/worker.hb"
Copy link
Member

Choose a reason for hiding this comment

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

If you need to rebase/fix a test, can you put this path into a let to DRY up some of the expectations below?

Copy link
Member Author

Choose a reason for hiding this comment

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

@jrafanie I thought lets weren't able to be accessed within an "around" block, but I could be wrong. But that was my rational for it not being DRY.

Copy link
Member Author

Choose a reason for hiding this comment

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

I was wrong... 😞

Will change.

expect(File).to receive(:exist?).with("/path/to/worker.hb")
.and_return(true, true)
expect(File).to receive(:mtime).with("/path/to/worker.hb")
.and_return(first_heartbeat, first_heartbeat+1)
Copy link
Member

Choose a reason for hiding this comment

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

^ 👍

# 1. Sets the initial heartbeat
# 2. Doesn't update the worker's last_heartbeat value
#
# But the result should not change after the first loop
Copy link
Member

Choose a reason for hiding this comment

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

👍

miq_server.validate_heartbeat(worker)
end

expect(worker.reload.last_heartbeat).to eq(first_heartbeat+i)
Copy link
Member

Choose a reason for hiding this comment

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

You need to freeze time at first_heartbeat for this test so these expectations pass.

Same for the ones below.

@jrafanie
Copy link
Member

LGTM so far @NickLaMuro, just minor test fixups. Nice find!

Copy link
Member

@gtanzillo gtanzillo left a comment

Choose a reason for hiding this comment

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

Looks good 👍 Thanks for taking care of this @NickLaMuro

With the previous version of this code, the validate_heartbeat code:

    def validate_heartbeat(w)
      last_heartbeat = workers_last_heartbeat(w)

      if w.last_heartbeat.nil?
        last_heartbeat ||= Time.now.utc
        w.update_attributes(:last_heartbeat => last_heartbeat)
      elsif !last_heartbeat.nil? && last_heartbeat > w.last_heartbeat
        w.update_attributes(:last_heartbeat => last_heartbeat)
      end
    end

Would update the `last_heartbeat` value for the worker every time
`validate_heartbeat` was called, which is not the intent.

When working correctly, the validate_heartbeat code should:

  * If no value is set in the DB, initialize it to either the time
    pulled from workers_last_heartbeat, or the current time (this should
    only happen the first time this method is called for this worker)
  * If workers_last_heartbeat is not nil, and it is a more resent
    heartbeat time, update the DB with the new value

Otherwise, assume we have the most up to date heartbeat value in the DB.

This change just returns `nil` if we don't have anything to provide from
the heartbeat file.  This is fine since the `validate_heartbeat` method
will take care of any initialization of the last_heartbeat value in the
DB, so workers_last_heartbeat_to_file is just an existence check, plus a
value if there is one.
@miq-bot
Copy link
Member

miq-bot commented Jun 30, 2017

Checked commit NickLaMuro@abd1b70 with ruby 2.2.6, rubocop 0.47.1, and haml-lint 0.20.0
2 files checked, 0 offenses detected
Everything looks fine. 🍰

@NickLaMuro
Copy link
Member Author

@jrafanie @gtanzillo Made a few updates:

  • Using be_within(1.second).of(SOME_TIME_HERE) to allow the tests to pass (rounding error when pulling from the DB I believe).
  • Instead of 2.times do |i|, doing things like [0, 5].each do |i| to space out the timings enough so that be_within isn't giving a false positive.
  • Updated the "missing heartbeat file" context to loop 4 times, just to confirm the same time (probably overkill).
  • Updated my comment for the "missing heartbeat file" case (made it more clear).

miq_server.validate_heartbeat(worker)
end

expect(worker.reload.last_heartbeat).to be_within(1.second).of(first_heartbeat + i)
Copy link
Member

Choose a reason for hiding this comment

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

👍

@jrafanie jrafanie merged commit 465bd15 into ManageIQ:master Jun 30, 2017
@jrafanie jrafanie added this to the Sprint 64 Ending Jul 3, 2017 milestone Jun 30, 2017
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.

4 participants