From 237a0c0ea7d3b1c2efc66c9cdd4b427e9718a6dd Mon Sep 17 00:00:00 2001 From: moltenhub-bot Date: Mon, 4 May 2026 17:44:37 +0000 Subject: [PATCH] refactor: reduce codebase and centralize classes --- ...send_form_completed_webhook_request_job.rb | 38 ++----------- .../send_form_declined_webhook_request_job.rb | 37 ++---------- .../send_form_started_webhook_request_job.rb | 37 ++---------- .../send_form_viewed_webhook_request_job.rb | 37 ++---------- ...submission_archived_webhook_request_job.rb | 34 ++--------- ...ubmission_completed_webhook_request_job.rb | 34 ++--------- ..._submission_created_webhook_request_job.rb | 34 ++--------- ..._submission_expired_webhook_request_job.rb | 34 ++--------- ...d_template_archived_webhook_request_job.rb | 34 ++--------- ...nd_template_created_webhook_request_job.rb | 34 ++--------- ...nd_template_updated_webhook_request_job.rb | 34 ++--------- app/jobs/webhook_request_job.rb | 57 +++++++++++++++++++ 12 files changed, 106 insertions(+), 338 deletions(-) create mode 100644 app/jobs/webhook_request_job.rb diff --git a/app/jobs/send_form_completed_webhook_request_job.rb b/app/jobs/send_form_completed_webhook_request_job.rb index e025bb4c..51beab0e 100644 --- a/app/jobs/send_form_completed_webhook_request_job.rb +++ b/app/jobs/send_form_completed_webhook_request_job.rb @@ -1,42 +1,16 @@ # frozen_string_literal: true class SendFormCompletedWebhookRequestJob - include Sidekiq::Job - - sidekiq_options queue: :webhooks + include WebhookRequestJob MAX_ATTEMPTS = 12 def perform(params = {}) - submitter = Submitter.find_by(id: params['submitter_id']) - - return unless submitter - - webhook_url = WebhookUrl.find_by(id: params['webhook_url_id']) - - return unless webhook_url - - attempt = params['attempt'].to_i - - return if webhook_url.url.blank? || webhook_url.events.exclude?('form.completed') - - Submissions::EnsureResultGenerated.call(submitter) - - ActiveStorage::Current.url_options = Docuseal.default_url_options - - resp = SendWebhookRequest.call(webhook_url, event_type: 'form.completed', - event_uuid: params['event_uuid'], - record: submitter, - attempt:, - data: Submitters::SerializeForWebhook.call(submitter)) - - if (resp.nil? || resp.status.to_i >= 400) && attempt <= MAX_ATTEMPTS && - (!Docuseal.multitenant? || submitter.account.account_configs.exists?(key: :plan)) - SendFormCompletedWebhookRequestJob.perform_in((2**attempt).minutes, { - **params, - 'attempt' => attempt + 1, - 'last_status' => resp&.status.to_i - }) + perform_webhook_request(params, record_key: 'submitter_id', record_class: Submitter, + event_type: 'form.completed') do |submitter| + Submissions::EnsureResultGenerated.call(submitter) + ActiveStorage::Current.url_options = Docuseal.default_url_options + Submitters::SerializeForWebhook.call(submitter) end end end diff --git a/app/jobs/send_form_declined_webhook_request_job.rb b/app/jobs/send_form_declined_webhook_request_job.rb index 32d63bde..c13ba0c6 100644 --- a/app/jobs/send_form_declined_webhook_request_job.rb +++ b/app/jobs/send_form_declined_webhook_request_job.rb @@ -1,40 +1,13 @@ # frozen_string_literal: true class SendFormDeclinedWebhookRequestJob - include Sidekiq::Job - - sidekiq_options queue: :webhooks - - MAX_ATTEMPTS = 10 + include WebhookRequestJob def perform(params = {}) - submitter = Submitter.find_by(id: params['submitter_id']) - - return unless submitter - - webhook_url = WebhookUrl.find_by(id: params['webhook_url_id']) - - return unless webhook_url - - attempt = params['attempt'].to_i - - return if webhook_url.url.blank? || webhook_url.events.exclude?('form.declined') - - ActiveStorage::Current.url_options = Docuseal.default_url_options - - resp = SendWebhookRequest.call(webhook_url, event_type: 'form.declined', - event_uuid: params['event_uuid'], - record: submitter, - attempt:, - data: Submitters::SerializeForWebhook.call(submitter)) - - if (resp.nil? || resp.status.to_i >= 400) && attempt <= MAX_ATTEMPTS && - (!Docuseal.multitenant? || submitter.account.account_configs.exists?(key: :plan)) - SendFormDeclinedWebhookRequestJob.perform_in((2**attempt).minutes, { - **params, - 'attempt' => attempt + 1, - 'last_status' => resp&.status.to_i - }) + perform_webhook_request(params, record_key: 'submitter_id', record_class: Submitter, + event_type: 'form.declined') do |submitter| + ActiveStorage::Current.url_options = Docuseal.default_url_options + Submitters::SerializeForWebhook.call(submitter) end end end diff --git a/app/jobs/send_form_started_webhook_request_job.rb b/app/jobs/send_form_started_webhook_request_job.rb index cc278d2a..3fcae466 100644 --- a/app/jobs/send_form_started_webhook_request_job.rb +++ b/app/jobs/send_form_started_webhook_request_job.rb @@ -1,40 +1,13 @@ # frozen_string_literal: true class SendFormStartedWebhookRequestJob - include Sidekiq::Job - - sidekiq_options queue: :webhooks - - MAX_ATTEMPTS = 10 + include WebhookRequestJob def perform(params = {}) - submitter = Submitter.find_by(id: params['submitter_id']) - - return unless submitter - - webhook_url = WebhookUrl.find_by(id: params['webhook_url_id']) - - return unless webhook_url - - attempt = params['attempt'].to_i - - return if webhook_url.url.blank? || webhook_url.events.exclude?('form.started') - - ActiveStorage::Current.url_options = Docuseal.default_url_options - - resp = SendWebhookRequest.call(webhook_url, event_type: 'form.started', - event_uuid: params['event_uuid'], - record: submitter, - attempt:, - data: Submitters::SerializeForWebhook.call(submitter)) - - if (resp.nil? || resp.status.to_i >= 400) && attempt <= MAX_ATTEMPTS && - (!Docuseal.multitenant? || submitter.account.account_configs.exists?(key: :plan)) - SendFormStartedWebhookRequestJob.perform_in((2**attempt).minutes, { - **params, - 'attempt' => attempt + 1, - 'last_status' => resp&.status.to_i - }) + perform_webhook_request(params, record_key: 'submitter_id', record_class: Submitter, + event_type: 'form.started') do |submitter| + ActiveStorage::Current.url_options = Docuseal.default_url_options + Submitters::SerializeForWebhook.call(submitter) end end end diff --git a/app/jobs/send_form_viewed_webhook_request_job.rb b/app/jobs/send_form_viewed_webhook_request_job.rb index 8f6f0d6d..43f4b501 100644 --- a/app/jobs/send_form_viewed_webhook_request_job.rb +++ b/app/jobs/send_form_viewed_webhook_request_job.rb @@ -1,40 +1,13 @@ # frozen_string_literal: true class SendFormViewedWebhookRequestJob - include Sidekiq::Job - - sidekiq_options queue: :webhooks - - MAX_ATTEMPTS = 10 + include WebhookRequestJob def perform(params = {}) - submitter = Submitter.find_by(id: params['submitter_id']) - - return unless submitter - - webhook_url = WebhookUrl.find_by(id: params['webhook_url_id']) - - return unless webhook_url - - attempt = params['attempt'].to_i - - return if webhook_url.url.blank? || webhook_url.events.exclude?('form.viewed') - - ActiveStorage::Current.url_options = Docuseal.default_url_options - - resp = SendWebhookRequest.call(webhook_url, event_type: 'form.viewed', - event_uuid: params['event_uuid'], - record: submitter, - attempt:, - data: Submitters::SerializeForWebhook.call(submitter)) - - if (resp.nil? || resp.status.to_i >= 400) && attempt <= MAX_ATTEMPTS && - (!Docuseal.multitenant? || submitter.account.account_configs.exists?(key: :plan)) - SendFormViewedWebhookRequestJob.perform_in((2**attempt).minutes, { - **params, - 'attempt' => attempt + 1, - 'last_status' => resp&.status.to_i - }) + perform_webhook_request(params, record_key: 'submitter_id', record_class: Submitter, + event_type: 'form.viewed') do |submitter| + ActiveStorage::Current.url_options = Docuseal.default_url_options + Submitters::SerializeForWebhook.call(submitter) end end end diff --git a/app/jobs/send_submission_archived_webhook_request_job.rb b/app/jobs/send_submission_archived_webhook_request_job.rb index 77ba6d57..386cadba 100644 --- a/app/jobs/send_submission_archived_webhook_request_job.rb +++ b/app/jobs/send_submission_archived_webhook_request_job.rb @@ -1,38 +1,12 @@ # frozen_string_literal: true class SendSubmissionArchivedWebhookRequestJob - include Sidekiq::Job - - sidekiq_options queue: :webhooks - - MAX_ATTEMPTS = 10 + include WebhookRequestJob def perform(params = {}) - submission = Submission.find_by(id: params['submission_id']) - - return unless submission - - webhook_url = WebhookUrl.find_by(id: params['webhook_url_id']) - - return unless webhook_url - - attempt = params['attempt'].to_i - - return if webhook_url.url.blank? || webhook_url.events.exclude?('submission.archived') - - resp = SendWebhookRequest.call(webhook_url, event_type: 'submission.archived', - event_uuid: params['event_uuid'], - record: submission, - attempt:, - data: submission.as_json(only: %i[id archived_at])) - - if (resp.nil? || resp.status.to_i >= 400) && attempt <= MAX_ATTEMPTS && - (!Docuseal.multitenant? || submission.account.account_configs.exists?(key: :plan)) - SendSubmissionArchivedWebhookRequestJob.perform_in((2**attempt).minutes, { - **params, - 'attempt' => attempt + 1, - 'last_status' => resp&.status.to_i - }) + perform_webhook_request(params, record_key: 'submission_id', record_class: Submission, + event_type: 'submission.archived') do |submission| + submission.as_json(only: %i[id archived_at]) end end end diff --git a/app/jobs/send_submission_completed_webhook_request_job.rb b/app/jobs/send_submission_completed_webhook_request_job.rb index 3832eb35..76ef3791 100644 --- a/app/jobs/send_submission_completed_webhook_request_job.rb +++ b/app/jobs/send_submission_completed_webhook_request_job.rb @@ -1,38 +1,12 @@ # frozen_string_literal: true class SendSubmissionCompletedWebhookRequestJob - include Sidekiq::Job - - sidekiq_options queue: :webhooks - - MAX_ATTEMPTS = 10 + include WebhookRequestJob def perform(params = {}) - submission = Submission.find_by(id: params['submission_id']) - - return unless submission - - webhook_url = WebhookUrl.find_by(id: params['webhook_url_id']) - - return unless webhook_url - - attempt = params['attempt'].to_i - - return if webhook_url.url.blank? || webhook_url.events.exclude?('submission.completed') - - resp = SendWebhookRequest.call(webhook_url, event_type: 'submission.completed', - event_uuid: params['event_uuid'], - record: submission, - attempt:, - data: Submissions::SerializeForApi.call(submission)) - - if (resp.nil? || resp.status.to_i >= 400) && attempt <= MAX_ATTEMPTS && - (!Docuseal.multitenant? || submission.account.account_configs.exists?(key: :plan)) - SendSubmissionCompletedWebhookRequestJob.perform_in((2**attempt).minutes, { - **params, - 'attempt' => attempt + 1, - 'last_status' => resp&.status.to_i - }) + perform_webhook_request(params, record_key: 'submission_id', record_class: Submission, + event_type: 'submission.completed') do |submission| + Submissions::SerializeForApi.call(submission) end end end diff --git a/app/jobs/send_submission_created_webhook_request_job.rb b/app/jobs/send_submission_created_webhook_request_job.rb index c9fb1ff6..4b92ecb9 100644 --- a/app/jobs/send_submission_created_webhook_request_job.rb +++ b/app/jobs/send_submission_created_webhook_request_job.rb @@ -1,38 +1,12 @@ # frozen_string_literal: true class SendSubmissionCreatedWebhookRequestJob - include Sidekiq::Job - - sidekiq_options queue: :webhooks - - MAX_ATTEMPTS = 10 + include WebhookRequestJob def perform(params = {}) - submission = Submission.find_by(id: params['submission_id']) - - return unless submission - - webhook_url = WebhookUrl.find_by(id: params['webhook_url_id']) - - return unless webhook_url - - attempt = params['attempt'].to_i - - return if webhook_url.url.blank? || webhook_url.events.exclude?('submission.created') - - resp = SendWebhookRequest.call(webhook_url, event_type: 'submission.created', - event_uuid: params['event_uuid'], - record: submission, - attempt:, - data: Submissions::SerializeForApi.call(submission)) - - if (resp.nil? || resp.status.to_i >= 400) && attempt <= MAX_ATTEMPTS && - (!Docuseal.multitenant? || submission.account.account_configs.exists?(key: :plan)) - SendSubmissionCreatedWebhookRequestJob.perform_in((2**attempt).minutes, { - **params, - 'attempt' => attempt + 1, - 'last_status' => resp&.status.to_i - }) + perform_webhook_request(params, record_key: 'submission_id', record_class: Submission, + event_type: 'submission.created') do |submission| + Submissions::SerializeForApi.call(submission) end end end diff --git a/app/jobs/send_submission_expired_webhook_request_job.rb b/app/jobs/send_submission_expired_webhook_request_job.rb index d89b4f3a..ceb35051 100644 --- a/app/jobs/send_submission_expired_webhook_request_job.rb +++ b/app/jobs/send_submission_expired_webhook_request_job.rb @@ -1,38 +1,12 @@ # frozen_string_literal: true class SendSubmissionExpiredWebhookRequestJob - include Sidekiq::Job - - sidekiq_options queue: :webhooks - - MAX_ATTEMPTS = 10 + include WebhookRequestJob def perform(params = {}) - submission = Submission.find_by(id: params['submission_id']) - - return unless submission - - webhook_url = WebhookUrl.find_by(id: params['webhook_url_id']) - - return unless webhook_url - - attempt = params['attempt'].to_i - - return if webhook_url.url.blank? || webhook_url.events.exclude?('submission.expired') - - resp = SendWebhookRequest.call(webhook_url, event_type: 'submission.expired', - event_uuid: params['event_uuid'], - record: submission, - attempt:, - data: Submissions::SerializeForApi.call(submission)) - - if (resp.nil? || resp.status.to_i >= 400) && attempt <= MAX_ATTEMPTS && - (!Docuseal.multitenant? || submission.account.account_configs.exists?(key: :plan)) - SendSubmissionExpiredWebhookRequestJob.perform_in((2**attempt).minutes, { - **params, - 'attempt' => attempt + 1, - 'last_status' => resp&.status.to_i - }) + perform_webhook_request(params, record_key: 'submission_id', record_class: Submission, + event_type: 'submission.expired') do |submission| + Submissions::SerializeForApi.call(submission) end end end diff --git a/app/jobs/send_template_archived_webhook_request_job.rb b/app/jobs/send_template_archived_webhook_request_job.rb index 1b1c7c92..5727cb22 100644 --- a/app/jobs/send_template_archived_webhook_request_job.rb +++ b/app/jobs/send_template_archived_webhook_request_job.rb @@ -1,38 +1,12 @@ # frozen_string_literal: true class SendTemplateArchivedWebhookRequestJob - include Sidekiq::Job - - sidekiq_options queue: :webhooks - - MAX_ATTEMPTS = 10 + include WebhookRequestJob def perform(params = {}) - template = Template.find_by(id: params['template_id']) - - return unless template - - webhook_url = WebhookUrl.find_by(id: params['webhook_url_id']) - - return unless webhook_url - - attempt = params['attempt'].to_i - - return if webhook_url.url.blank? || webhook_url.events.exclude?('template.archived') - - resp = SendWebhookRequest.call(webhook_url, event_type: 'template.archived', - event_uuid: params['event_uuid'], - record: template, - attempt:, - data: template.as_json(only: %i[id archived_at])) - - if (resp.nil? || resp.status.to_i >= 400) && attempt <= MAX_ATTEMPTS && - (!Docuseal.multitenant? || template.account.account_configs.exists?(key: :plan)) - SendTemplateArchivedWebhookRequestJob.perform_in((2**attempt).minutes, { - **params, - 'attempt' => attempt + 1, - 'last_status' => resp&.status.to_i - }) + perform_webhook_request(params, record_key: 'template_id', record_class: Template, + event_type: 'template.archived') do |template| + template.as_json(only: %i[id archived_at]) end end end diff --git a/app/jobs/send_template_created_webhook_request_job.rb b/app/jobs/send_template_created_webhook_request_job.rb index cb0af29f..cb139fab 100644 --- a/app/jobs/send_template_created_webhook_request_job.rb +++ b/app/jobs/send_template_created_webhook_request_job.rb @@ -1,38 +1,12 @@ # frozen_string_literal: true class SendTemplateCreatedWebhookRequestJob - include Sidekiq::Job - - sidekiq_options queue: :webhooks - - MAX_ATTEMPTS = 10 + include WebhookRequestJob def perform(params = {}) - template = Template.find_by(id: params['template_id']) - - return unless template - - webhook_url = WebhookUrl.find_by(id: params['webhook_url_id']) - - return unless webhook_url - - attempt = params['attempt'].to_i - - return if webhook_url.url.blank? || webhook_url.events.exclude?('template.created') - - resp = SendWebhookRequest.call(webhook_url, event_type: 'template.created', - event_uuid: params['event_uuid'], - record: template, - attempt:, - data: Templates::SerializeForApi.call(template)) - - if (resp.nil? || resp.status.to_i >= 400) && attempt <= MAX_ATTEMPTS && - (!Docuseal.multitenant? || template.account.account_configs.exists?(key: :plan)) - SendTemplateCreatedWebhookRequestJob.perform_in((2**attempt).minutes, { - **params, - 'attempt' => attempt + 1, - 'last_status' => resp&.status.to_i - }) + perform_webhook_request(params, record_key: 'template_id', record_class: Template, + event_type: 'template.created') do |template| + Templates::SerializeForApi.call(template) end end end diff --git a/app/jobs/send_template_updated_webhook_request_job.rb b/app/jobs/send_template_updated_webhook_request_job.rb index 46a67dcc..990e5f0e 100644 --- a/app/jobs/send_template_updated_webhook_request_job.rb +++ b/app/jobs/send_template_updated_webhook_request_job.rb @@ -1,38 +1,12 @@ # frozen_string_literal: true class SendTemplateUpdatedWebhookRequestJob - include Sidekiq::Job - - sidekiq_options queue: :webhooks - - MAX_ATTEMPTS = 10 + include WebhookRequestJob def perform(params = {}) - template = Template.find_by(id: params['template_id']) - - return unless template - - webhook_url = WebhookUrl.find_by(id: params['webhook_url_id']) - - return unless webhook_url - - attempt = params['attempt'].to_i - - return if webhook_url.url.blank? || webhook_url.events.exclude?('template.updated') - - resp = SendWebhookRequest.call(webhook_url, event_type: 'template.updated', - event_uuid: params['event_uuid'], - record: template, - attempt:, - data: Templates::SerializeForApi.call(template)) - - if (resp.nil? || resp.status.to_i >= 400) && attempt <= MAX_ATTEMPTS && - (!Docuseal.multitenant? || template.account.account_configs.exists?(key: :plan)) - SendTemplateUpdatedWebhookRequestJob.perform_in((2**attempt).minutes, { - **params, - 'attempt' => attempt + 1, - 'last_status' => resp&.status.to_i - }) + perform_webhook_request(params, record_key: 'template_id', record_class: Template, + event_type: 'template.updated') do |template| + Templates::SerializeForApi.call(template) end end end diff --git a/app/jobs/webhook_request_job.rb b/app/jobs/webhook_request_job.rb new file mode 100644 index 00000000..8184d877 --- /dev/null +++ b/app/jobs/webhook_request_job.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +module WebhookRequestJob + extend ActiveSupport::Concern + + DEFAULT_MAX_ATTEMPTS = 10 + + included do + include Sidekiq::Job + + sidekiq_options queue: :webhooks + end + + def perform_webhook_request(params, record_key:, record_class:, event_type:) + record = record_class.find_by(id: params[record_key]) + + return unless record + + webhook_url = WebhookUrl.find_by(id: params['webhook_url_id']) + + return unless webhook_url + + attempt = params['attempt'].to_i + + return if webhook_url.url.blank? || webhook_url.events.exclude?(event_type) + + resp = SendWebhookRequest.call(webhook_url, event_type:, + event_uuid: params['event_uuid'], + record:, + attempt:, + data: yield(record)) + + retry_webhook_request(resp, record, params, attempt) + end + + private + + def retry_webhook_request(resp, record, params, attempt) + return unless retry_webhook_request?(resp, record, attempt) + + self.class.perform_in((2**attempt).minutes, { + **params, + 'attempt' => attempt + 1, + 'last_status' => resp&.status.to_i + }) + end + + def retry_webhook_request?(resp, record, attempt) + (resp.nil? || resp.status.to_i >= 400) && + attempt <= max_attempts && + (!Docuseal.multitenant? || record.account.account_configs.exists?(key: :plan)) + end + + def max_attempts + self.class.const_defined?(:MAX_ATTEMPTS, false) ? self.class::MAX_ATTEMPTS : DEFAULT_MAX_ATTEMPTS + end +end