Class: Vendors::GoogleReserve::WebhookWorker

Inherits:
ApplicationWorker
  • Object
show all
Includes:
ElasticAPM::SpanHelpers
Defined in:
app/workers/vendors/google_reserve/webhook_worker.rb

Overview

WebhookWorker is a Sidekiq worker that handles Google Reserve Real-Time Update (RTU) webhooks

This worker sends reservation status updates to Google Reserve when reservations change state, enabling Google to keep their system synchronized with restaurant booking status in real-time. It's a critical component of the Google Reserve E2E integration.

Job Configuration

  • Queue: :critical (high priority processing)

  • Lock: :until_executed with on_conflict: :replace to ensure latest operations run immediately

  • Lock args: Uses first two arguments (reservation_id, status) for deduplication

Supported Status Updates

  • RWG_CONFIRMED: Reservation confirmed by restaurant

  • RWG_DECLINED_BY_MERCHANT: Reservation cancelled/rejected by restaurant

Process Overview

  1. Validates Flipper feature flag :google_reserve_e2e is enabled

  2. Loads reservation and sets restaurant timezone context

  3. Handles status-specific logic (immediate send vs wait-and-send)

  4. Delegates to VendorsService::GoogleReserve::WebhookService for actual webhook sending

Error Handling

  • Prevents duplicate webhook sends for DECLINED_BY_MERCHANT status

  • Waits up to 30 seconds for reservation status changes before timeout

  • Comprehensive business logging with reservation and vendor context

Dependencies

  • VendorsService::GoogleReserve::WebhookService: Contains webhook sending logic

  • Flipper feature flag: :google_reserve_e2e must be enabled

  • BUSINESS_LOGGER: For reservation context logging

Instance Method Summary collapse

Instance Method Details

#duplicate_webhook_status?(reservation, status) ⇒ Boolean

Returns:

  • (Boolean)


105
106
107
108
# File 'app/workers/vendors/google_reserve/webhook_worker.rb', line 105

def duplicate_webhook_status?(reservation, status)
  webhook_status = reservation&.vendor_reservation&.webhook_reservation_status
  webhook_status.present? && webhook_status == status
end

#perform(reservation_id, status) ⇒ void

This method returns an undefined value.

Main entry point for Google Reserve webhook processing Handles different reservation status updates and delegates to appropriate service methods

Parameters:

  • reservation_id (Integer)

    The ID of the reservation to send webhook for

  • status (String)

    The webhook status to send (RWG_CONFIRMED or RWG_DECLINED_BY_MERCHANT)

Raises:

  • (NotImplementedError)

    If status is not supported



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'app/workers/vendors/google_reserve/webhook_worker.rb', line 48

def perform(reservation_id, status)
  BUSINESS_LOGGER.set_business_context({ vendor_name: ApiVendorV1::Constants::GOOGLE_RESERVE_VENDOR_NAME,
                                         reservation_id: reservation_id })
  return unless Flipper.enabled?(:google_reserve_e2e)

  # Eager load vendor_reservation to prevent N+1 queries
  reservation = Reservation.includes(:vendor_reservation).find_by(id: reservation_id)

  Time.use_zone reservation.restaurant.time_zone do
    Time.zone.now
  end

  case status
  when ApiVendorV1::Constants::RWG_CONFIRMED
    send_webhook_to_google_reserve(reservation, ApiVendorV1::Constants::RWG_CONFIRMED)
  when ApiVendorV1::Constants::RWG_DECLINED_BY_MERCHANT, ApiVendorV1::Constants::RWG_CANCELED
    # Prevent sending CANCEL status duplication to GoogleReserve webhook
    return if duplicate_webhook_status?(reservation, status)

    wait_until_reservation_status_has_changed(reservation_id, [:cancelled, :rejected])
    send_webhook_to_google_reserve(reservation, status)
  else
    raise NotImplementedError
  end
end

#send_webhook_to_google_reserve(reservation, status) ⇒ Object



100
101
102
# File 'app/workers/vendors/google_reserve/webhook_worker.rb', line 100

def send_webhook_to_google_reserve(reservation, status)
  VendorsService::GoogleReserve::WebhookService.new(reservation, status).send_webhook
end

#wait_until_reservation_status_has_changed(reservation_id, status) ⇒ void

This method returns an undefined value.

Waits for reservation status to change to expected values before proceeding Uses a polling mechanism with timeout to ensure reservation state is synchronized before sending webhook to Google Reserve

Parameters:

  • reservation_id (Integer)

    The reservation ID to monitor

  • status (Array<Symbol>)

    Expected reservation statuses to wait for

Raises:

  • (RuntimeError)

    If reservation status doesn't change within 30 seconds



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'app/workers/vendors/google_reserve/webhook_worker.rb', line 83

def wait_until_reservation_status_has_changed(reservation_id, status)
  retry_times = 0
  loop do
    if status.include?(Reservation.find(reservation_id).status_as_symbol)
      break
    else
      retry_times += 1
      if retry_times == 100
        raise 'Unknown reservation status'
      end

      sleep 1
    end
  end
end