Class: SolidQueue::Record

Inherits:
Object
  • Object
show all
Includes:
Mongoid::Document, Mongoid::Timestamps
Defined in:
lib/solid_queue_mongoid/models/record.rb

Constant Summary collapse

INDEX_HINTS =

Subclasses declare their MySQL index name → MongoDB field spec mappings here.

{}.freeze

Class Method Summary collapse

Class Method Details

.create_or_find_by!(attrs, &block) ⇒ Object

Mongoid equivalent of ActiveRecord's create_or_find_by!. Tries to create; on duplicate-key error or uniqueness validation error finds the existing record. Falls back to finding by job_id alone when the full attrs lookup would miss the existing record (e.g. queue_name is not in attrs but was set via a before_create callback).



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/solid_queue_mongoid/models/record.rb', line 95

def create_or_find_by!(attrs, &block)
  record = new(attrs)
  block.call(record) if block_given?
  record.save!
  record
rescue Mongoid::Errors::Validations => e
  # If the only errors are uniqueness-related, fall back to find the existing record
  raise unless uniqueness_only_error?(e.document)

  find_by_unique_key(attrs) || where(attrs).first || record
rescue Mongo::Error::OperationFailure => e
  raise unless duplicate_key_error?(e)

  find_by_unique_key(attrs) || where(attrs).first || raise(e)
end

.find_by!(attrs) ⇒ Object

find_by that raises Mongoid::Errors::DocumentNotFound when missing.



112
113
114
# File 'lib/solid_queue_mongoid/models/record.rb', line 112

def find_by!(attrs)
  find_by(attrs) || raise(Mongoid::Errors::DocumentNotFound.new(self, attrs))
end

.index(spec, options = nil) ⇒ Object

Override Mongoid's index() to use our per-class storage.



24
25
26
27
28
29
# File 'lib/solid_queue_mongoid/models/record.rb', line 24

def index(spec, options = nil)
  specification = Mongoid::Indexable::Specification.new(self, spec, options)
  return if index_specifications.include?(specification)

  index_specifications.push(specification)
end

.index_specifications ⇒ Object



15
16
17
# File 'lib/solid_queue_mongoid/models/record.rb', line 15

def index_specifications
  @index_specifications ||= []
end

.index_specifications=(val) ⇒ Object



19
20
21
# File 'lib/solid_queue_mongoid/models/record.rb', line 19

def index_specifications=(val)
  @_sq_index_specs = val
end

.inherited(subclass) ⇒ Object

Dynamic collection naming with prefix



33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/solid_queue_mongoid/models/record.rb', line 33

def self.inherited(subclass)
  super

  collection_name = subclass.name.demodulize.tableize
  prefixed_name = "#{SolidQueue.collection_prefix}#{collection_name}"

  subclass.store_in collection: prefixed_name, client: -> { SolidQueue.client.to_s }

  # Each subclass gets its own empty index_specifications array.
  # Indexes must be explicitly defined in each subclass (not inherited from parent)
  # because Mongoid::Indexable::Specification stores a reference to the klass,
  # and copying parent specs would create indexes on the parent's collection.
  subclass.instance_variable_set(:@_sq_index_specs, [])
end

.non_blocking_lock ⇒ Object

MongoDB has no row-level locking; this is a no-op stub so SolidQueue code that chains .non_blocking_lock still works.



51
52
53
# File 'lib/solid_queue_mongoid/models/record.rb', line 51

def non_blocking_lock
  all
end

.supports_insert_conflict_target? ⇒ Boolean

MongoDB supports unique indexes which serve the same purpose.

Returns:

  • (Boolean)


66
67
68
# File 'lib/solid_queue_mongoid/models/record.rb', line 66

def supports_insert_conflict_target?
  true
end

.transaction(_requires_new: false, &block) ⇒ Object

Mongoid 9 supports multi-document transactions via replica sets. We wrap in a MongoDB session transaction when available; fall back to a plain yield for non-replica-set environments (e.g. tests with a standalone).



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/solid_queue_mongoid/models/record.rb', line 73

def transaction(_requires_new: false, &block)
  Mongoid::QueryCache.clear_cache
  Mongoid.default_client.with_session do |session|
    session.start_transaction
    result = yield
    session.commit_transaction
    result
  end
rescue Mongo::Error::InvalidSession, Mongo::Error::OperationFailure => e
  # Not in a replica set or session not supported — execute without transaction
  raise if e.message.to_s.include?("Transaction numbers are only allowed")

  yield
rescue StandardError
  yield
end

.use_index(*indexes) ⇒ Object

Translate solid_queue MySQL index names to MongoDB hint specs and apply via Mongoid's .hint(). Unknown names are ignored (no hint applied). Subclasses may override INDEX_HINTS to register their own mappings.



58
59
60
61
62
63
# File 'lib/solid_queue_mongoid/models/record.rb', line 58

def use_index(*indexes)
  specs = indexes.filter_map do |name|
    name.is_a?(Hash) ? name : self::INDEX_HINTS[name.to_sym]
  end
  specs.any? ? hint(specs.first) : all
end