Skip to content

perform_now executes job twice when Sentry is enabled #3046

Description

@abratashov

Issue Description

We're seeing a very strange issue where calling perform_now results in the job logic being executed twice.

As a temporary workaround we've replaced perform_now with a direct perform call, but we'd like to understand why perform_now is causing duplicate execution.

Console output

(prod)> puts RespondSurveyAnswerJob.instance_method(:perform_now).owner
Sentry::Rails::ActiveJobExtensions

(prod)> puts ActiveJob::Execution.instance_method(:perform_now).owner
ActiveJob::Execution

(prod)> puts RespondSurveyAnswerJob.ancestors
RespondSurveyAnswerJob
ApplicationJob
Sentry::Rails::ActiveJobExtensions
ActiveJob::Base
ActiveJob::EnqueueAfterTransactionCommit
ActiveRecord::Railties::JobRuntime
ActiveJob::Translation
ActiveJob::Timezones
ActiveJob::Logging
ActiveJob::Instrumentation
ActiveJob::Exceptions
ActiveJob::Callbacks
ActiveSupport::Callbacks
ActiveJob::Execution
ActiveSupport::Rescuable
ActiveJob::Enqueuing
ActiveJob::QueuePriority
ActiveJob::QueueName
ActiveJob::QueueAdapter
ActiveJob::Core
ActiveSupport::Dependencies::RequireDependency
Object
PP::ObjectMixin
FriendlyId::ObjectUtils
ActiveSupport::ToJsonWithActiveSupportEncoder
ActiveSupport::Tryable
JSON::GeneratorMethods
Kernel
BasicObject

Full log of duplicate email sending:
logs.txt

Reproduction Steps

RespondSurveyAnswerJob.perform_now(responder.id, contact.email, contact.name)

runs worker twice.

Simple example:

class TestJob < ApplicationJob
  def perform
    puts "PERFORM #{SecureRandom.hex(4)}"
  end
end

TestJob.perform_now # or TestJob.perform_later
=>
PERFORM e826218d 
PERFORM cb13c452

Expected Behavior

perform_now should execute the job exactly once.

Actual Behavior

perform_now causes the job body to execute twice, resulting in duplicate side effects (for example, duplicate emails).

Calling the job directly via:

RespondSurveyAnswerJob
  .new(...)
  .perform(...)

executes it only once.

Ruby Version

3.4.1

SDK Version

5.28

Integration and Its Version

rails (7.2.3.2), resque (2.7.0), concurrent-ruby (1.3.8)

Sentry Config

# config/initializers/sentry.rb

return if ENV['SECRET_KEY_BASE_DUMMY']

load 'app/services/sentry_rate_manager.rb'

Sentry.init do |config|
  config.dsn = Rails.application.config.sentry_dsn
  config.environment = Rails.application.config.sentry_env
  config.enable_tracing = true
  config.breadcrumbs_logger = %i[active_support_logger http_logger]

  filter = ActiveSupport::ParameterFilter.new(Rails.application.config.filter_parameters)

  config.before_send = lambda do |event, _hint|
    filter.filter(event.to_hash)
    SentryRateManager.process_limiting_sentry_event(event)
  end
end

Metadata

Metadata

Assignees

No one assigned

    Projects

    Status
    Waiting for: Product Owner

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions