Core Question
Core Question
A VRRP backup never asks "are you alive?" — so how does it decide, correctly, that the master is gone?
Outcome
Outcome
By the end of this session, the learner should be able to:
- explain why failover is inferred from absence rather than detected as an event
- compute
Skew_Timefor a given priority and say why it shrinks as priority rises - state the exact comparison
master_is_down()makes, including which side of the boundary counts as "down" - explain what a single call to
heartbeat()does to that boundary
Read Order
Read Order
- Read the module docstring at the top of the file
- Read
ADVERTISEMENT_INTERVAL - Read
master_down_interval() - Read
BackupWatch - Read
heartbeat() - Read
master_is_down() - Run
examples/ha/session_02_walkthrough.py
Read It Like Code
Read It Like Code
BackupWatch(
last_heard_at,
)Fields That Matter
Fields That Matter
| Field | Why it matters |
|---|---|
last_heard_at | The only state a backup keeps about the master. Everything else is arithmetic on this one timestamp. |
Decision Flow
Decision Flow
master_down_interval(priority): skew = ((256 - priority) * ADVERTISEMENT_INTERVAL) // 256 return 3 * ADVERTISEMENT_INTERVAL + skew master_is_down(watch, priority, now): now >= watch.last_heard_at + master_down_interval(priority) -> True (down) otherwise -> False (still up)
Reading Lens
Reading Lens
The important move in this session is to stop asking "did a failure event fire?" and start asking:
- what time did the master last speak, per
last_heard_at? - how long is this particular backup willing to wait, given its own priority?
- has
nowcrossedlast_heard_at + master_down_interval(priority)yet — and is the crossing point itself included?
Nothing in this file reacts to a failure. master_is_down() is a pure comparison, callable at any time, with no side effect — the "detection" is just asking the question at the right moment.
Toy Model Boundary
Toy Model Boundary
Real VRRP backups also track a Skew_Time-adjusted wait specifically for the very first advertisement after startup, and the interval can itself be learned from the master's advertised Advertisement_Interval rather than assumed fixed. This module hard-codes ADVERTISEMENT_INTERVAL = 1000 and only models steady-state timeout math — no startup grace period, no learned interval.
Code Landmarks
Code Landmarks
master_down_interval()'s docstring
The skew is the reading target: Skew_Time = ((256 - priority) * Advertisement_Interval) / 256. A higher priority produces a smaller 256 - priority, hence a smaller skew, hence a shorter total wait. The best-priority backup always finishes counting first — the skew turns what would otherwise be a tie among multiple backups into an ordered race with a predictable winner.
The integer division in master_down_interval()
// 256, not / 256. Skew_Time is defined in milliseconds and RFC 5798 specifies it as an integer computation; using // instead of true division keeps master_down_interval()'s return value an int that can be compared directly against another int, now, with no floating-point rounding to reason about.
master_is_down()'s comparison
now >= watch.last_heard_at + master_down_interval(priority). The operator is >=, not > — the exact millisecond the interval elapses already counts as down. This is the same boundary convention as dns/cache.py's entry_is_expired(): the threshold instant belongs to the "past" outcome, not the "still valid" one.
heartbeat()
One line: watch.last_heard_at = now. It doesn't touch priority, doesn't touch the interval — it only moves the anchor that master_is_down() measures from. Every subsequent down-check is relative to this new anchor.
Failure Questions
Failure Questions
Use the source file to answer these:
- For
priority=254, what isSkew_Timebefore it's added to3 * ADVERTISEMENT_INTERVAL? Compute(256 - 254) * 1000 // 256by hand and confirm it matches what the walkthrough prints. - Why does
master_down_interval()use//(integer division) instead of/? What type wouldSkew_Timebe if/were used, and what would that break inmaster_is_down()'s comparison? - At
now == watch.last_heard_at + master_down_interval(priority)exactly, doesmaster_is_down()returnTrueorFalse? Which comparison operator decides this? - Two backups, priority 254 and priority 100, both stop hearing the master at the same
last_heard_at. Which one'smaster_is_down()returnsTruefirst, and by how many milliseconds (usingADVERTISEMENT_INTERVAL = 1000)? heartbeat()takeswatchandnowbut notpriority. Why doesn't it needpriorityat all — what does that tell you about which value actually depends on priority?
Walkthrough
Walkthrough
Run this:
PYTHONPATH=src python3 examples/ha/session_02_walkthrough.py
The walkthrough prints master_down_interval(254) and master_down_interval(100) side by side, checks the >= boundary one millisecond before and exactly at the threshold, and shows a heartbeat() call pushing that boundary forward.
Done When
Done When
The learner can say all of the following without looking at notes:
- "A backup doesn't detect the master's failure — it infers it by comparing now against last_heard_at plus a computed interval."
- "Higher priority means a smaller skew means a shorter wait — the best backup always notices first."
- "The boundary is >=, so the exact millisecond the interval elapses already counts as down."
References
References
- RFC 5798 Section 6.2 (Master_Down_Interval, Skew_Time)
- RFC 5798 Section 5.2.4 (Advertisement_Interval)
Continue