Class: Mistri::Stores::ActiveRecord
- Inherits:
-
Object
- Object
- Mistri::Stores::ActiveRecord
- Defined in:
- lib/mistri/stores/active_record.rb
Overview
Entries in the host's own database, through a model class the host supplies, so sessions live where application data lives: MySQL, Postgres, whatever the app runs. Not auto-required; load it with require "mistri/stores/active_record".
The model needs three columns: session_id (string, indexed), position (integer), payload (text). A migration to copy:
create_table :mistri_entries do |t|
t.string :session_id, null: false, index: true
t.integer :position, null: false
t.text :payload, size: :medium, null: false
t.
end
add_index :mistri_entries, [:session_id, :position], unique: true
The unique index is load-bearing: a session's loop is serial, but other writers append alongside it by design (a steer from a web process, a background child's report from a job), so appends are optimistic. Two writers that pick the same position collide on the index and the loser retries at the next one; entry order stays intact without a lock.
Reads select only (position, payload) and sort in Ruby: ORDER BY over rows carrying multi-megabyte payloads exhausts MySQL's sort buffer.
Constant Summary collapse
- APPEND_ATTEMPTS =
Concurrent writers converge in one or two retries; a session would need this many simultaneous appenders to exhaust them.
5
Instance Method Summary collapse
- #append(id, entry) ⇒ Object
-
#initialize(model) ⇒ ActiveRecord
constructor
A new instance of ActiveRecord.
- #load(id) ⇒ Object
Constructor Details
#initialize(model) ⇒ ActiveRecord
Returns a new instance of ActiveRecord.
36 37 38 |
# File 'lib/mistri/stores/active_record.rb', line 36 def initialize(model) @model = model end |
Instance Method Details
#append(id, entry) ⇒ Object
40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/mistri/stores/active_record.rb', line 40 def append(id, entry) payload = JSON.generate(entry) attempts = 0 begin position = @model.where(session_id: id).maximum(:position).to_i + 1 @model.create!(session_id: id, position: position, payload: payload) nil rescue ::ActiveRecord::RecordNotUnique attempts += 1 raise if attempts >= APPEND_ATTEMPTS retry end end |
#load(id) ⇒ Object
55 56 57 58 59 |
# File 'lib/mistri/stores/active_record.rb', line 55 def load(id) @model.where(session_id: id).pluck(:position, :payload) .sort_by(&:first) .map { |_position, payload| JSON.parse(payload) } end |