Class: VendorsService::InventorySync::SchedulerService

Inherits:
Object
  • Object
show all
Includes:
ElasticAPM::SpanHelpers, SupplierConfig
Defined in:
app/services/vendors_service/inventory_sync/scheduler_service.rb

Overview

Service responsible for scheduling inventory synchronization for various vendor restaurants.

This service provides a unified interface for managing inventory sync across multiple suppliers while respecting each supplier's specific API rate limits and constraints. It handles:

  • Rate limiting through intelligent batching and delays

  • Supplier-specific configuration management

  • Comprehensive APM instrumentation and structured logging

  • Trigger type determination based on context and history

  • Database interaction for sync trigger tracking

## Supported Suppliers

  • *Tablecheck*: 10,000 requests per 5 minutes (750 restaurants per batch, 6 minutes delay)

  • *SevenRooms*: 1,000 requests per 10 seconds (1 restaurant per batch, 10 seconds delay)

## Sync Strategies

  • *:four_days* - Full sync of all available inventory days (up to restaurant.days_in_advance)

  • *:one_day* - Partial sync of up to 28 days

  • *:four_hours* - Quick sync of just 7 days ahead

## Usage Examples “`ruby # Schedule sync for all Tablecheck restaurants service = VendorsService::InventorySync::SchedulerService.new(supplier: :tablecheck) result = service.schedule_sync

# Schedule sync for specific restaurants with custom trigger type result = service.schedule_sync(

restaurant_ids: [1, 2, 3],
trigger_type: :four_days

)

# Check result if result

puts "Scheduled #{result[:restaurants_scheduled]} restaurants in #{result[:batch_count]} batches"

else

puts "Failed: #{result[:reason]}"

end “`

## Configuration Supplier configurations are defined in SUPPLIER_CONFIGS constant and include:

  • Rate limiting parameters (batch_size, delay_interval)

  • Feature flags and worker classes

  • Database models and associations

## Error Handling The service provides comprehensive error handling with:

  • APM error reporting via APMErrorHandler

  • Structured logging via BUSINESS_LOGGER and BUSINESS_LOGGER

  • Graceful degradation for unsupported suppliers

Constant Summary

Constants included from SupplierConfig

VendorsService::InventorySync::SupplierConfig::SUPPLIER_CONFIG

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from SupplierConfig

#get_supplier_config

Constructor Details

#initialize(supplier:) ⇒ SchedulerService

Initialize the service for a specific supplier

Parameters:

  • supplier (String, Symbol)

    The supplier name (must exist in SUPPLIER_CONFIGS)

Raises:

  • (ArgumentError)

    If supplier is not supported



66
67
68
69
# File 'app/services/vendors_service/inventory_sync/scheduler_service.rb', line 66

def initialize(supplier:)
  @supplier = supplier.to_sym
  @config = get_supplier_config(supplier)
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



60
61
62
# File 'app/services/vendors_service/inventory_sync/scheduler_service.rb', line 60

def config
  @config
end

#supplierObject (readonly)

Returns the value of attribute supplier.



60
61
62
# File 'app/services/vendors_service/inventory_sync/scheduler_service.rb', line 60

def supplier
  @supplier
end

Instance Method Details

#schedule_sync(restaurant_ids: nil, trigger_type: nil) ⇒ Hash

Schedules inventory sync for vendor restaurants based on specified trigger type

This method orchestrates the entire sync scheduling process:

  1. Validates feature flags and permissions

  2. Determines appropriate trigger type based on context

  3. Queries and batches eligible restaurants

  4. Schedules individual sync workers with appropriate delays

  5. Records trigger events for tracking

Parameters:

  • restaurant_ids (Array<Integer>, nil) (defaults to: nil)

    Optional list of restaurant IDs to sync; nil for all eligible

  • trigger_type (String, nil) (defaults to: nil)

    Type of sync to perform (four_days, one_day, four_hours); nil for auto-determination

Returns:

  • (Hash)

    Result hash containing:

    • success [Boolean] Whether the operation completed successfully

    • reason [String] Failure reason if success is false

    • restaurant_count [Integer] Total restaurants found

    • batch_count [Integer] Number of batches created

    • restaurants_scheduled [Integer] Number of restaurants actually scheduled

    • trigger_type [Symbol] Final trigger type used

    • force_update [Boolean] Whether this was a forced update

    • supplier [String] The supplier name



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'app/services/vendors_service/inventory_sync/scheduler_service.rb', line 91

def schedule_sync(restaurant_ids: nil, trigger_type: nil)
  return unless Flipper.enabled?(config[:flipper_feature])

  # Set business context for structured logging
  BUSINESS_LOGGER.set_business_context(
    {
      supplier: supplier,
      restaurant_ids: restaurant_ids,
      trigger_type: trigger_type,
    },
  )

  # Log the start of execution with proper context
  force_update = restaurant_ids.present? || trigger_type.present?
  if force_update
    BUSINESS_LOGGER.info(
      "#{self.class}: Force updating inventory for specific restaurants", {
        restaurant_ids: restaurant_ids,
        trigger_type: trigger_type,
        supplier: supplier,
      }
    )
  end

  # Determine trigger type
  determined_trigger = determine_trigger_type_with_logging(trigger_type)
  final_trigger_type = determined_trigger.to_sym

  # Process the restaurants in batches
  result = process_restaurant_batches(restaurant_ids, final_trigger_type, force_update)

  # Log the trigger for tracking purposes
  log_trigger(final_trigger_type) if final_trigger_type == :four_days && !force_update

  {
    success: true,
    restaurant_count: result[:restaurant_count],
    batch_count: result[:batch_count],
    restaurants_scheduled: result[:restaurants_scheduled],
    trigger_type: final_trigger_type,
    force_update: force_update,
    supplier: supplier,
  }
rescue StandardError => e
  APMErrorHandler.report(
    "#{supplier.capitalize} inventory sync scheduler failed",
    exception: e,
    context: {
      restaurant_ids: restaurant_ids,
      trigger_type: trigger_type,
      supplier: supplier,
    },
  )

  BUSINESS_LOGGER.error(
    "#{self.class}: Error during inventory sync scheduling", {
      exception: e.class.name,
      message: e.message,
      restaurant_ids: restaurant_ids,
      trigger_type: trigger_type,
      supplier: supplier,
    }
  )

  raise e
end