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.



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

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



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

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

#existing_transaction_in_progress?Boolean

Returns:

  • (Boolean)


238
239
240
# File 'lib/eventsimple/event.rb', line 238

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.



176
177
178
179
180
181
182
# File 'lib/eventsimple/event.rb', line 176

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

#inherited(subclass) ⇒ Object



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

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

#rescue_invalid_transition(&block) ⇒ Object



166
167
168
# File 'lib/eventsimple/event.rb', line 166

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

#resolve_metadata_klassObject



170
171
172
# File 'lib/eventsimple/event.rb', line 170

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



185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/eventsimple/event.rb', line 185

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



162
163
164
# File 'lib/eventsimple/event.rb', line 162

def validate_with(form_klass)
  @validate_with = form_klass
end

#with_locksObject



215
216
217
218
219
220
221
# File 'lib/eventsimple/event.rb', line 215

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



223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/eventsimple/event.rb', line 223

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