Class: Cells::TransactionRecord
- Inherits:
-
Object
- Object
- Cells::TransactionRecord
- Defined in:
- app/models/cells/transaction_record.rb
Overview
This class is a fake ActiveRecord::Base which implements the interface partially so that it can be used with ActiveRecord::ConnectionAdapters::Transaction#add_record github.com/rails/rails/blob/v7.1.5.2/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb#L147-L155 From there, several methods are required to be implemented:
-
#before_committed!
-
Normally implemented by ActiveRecord::Transactions
-
-
#committed!
-
Normally implemented by ActiveRecord::Transactions
-
-
#rolledback!
-
Normally implemented by ActiveRecord::Transactions
-
-
#trigger_transactional_callbacks?
-
Normally implemented by ActiveRecord::Transactions
-
Overridden by Cells::TransactionRecord to avoid more interfaces needed
-
-
#destroyed?
-
Normally implemented by ActiveRecord::Persistence but we ignore it
-
-
#_new_record_before_last_commit
-
Normally implemented by ActiveRecord::Transactions
-
We ignore some methods because they won’t be called under specific conditions, specifically when the following both return true:
-
#trigger_transactional_callbacks?
Defined Under Namespace
Modules: TransactionExtension
Constant Summary collapse
- Error =
Class.new(RuntimeError)
- TIMEOUT_IN_SECONDS =
0.2
Class Method Summary collapse
-
.current_transaction(connection) ⇒ Object
Extend the transaction class with an accessor to store a TransactionRecord in
cells_current_transaction_record.
Instance Method Summary collapse
- #before_committed! ⇒ Object
-
#committed!(should_run_callbacks: true) ⇒ Object
rubocop:disable Lint/UnusedMethodArgument – this needs to follow the interface.
- #create_record(metadata) ⇒ Object
- #destroy_record(metadata) ⇒ Object
-
#initialize(connection, transaction) ⇒ TransactionRecord
constructor
A new instance of TransactionRecord.
-
#rolledback!(force_restore_state: false, should_run_callbacks: true) ⇒ Object
rubocop:disable Lint/UnusedMethodArgument – this needs to follow the interface.
-
#trigger_transactional_callbacks? ⇒ Boolean
Always trigger callbacks.
Constructor Details
#initialize(connection, transaction) ⇒ TransactionRecord
Returns a new instance of TransactionRecord.
61 62 63 64 65 66 67 68 |
# File 'app/models/cells/transaction_record.rb', line 61 def initialize(connection, transaction) @connection = connection @transaction = transaction @create_records = [] @destroy_records = [] @outstanding_lease = nil @done = false end |
Class Method Details
.current_transaction(connection) ⇒ Object
Extend the transaction class with an accessor to store a TransactionRecord in cells_current_transaction_record. Each transaction object is unique, and Rails manages their lifecycle, so explicit cleanup isn’t required. Nested transactions aren’t supported or expected in this design.
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'app/models/cells/transaction_record.rb', line 38 def self.current_transaction(connection) return unless Current.cells_claims_leases? # The Cells::OutstandingLease requires a transaction to be open # to ensure that the lease is only created if the transaction # within a transaction and not outside of one if connection.current_transaction.closed? raise Error, 'The Cells::TransactionRecord requires transaction to be open' end current_transaction = connection.current_transaction instance = current_transaction.cells_current_transaction_record return instance if instance TransactionRecord.new(connection, current_transaction).tap do |instance| current_transaction.cells_current_transaction_record = instance # https://api.rubyonrails.org/v7.1.5.2/classes/ActiveRecord/ConnectionAdapters/DatabaseStatements.html#method-i-add_transaction_record # https://github.com/rails/rails/blob/v7.1.5.2/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb#L147-L155 current_transaction.add_record(instance) end end |
Instance Method Details
#before_committed! ⇒ Object
90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'app/models/cells/transaction_record.rb', line 90 def before_committed! raise Error, 'Already done' if done raise Error, 'Already created lease' if outstanding_lease raise Error, 'Attributes can now only be claimed on main DB' if Cells::OutstandingLease.connection != @connection @outstanding_lease = Cells::OutstandingLease.create_from_request!( create_records: sanitize_records_for_grpc(create_records), destroy_records: sanitize_records_for_grpc(destroy_records), deadline: deadline ) rescue GRPC::BadStatus => e raise_committing_error!(e) raise ActiveRecord::Rollback end |
#committed!(should_run_callbacks: true) ⇒ Object
rubocop:disable Lint/UnusedMethodArgument – this needs to follow the interface
117 118 119 120 121 122 123 124 |
# File 'app/models/cells/transaction_record.rb', line 117 def committed!(should_run_callbacks: true) # rubocop:disable Lint/UnusedMethodArgument -- this needs to follow the interface raise Error, 'Already done' if done raise Error, 'No lease created' unless outstanding_lease outstanding_lease.send_commit_update!(deadline: deadline) outstanding_lease.destroy! # the lease is no longer needed @done = true end |
#create_record(metadata) ⇒ Object
70 71 72 73 74 |
# File 'app/models/cells/transaction_record.rb', line 70 def create_record() raise Error, 'Lease already created' if outstanding_lease create_records << end |
#destroy_record(metadata) ⇒ Object
76 77 78 79 80 |
# File 'app/models/cells/transaction_record.rb', line 76 def destroy_record() raise Error, 'Lease already created' if outstanding_lease destroy_records << end |
#rolledback!(force_restore_state: false, should_run_callbacks: true) ⇒ Object
rubocop:disable Lint/UnusedMethodArgument – this needs to follow the interface
105 106 107 108 109 110 111 112 113 114 115 |
# File 'app/models/cells/transaction_record.rb', line 105 def rolledback!(force_restore_state: false, should_run_callbacks: true) # rubocop:disable Lint/UnusedMethodArgument -- this needs to follow the interface raise Error, 'Already done' if done # It is possible that lease might be not created yet, # since the transaction might be rolledback prematurely return unless outstanding_lease outstanding_lease.send_rollback_update!(deadline: deadline) outstanding_lease.destroy! # the lease is no longer needed @done = true end |
#trigger_transactional_callbacks? ⇒ Boolean
Always trigger callbacks. See: ActiveRecord::ConnectionAdapters::Transaction#
prepare_instances_to_run_callbacks_on
86 87 88 |
# File 'app/models/cells/transaction_record.rb', line 86 def trigger_transactional_callbacks? true end |