Module: Eventsimple::Event::ClassMethods

Defined in:
lib/eventsimple/event.rb

Instance Method Summary collapse

Instance Method Details

#create(*args, &block) ⇒ Object

We want to automatically retry writes on concurrency failures. However events with sync reactors may have multiple nested events that are written within the same transaction. We can only catch and retry writes when we are in the outermost transaction.



197
198
199
200
201
# File 'lib/eventsimple/event.rb', line 197

def create(*args, &block)
  with_locks do
    with_retries(args) { super }
  end
end

#create!(*args, &block) ⇒ Object



203
204
205
206
207
# File 'lib/eventsimple/event.rb', line 203

def create!(*args, &block)
  with_locks do
    with_retries(args) { super }
  end
end

#existing_transaction_in_progress?Boolean

Returns:

  • (Boolean)


232
233
234
# File 'lib/eventsimple/event.rb', line 232

def existing_transaction_in_progress?
  ActiveRecord::Base.connection.transaction_open?
end

#find_sti_class(type_name) ⇒ Object

We don’t store the full namespaced class name in the events table. Events for an entity are expected to be namespaced under _events_namespace.



170
171
172
173
174
175
176
# File 'lib/eventsimple/event.rb', line 170

def find_sti_class(type_name)
  if _events_namespace.blank?
    super
  else
    super("#{_events_namespace}::#{type_name}")
  end
end

#inherited(subclass) ⇒ Object



151
152
153
154
# File 'lib/eventsimple/event.rb', line 151

def inherited(subclass)
  super
  subclass.attribute :data, Eventsimple::DataType.new(subclass)
end

#rescue_invalid_transition(&block) ⇒ Object



160
161
162
# File 'lib/eventsimple/event.rb', line 160

def rescue_invalid_transition(&block)
  self._on_invalid_transition = block || ->(error) {}
end

#resolve_metadata_klassObject



164
165
166
# File 'lib/eventsimple/event.rb', line 164

def 
   || Eventsimple::Metadata
end

#sti_class_for(type_name) ⇒ Object

Use a no-op deleted class for events that no longer exist in the codebase



179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/eventsimple/event.rb', line 179

def sti_class_for(type_name)
  super
rescue ActiveRecord::SubclassNotFound
  klass_name = "Deleted__#{type_name.demodulize}"
  return const_get(klass_name) if const_defined?(klass_name)

  klass = Class.new(self) do
    def deleted?
      true
    end
  end

  const_set(klass_name, klass)
end

#validate_with(form_klass) ⇒ Object



156
157
158
# File 'lib/eventsimple/event.rb', line 156

def validate_with(form_klass)
  @validate_with = form_klass
end

#with_locksObject



209
210
211
212
213
214
215
# File 'lib/eventsimple/event.rb', line 209

def with_locks(&)
  if _outbox_enabled
    base_class.with_advisory_lock(base_class.name, { transaction: existing_transaction_in_progress? }, &)
  else
    yield
  end
end

#with_retries(args) ⇒ Object



217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/eventsimple/event.rb', line 217

def with_retries(args, &)
  entity = args[0][_aggregate_klass.model_name.element.to_sym]

  # Only implement retries when the event is not already inside a transaction.
  if entity&.persisted? && !existing_transaction_in_progress?
    Retriable.with_context(:optimistic_locking, on_retry: proc { entity.reload }, &)
  else
    yield
  end
rescue ActiveRecord::StaleObjectError => e
  raise e unless existing_transaction_in_progress?

  raise e, "#{e.message} No retries are attempted when already inside a transaction."
end