Uploaded image for project: 'Ruby Driver'
  1. Ruby Driver
  2. RUBY-1353

max_staleness does not work due to seconds / milliseconds mismatch

    • Type: Icon: Bug Bug
    • Resolution: Fixed
    • Priority: Icon: Major - P3 Major - P3
    • 2.7.0.rc0
    • Affects Version/s: 2.4.2, 2.5.3
    • Component/s: Server Selection, Spec Comp
    • Labels:
      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:

      https://github.com/mongodb/mongo-ruby-driver/blob/v2.5.3/lib/mongo/server_selector/selectable.rb#L229

      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.

            Assignee:
            oleg.pudeyev@mongodb.com Oleg Pudeyev (Inactive)
            Reporter:
            ralf@embarkmobile.com Ralf Kistner
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: