Last active
August 24, 2017 13:50
-
-
Save treznick/b0c9c1465111018b896385a34f41252d to your computer and use it in GitHub Desktop.
Debouncing API payloads
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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