Class: Webhookdb::Idempotency

Inherits:
Object
  • Object
show all
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.

Defined Under Namespace

Classes: Builder, InDatabase, InMemory

Constant Summary collapse

NOOP =
:skipped

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.skip_transaction_checkObject

Skip the transaction check. Useful in unit tests. See class docs for details.



33
34
35
# File 'lib/webhookdb/idempotency.rb', line 33

def skip_transaction_check
  @skip_transaction_check
end

Class Method Details

._memory_cache_resultsObject



39
# File 'lib/webhookdb/idempotency.rb', line 39

def _memory_cache_results = @_memory_cache_results ||= {}

.every(interval) ⇒ Builder

Returns:



49
50
51
52
53
# File 'lib/webhookdb/idempotency.rb', line 49

def every(interval)
  b = self::Builder.new
  b._every = interval
  return b
end

.memory_cacheHash

Returns:

  • (Hash)


38
# File 'lib/webhookdb/idempotency.rb', line 38

def memory_cache = @memory_cache ||= {}

.once_everBuilder

Returns:



42
43
44
45
46
# File 'lib/webhookdb/idempotency.rb', line 42

def once_ever
  b = self::Builder.new
  b._once_ever = true
  return b
end

.separate_connectionObject



55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/webhookdb/idempotency.rb', line 55

def separate_connection
  @connection ||= Sequel.connect(
    uri,
    logger: self.logger,
    extensions: [
      :connection_validator,
      :pg_json, # Must have this to mirror the main model DB
    ],
    **Webhookdb::Dbutil.configured_connection_options,
  )
  return @connection
end

.skip_transaction_check?Boolean

Returns:

  • (Boolean)


35
# File 'lib/webhookdb/idempotency.rb', line 35

def skip_transaction_check? = self.skip_transaction_check