Class: Idempo::ActiveRecordBackend
- Inherits:
-
Object
- Object
- Idempo::ActiveRecordBackend
- Defined in:
- lib/idempo/active_record_backend.rb
Overview
This backend currently only works with mysql2 since it uses advisory locks
Defined Under Namespace
Classes: MysqlLock, PostgresLock, Store
Class Method Summary collapse
Instance Method Summary collapse
-
#initialize ⇒ ActiveRecordBackend
constructor
A new instance of ActiveRecordBackend.
-
#model ⇒ Object
Allows the model to be defined lazily without having to require active_record when this module gets loaded.
-
#prune! ⇒ Object
Deletes expired cached Idempo responses from the database, in batches.
- #with_idempotency_key(request_key) ⇒ Object
Constructor Details
#initialize ⇒ ActiveRecordBackend
Returns a new instance of ActiveRecordBackend.
61 62 63 64 |
# File 'lib/idempo/active_record_backend.rb', line 61 def initialize require "active_record" @memory_lock = Idempo::MemoryLock.new end |
Class Method Details
.create_table(via_migration) ⇒ Object
3 4 5 6 7 8 9 10 |
# File 'lib/idempo/active_record_backend.rb', line 3 def self.create_table(via_migration) via_migration.create_table "idempo_responses", charset: "utf8mb4", collation: "utf8mb4_unicode_ci" do |t| t.string :idempotent_request_key, index: {unique: true}, null: false t.datetime :expire_at, index: true, null: false # Needs an index for cleanup t.binary :idempotent_response_payload, limit: Idempo::SAVED_RESPONSE_BODY_SIZE_LIMIT t. end end |
Instance Method Details
#model ⇒ Object
Allows the model to be defined lazily without having to require active_record when this module gets loaded
67 68 69 70 71 |
# File 'lib/idempo/active_record_backend.rb', line 67 def model @model_class ||= Class.new(ActiveRecord::Base) do self.table_name = "idempo_responses" end end |
#prune! ⇒ Object
Deletes expired cached Idempo responses from the database, in batches
97 98 99 |
# File 'lib/idempo/active_record_backend.rb', line 97 def prune! model.where("expire_at < ?", Time.now).in_batches.delete_all end |
#with_idempotency_key(request_key) ⇒ Object
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/idempo/active_record_backend.rb', line 73 def with_idempotency_key(request_key) # We need to use an in-memory lock because database advisory locks are # reentrant. Both Postgres and MySQL allow multiple acquisitions of the # same advisory lock within the same connection - in most Rails/Rack apps # this translates to "within the same thread". This means that if one # elects to use a non-threading webserver (like Falcon), or tests Idempo # within the same thread (like we do), they won't get advisory locking # for concurrent requests. Therefore a staged lock is required. First we apply # the memory lock (for same thread on this process/multiple threads on this # process) and then once we have that - the DB lock. @memory_lock.with(request_key) do db_safe_key = Digest::SHA1.base64digest(request_key) database_lock = lock_implementation_for_connection(model.connection) raise Idempo::ConcurrentRequest unless database_lock.acquire(model.connection, request_key) begin yield(Store.new(db_safe_key, model)) ensure database_lock.release(model.connection, request_key) end end end |