-
Type: Bug
-
Resolution: Fixed
-
Priority: Major - P3
-
Affects Version/s: 2.4.2, 2.5.3
-
Component/s: Server Selection, Spec Comp
-
None
-
Environment:MongoDB 3.4+
The max_staleness read preference is specified in seconds. However, during the server selection check, there is a mismatch when comparing the staleness: The actual staleness is calculated in seconds, but compared to the configured preference converted to milliseconds (see below). This means that if e.g. the max_staleness is set to 90, it will only ignore servers that are 25 hours stale (90 * 1000 / 3600 == 25).
The code is here:
Copied, with my comments:
def filter_stale_servers(candidates, primary = nil) return candidates unless @max_staleness max_staleness_ms = @max_staleness * 1000 if primary candidates.select do |server| validate_max_staleness_support!(server) # last_scan and last_write_date are Time objects. Subtracting them gives a duration in seconds (Float) staleness = (server.last_scan - server.last_write_date) - # seconds (primary.last_scan - primary.last_write_date) + # seconds (server.heartbeat_frequency_seconds * 1000) # ms staleness <= max_staleness_ms end else max_write_date = candidates.collect(&:last_write_date).max candidates.select do |server| validate_max_staleness_support!(server) # Same issue here: max_write_date and last_write_date are Time objects staleness = max_write_date - server.last_write_date + (server.heartbeat_frequency_seconds * 1000) staleness <= max_staleness_ms end end end
Note that there are tests in the code, but the types are different in the tests:
https://github.com/mongodb/mongo-ruby-driver/blob/v2.5.3/spec/mongo/max_staleness_spec.rb#L61
In the tests, the values are numbers in ms, instead of Time objects as in reality.