Skip to content

Instantly share code, notes, and snippets.

@kaspth
Last active April 6, 2023 16:56
Show Gist options
  • Save kaspth/b13a4116bdd9e8f9735ea4abcec7acd0 to your computer and use it in GitHub Desktop.
Save kaspth/b13a4116bdd9e8f9735ea4abcec7acd0 to your computer and use it in GitHub Desktop.
Let secondary services deliver expositions to a primary service intake which it may process, everything happens on a private network.
class Invoice
delivers_exposition # only: :create ?
# ^ shorthand for this:
after_create_commit -> { Exposition.deliver_later "invoice.create", self }
after_update_commit -> { Exposition.deliver_later "invoice.update", self }
after_destroy_commit -> { Exposition.deliver_later "invoice.destroy", self }
end
class Exposition < Data.define(:service, :event, :gid)
def initialize(service: "invoices", **) = super
class DeliveryJob < ApplicationJob
def perform(**) = Exposition.new(**).deliver
end
def self.deliver_later(event, model)
DeliveryJob.perform_later(event:, gid: model.to_gid)
end
def deliver
Net::HTTP.post("https://localhost:4444/internal/intakes", service:, event:, gid:)
end
end
class Internal::ExpositionsController < ApplicationController
def show
render json: GlobalID.find(params[:gid]) # calls as_json, override on Invoice to tweak logic, could also use Jbuilder or whatever here
end
end
class Internal::IntakesController < ApplicationController
def create
Event::Job.perform_later params.permit! # Ensure job enqueue, that would fail on perform, to replay after fixing app-code.
end
end
class Event < Data.define(:service, :event, :gid)
class Job < ApplicationJob
def perform(**) = Event.new(**).perform
end
def perform
case service
when "invoices" then invoice_service_perform
else
raise "unknown service" # Fail job so it can be retried
end
end
private
def invoice_service_perform
case event
when "invoice.update"
Invoice.update! data.slice(:id, :customer_name)
end
end
def data = @data ||= client.fetch(gid)
def client = @client ||= Service.client(service)
end
class Service
mattr_accessor :endpoint
def self.client(name)
{ invoices: Invoice }.fetch(name.to_sym).new
end
def fetch(gid)
# However, Net::HTTP get works or another HTTP client gem.
Net::HTTP.get(endpoint, body: { gid: gid }).then { JSON.parse _1, symbolize_names: true }
end
class Invoice < Service
self.endpoint = "https://localhost:5555/internal/expositions" # Or some other routing
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment