Use a sortable unique ID for the event_id (#3972)
This commit is contained in:
parent
ac5509e181
commit
b6c27f34fa
7 changed files with 53 additions and 6 deletions
1
Gemfile
1
Gemfile
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
10
app/services/secrets/generator.rb
Normal file
10
app/services/secrets/generator.rb
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
18
spec/services/secrets/generator_spec.rb
Normal file
18
spec/services/secrets/generator_spec.rb
Normal 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
|
||||
Loading…
Add table
Reference in a new issue