Last active
April 2, 2018 16:11
-
-
Save bibendi/37e2898c274eb581a4f2260f0716ef93 to your computer and use it in GitHub Desktop.
This file contains 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
# ===== Common side in gem apress-api | |
Rails.application.routes.draw do | |
scope module: "apress", constraints: {domain: :current} do | |
namespace "api/v1" do | |
post 'callbacks/:service' => 'callbacks#create' | |
end | |
end | |
end | |
Rails.application.config.api = { | |
callbacks: ActiveSupport::HashWithIndifferentAccess.new, | |
events: ActiveSupport::HashWithIndifferentAccess.new([]) | |
} | |
module Apress | |
module Api | |
class CallbacksController < ::Apress::Api::BaseController | |
def create | |
service = params.require(:service) | |
event = params.require(:event) | |
job = ::Rails.application.config.api[:callbacks].fetch(service).fetch(event).camelize.constantize | |
event_params = params[:params] || {} | |
if job.respond_to?(:enqueue) | |
job.enqueue(event_params) | |
else | |
::Resque.enqueue(job, event_params) | |
end | |
head 201 | |
end | |
end | |
end | |
end | |
module Apress | |
module Api | |
class DelayedFireCallback | |
include Interactor | |
def call | |
services = Rails.application.config.api[:events].fetch(context.event) | |
::Resque.redis.multi do | |
services.each do |service| | |
::Resque.enqueue( | |
::Apress::Api::FireCallbackJob, | |
service, | |
context.event, | |
context.params | |
) | |
end | |
end | |
end | |
end | |
end | |
end | |
module Apress | |
module Api | |
class FireCallbackJob | |
include Resque::Integration | |
queue :api_callbacks | |
retries | |
def self.perform(serivce, event, params) | |
callback_class = "#{service}_client/fire_callback".camelize.constantize | |
callback_class.call!( | |
event: event, | |
params: params | |
) | |
end | |
end | |
end | |
end | |
module Apress | |
module Api | |
module Callbacks | |
def notify_service(event:, params: {}, when:) | |
# Metaprogramming magic | |
end | |
end | |
end | |
end | |
# ===== Project side | |
# apress-companies | |
module Apress | |
module Companies | |
class CompanyUser | |
extend ::Apress::Api::Callbacks | |
notify_services event: 'company_user:delete', | |
params: [:company_id, :user], | |
when: [:after_commit, on: :destroy] | |
# !!!! Will be generated as... !!!! | |
# BEGIN | |
after_commit(on: :destroy) do | |
::Apress::Api::DelayedFireCallback.call!( | |
event: 'company_user:delete', | |
params: {company_id: company_id, user_id: user} | |
) | |
end | |
# END | |
end | |
end | |
end | |
# cosmos_client | |
Rails.application.config.api[:events]['company_user:delete'] << :cosmos | |
module CosmosClient | |
class FireCallback | |
include Interactor | |
def call | |
# Если у нас стоит флаг о том, что сервис не готов принимать запросы, то мы не будем этого делать, так как нет гарантий, | |
# что принятый на той стороне запрос корректно обработается. Мы лучше попробуем его послать позднее, | |
# выбросив здесь исключение, чтобы отработал механиз retry в FireCallbackJob | |
context.fail!(message: 'cosmos.updates_locked') if ::Apress::Orders.updates_locked? | |
callback = ::CosmosClient::Callback.new(event: context.event, params: context.params) | |
context.callback = callback | |
context.fail!(message: 'cosmos.fire_callback.failure') unless callback.save | |
end | |
end | |
end | |
module CosmosClient | |
class Callback < CosmosClient::Base | |
self.site = ::CosmosClient.api_url + "/callbacks/cosmos" | |
end | |
end | |
# ===== Cosmos (Apress::Orders at now) side | |
Rails.application.config.api[:callbacks][:cosmos] = { | |
'company_user:delete' => 'apress/orders/reset_manager_to_default_job' | |
} | |
# https://github.com/abak-press/apress-orders/blob/master/app/jobs/apress/orders/reset_manager_to_default_job.rb#L4 | |
# FIXME: Убрать уникальность, которая к тому же сделана и с ошибкой | |
module Apress | |
module Orders | |
class ResetManagerToDefaultJob | |
include Resque::Integration | |
queue :orders_unbind_manager | |
retries | |
def self.perform(params) | |
# ... | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
А тут - https://gist.github.com/bibendi/37e2898c274eb581a4f2260f0716ef93#file-service-callbacks-rb-L19 - случаем DoS не возможен?
Я так понимаю тут надо какие-то ограничения поставить на того, кто может отправлять туда запрос?
Например, что это может сделать только проект в котором задан какой-нибудь secret-token общий с сервисным проектом.