Use a sortable unique ID for the event_id (#3972)

This commit is contained in:
rhymes 2019-09-09 16:15:12 +02:00 committed by Mac Siri
parent ac5509e181
commit b6c27f34fa
7 changed files with 53 additions and 6 deletions

View file

@ -94,6 +94,7 @@ gem "timber-rails", "~> 1.0" # Timber integration for Rails
gem "twilio-ruby", "~> 5.25" # The official library for communicating with the Twilio REST API
gem "twitter", "~> 6.2" # A Ruby interface to the Twitter API
gem "uglifier", "~> 4.1" # Uglifier minifies JavaScript files
gem "ulid", "~> 1.1" # Universally Unique Lexicographically Sortable Identifier implementation for Ruby
gem "validate_url", "~> 1.0" # Library for validating urls in Rails
gem "webpacker", "~> 3.5" # Use webpack to manage app-like JavaScript modules in Rails
gem "webpush", "~> 1.0" # Encryption Utilities for Web Push payload

View file

@ -791,6 +791,7 @@ GEM
uber (0.1.0)
uglifier (4.1.20)
execjs (>= 0.3.0, < 3)
ulid (1.1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.6)
@ -973,6 +974,7 @@ DEPENDENCIES
twilio-ruby (~> 5.25)
twitter (~> 6.2)
uglifier (~> 4.1)
ulid (~> 1.1)
validate_url (~> 1.0)
vcr (~> 5.0)
web-console (~> 3.7)

View file

@ -6,14 +6,17 @@ module Webhook
article_destroyed
].freeze
attr_reader :event_type, :payload, :timestamp
attr_reader :event_type, :payload, :timestamp, :event_id
def initialize(event_type:, payload: {})
raise InvalidEvent unless EVENT_TYPES.include?(event_type)
@event_type = event_type
@payload = payload
@timestamp = Time.current.rfc3339
now = Time.current
@timestamp = now.rfc3339
@event_id = Secrets::Generator.sortable(now)
end
def as_json(*_args)

View file

@ -1,10 +1,10 @@
module Webhook
class EventSerializer
include FastJsonapi::ObjectSerializer
set_type :webhook_event
set_id do |event|
"#{event.event_type}_#{event.timestamp}"
end
set_id :event_id
attributes :event_type, :timestamp, :payload
end
end

View file

@ -0,0 +1,10 @@
module Secrets
module Generator
module_function
# Generates a unique and lexicographically sortable ID
def sortable(time = Time.current)
ULID.generate(time)
end
end
end

View file

@ -4,7 +4,7 @@ RSpec.describe Webhook::Event, type: :model do
let(:article) { create(:article) }
let!(:payload) { Webhook::PayloadAdapter.new(article).hash }
it "rases an exception" do
it "raises an exception with a unknown event type" do
expect do
described_class.new(event_type: "cool_event")
end.to raise_error(Webhook::InvalidEvent)
@ -29,6 +29,19 @@ RSpec.describe Webhook::Event, type: :model do
expect(attributes[:event_type]).to eq("article_updated")
expect(attributes[:payload][:data][:attributes][:title]).to eq(article.title)
end
it "provides an event_id dependent on time" do
event1 = described_class.new(event_type: "article_updated", payload: payload)
event1_id = event1.as_json.dig(:data, :id)
event2 = nil
Timecop.freeze(1.month.ago) do
event2 = described_class.new(event_type: "article_updated", payload: payload)
end
event2_id = event2.as_json.dig(:data, :id)
expect(event2_id < event1_id).to be(true)
end
end
describe "#to_json" do

View file

@ -0,0 +1,18 @@
require "rails_helper"
RSpec.describe Secrets::Generator, type: :service do
describe ".sortable" do
it "generates unique identifiers" do
expect(described_class.sortable).not_to eq(described_class.sortable)
end
it "generates sortable identifiers" do
now_id = described_class.sortable
a_month_from_now_id = described_class.sortable(1.month.from_now)
a_month_ago_id = described_class.sortable(1.month.ago)
expected_ids = [a_month_ago_id, now_id, a_month_from_now_id]
expect([now_id, a_month_from_now_id, a_month_ago_id].sort).to eq(expected_ids)
end
end
end