Class: Webhookdb::Idempotency
- Inherits:
-
Object
- Object
- Webhookdb::Idempotency
- Extended by:
- MethodUtilities
- Defined in:
- lib/webhookdb/idempotency.rb
Overview
Support idempotent operations. This is very useful when 1) protecting the API against requests dispatched multiple times, as browsers are liable to do, and 2) designing parts of a system so they can be used idempotently, especially async jobs. This ensures an event can be republished if a job fails, but jobs that worked won’t be re-run.
In general, you do not use Idempotency instances directly; instead, you will use once_ever and every. For example, to only send a welcome email once:
Webhookdb::Idempotency.once_ever.under_key("welcome-email-#{customer.id}") { send_welcome_email(customer) }
Similarly, to prevent an action email from going out multiple times in a short period accidentally:
Webhookdb::Idempotency.every(1.hour).under_key("new-order-#{order.id}") { send_new_order_email(order) }
Note that idempotency cannot be executed while already in a transaction. If it were, the unique row would not be visible to other transactions. So the new row must be committed, then the idempotency evaluated (and the callback potentially run). To disable this check, set ‘Postgres.unsafe_skip_transaction_check’ to true, usually using the :no_transaction_check spec metadata.
Constant Summary collapse
- NOOP =
:skipped
Instance Attribute Summary collapse
-
#__every ⇒ Object
Returns the value of attribute __every.
-
#__once_ever ⇒ Object
Returns the value of attribute __once_ever.
Class Method Summary collapse
Instance Method Summary collapse
Methods included from MethodUtilities
attr_predicate, attr_predicate_accessor, singleton_attr_accessor, singleton_attr_reader, singleton_attr_writer, singleton_method_alias, singleton_predicate_accessor, singleton_predicate_reader
Instance Attribute Details
#__every ⇒ Object
Returns the value of attribute __every.
48 49 50 |
# File 'lib/webhookdb/idempotency.rb', line 48 def __every @__every end |
#__once_ever ⇒ Object
Returns the value of attribute __once_ever.
48 49 50 |
# File 'lib/webhookdb/idempotency.rb', line 48 def __once_ever @__once_ever end |
Class Method Details
.every(interval) ⇒ Object
42 43 44 45 46 |
# File 'lib/webhookdb/idempotency.rb', line 42 def self.every(interval) idem = self.new idem.__every = interval return idem end |
.once_ever ⇒ Object
36 37 38 39 40 |
# File 'lib/webhookdb/idempotency.rb', line 36 def self.once_ever idem = self.new idem.__once_ever = true return idem end |
Instance Method Details
#execute ⇒ Object
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/webhookdb/idempotency.rb', line 56 def execute Webhookdb::Postgres.check_transaction( self.db, "Cannot use idempotency while already in a transaction, since side effects may not be idempotent", ) self.class.dataset.insert_conflict.insert(key: self.key) self.db.transaction do idem = Webhookdb::Idempotency[key: self.key].lock! if idem.last_run.nil? result = yield() idem.update(last_run: Time.now) return result end return NOOP if self.__once_ever return NOOP if Time.now < (idem.last_run + self.__every) result = yield() idem.update(last_run: Time.now) return result end end |
#under_key(key, &block) ⇒ Object
50 51 52 53 54 |
# File 'lib/webhookdb/idempotency.rb', line 50 def under_key(key, &block) self.key = key return self.execute(&block) if block return self end |