Uploaded image for project: 'Mongoid'
  1. Mongoid
  2. MONGOID-5078

Background jobs queued during after_save, which atomically query sharded documents, fail because of atomic_selector.

    • Type: Icon: Bug Bug
    • Resolution: Fixed
    • Priority: Icon: Major - P3 Major - P3
    • 8.0.1
    • Affects Version/s: 7.2.1
    • Component/s: Callbacks, Query
    • None

      Summary

      When a user needs to queue a background job during an after_save callback for a sharded document, and that job requires access to the document's atomic selector in order to query the updated document, current Mongoid code doesn't appear to permit this functionality.

      Repro

      module MyModule
      	module_function def create_background_job(atomic_selector)
      		# This line throws a DocumentNotFound error when called from Profile's
      		# after_save callback, because atomic_selector will have the outdated
      		# sharded field.
      		Profile.where(atomic_selector)
      	end
      end
      
      # Copied Profile class from profile.rb + an added after_save callback.
      class Profile
        include Mongoid::Document
        field :name, type: String
      
        embeds_one :profile_image
      
        shard_key :name
      
        after_save do |document|
        	# This line will fail when the 'name' field (shard_key) has been updated. The
        	# failure will be because at this point in time, document.atomic_selector
        	# will contain the now-outdated value for the 'name' field.
        	MyModule.create_background_job(document.atomic_selector)
        end
      end
      
      # Profile shard_key :name
      profile = Profile.create(name: "Alice")
      
      profile.name = "Bob"
      
      # This line won't fail, but its triggered after_save callback, which in-turn
      # will trigger MyModule.create_background_job(document.atomic_selector),
      # which will then try to query the document using its outdated atomic_selector,
      # will fail.
      profile.save()
      

      Current Functionality

      After digging through Mongoid source code & documentation, I understand the
      reason that atomic_selector has an outdated value for shard keys during
      after_save callbacks. It is built from shard_key_selector, which in-turn uses attribute_was. attribute_was is not updated until *after* the after_save callback has completed.

      Request

      However, supporting background jobs queued during an after_save callback querying sharded documents, does feel like an important use-case. Especially since this functionality works for non-sharded documents. I know we have multiple existing use cases where we leverage functionality like this, but we have to use some gross patterns to work around the atomic_selector difficulty.

      I'm wondering if there exists a simple solution to this problem such as adding an optional parameter to atomic_selector such as

      def atomic_selector(force_retrieve_newest_values = false)
      

      Or maybe adding an atomic_selector variant which automatically retrieves the fields using only selector[field.to_s] = send(field) instead of selector[field.to_s] = new_record? ? send(field) : attribute_was(field). I'm still learning the Mongoid codebase, but it looks hopeful that there exists a solution which:
      1. Would be simple to implement
      2. Wouldn't break existing code.
      3. Would unlock this desired functionality

            Assignee:
            dmitry.rybakov@mongodb.com Dmitry Rybakov
            Reporter:
            dalton.black@braze.com Dalton Black
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: