Skip to content

Instantly share code, notes, and snippets.

@treznick
Last active August 24, 2017 13:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save treznick/b0c9c1465111018b896385a34f41252d to your computer and use it in GitHub Desktop.
Save treznick/b0c9c1465111018b896385a34f41252d to your computer and use it in GitHub Desktop.
Debouncing API payloads
class TalksController
def create
talk = Talk.new(talk_params)
# handle creation
end
def update
@talk.update_attributes(talk_params)
# handle update
end
end
class Talk < ApplicationRecord
before_save :send_create_to_external_service, on: :create
before_save :send_update_to_external_service, on: :update
private
def send_create_to_external_service
SendTalkToApiService.new(self, changes, "create").call
end
def send_update_to_external_service
SendTalkToApiService.new(self, changes, "update").call
end
end
# NOTE: It might be worth breaking this out into two services, one for
# creation, one for updating, as the guard logic and whitelists might be
# different.
class SendTalkToApiService
WHITELISTED_ATTRIBUTES = %w(foo bar baz).freeze
# NOTE: This might need to be tuned
DEBOUNCE_SECONDS = 10
def initialize(talk, changes, action)
@talk, @changes, @action = talk, changes, action
end
def call
return unless changes_in_whitelist?
return if payload_already_fired?
ApiPayload.create(payload_hash: payload_hash, action: action)
# fire update
end
private
attr_accessor :talk, :changes, :action
def changes_in_whitelist?
talk.keys & WHITELISTED_ATTRIBUTES
end
def debounce_range
(DEBOUNCE_SECONDS.seconds.ago..Time.now)
end
def payload_already_fired?
ApiPayload.where(payload_hash: payload_digest, created_at: debounce_range, action: action).present?
end
def payload_digest
Digest::SHA256.digest(changes.sort.to_yaml)
end
end
class ApiPayload < ApplicationRecord
# schema notes:
#
# compound index payload_hash, created_at and action
# NOTE: we need to sort, serialize and hash the payload above as a
# workaround to MySQL not supporting indexable JSON columns. I'm not sure if
# Postgres' indexable JSONB column type allows for indexing the whole
# document. Sorting also might bite us here.
#
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment