Class: Privacy::DataDeletionWorker

Inherits:
Object
  • Object
show all
Includes:
Sidekiq::Job
Defined in:
app/workers/privacy/data_deletion_worker.rb

Overview

Sidekiq worker: drives a DeletionRequest through its lifecycle.

Trigger path:

  1. Webhooks::V1::Facebook::DataDeletionController#create (or the admin
    "approve" action for held requests) enqueues
    Privacy::DataDeletionWorker.perform_async(request.id)
  2. Worker atomically claims the row by transitioning pending
    processing in a single UPDATE; if the row was already claimed by
    a parallel run (or another state), the worker returns immediately
  3. Resolves the FB UID → Authentication → Account → Party (or pulls
    account_id/party_id already set by the admin manual-intake form)
  4. Runs ManualReviewDetector — bails to held_for_review if
    any Tier-3 trigger fires (admin gets an email; queue surfaces in
    /admin/privacy/deletion_requests)
  5. Runs ScrubService inside the transaction; on success
    transitions to completed, on failure to failed for human follow-up
  6. Enqueues ProcessorDetachWorker for async Stripe/PayPal
    detach (separate worker so a flaky outbound HTTP call cannot roll
    back the local scrub)
  7. Any uncaught exception is caught at the top level, the request
    is transitioned to failed with the error captured for the admin
    review queue, then re-raised so Sidekiq's error log records it too

Sidekiq worker: scrubs a Privacy::DeletionRequest.

Examples:

Privacy::DataDeletionWorker.perform_async(deletion_request.id)

Instance Method Summary collapse

Instance Method Details

#perform(deletion_request_id) ⇒ Object

Runs the job.

Parameters:

  • deletion_request_id (Integer)

    the deletion request id

Returns:

  • (Object)

    the result



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'app/workers/privacy/data_deletion_worker.rb', line 44

def perform(deletion_request_id)
  # Atomic claim: a single UPDATE WHERE state = 'pending' moves the
  # row to `processing`. If two workers race, only one update affects
  # a row; the other returns early. Eliminates the duplicate-scrub /
  # duplicate-email window between `find_by` and `start_processing`.
  claimed_rows = Privacy::DeletionRequest
                   .where(id: deletion_request_id, state: 'pending')
                   .update_all(state: 'processing', updated_at: Time.current) # rubocop:disable Rails/SkipsModelValidations
  return if claimed_rows.zero?

  req = Privacy::DeletionRequest.find(deletion_request_id)
  Rails.logger.info("Privacy::DataDeletionWorker starting request=#{req.id} source=#{req.source}")

  run_scrub_for(req)
rescue StandardError => e
  # Top-level safety net. With `retry: false`, any uncaught exception
  # would otherwise leave the request stuck in `processing` forever.
  handle_uncaught_exception(req, e)
  raise
end