I'm the maintenance developer for an inventory management site. There's a quarterly process that fails for about 10-20% of our customers but yields no error message or failure output of any sort. I've traced the code from trigger to model and found nothing that stands out as well as run code/tests by hand and can't find any loose ends to pull on.
I can share chunks of code as requested, but here is the class that handles the part that's failing. The process is one that looks at a company's history and generates min/max inventory recommended changes.
class ProductInventoryAdjustment < ActiveRecord::Base
belongs_to :product
has_many :notifications, as: :target, dependent: :destroy
validates :product_id, presence: true
validates :max_inventory, presence: true
validates :min_inventory, presence: true
validates :state, presence: true
def self.create_scheduled_adjustments
if is_annual?
schedules_to_adjust = ["quarterly", "semiannual", "annual"]
elsif is_semiannual?
schedules_to_adjust = ["quarterly", "semiannual"]
elsif is_quarter?
schedules_to_adjust = ["quarterly"]
else
# This method runs monthly, so on off months we
# catch here and return.
return
end
companies = Company.where(inventory_adjustment_schedule: schedules_to_adjust)
companies.each { |c| create_adjustments_for_company(c) }
end
def self.create_adjustments_for_company(company)
company.products.each { |p| create_adjustments_for_product(p) }
company.users.each do |user|
Notification.create!({
user: user,
notification_type: Notification::INVENTORY_ADJUSTMENT,
target: company
})
end
end
def self.create_adjustments_for_product(product)
return false if !product.is_old_enough_to_calculate_used_inventory?
average_inventory_used_per_week = product.average_inventory_used_per_week
max_inventory = (average_inventory_used_per_week * 4).ceil
min_inventory = (average_inventory_used_per_week * 2).round
max_inventory = 1 if max_inventory < 1
product.inventory_adjustments.create(
max_inventory: max_inventory,
min_inventory: min_inventory
)
end
private
def self.is_quarter?
[1,4,7,10].include? Date.today.month
end
def self.is_semiannual?
[1,7].include? Date.today.month
end
def self.is_annual?
[1].include? Date.today.month
end
end
100% of our clients do this quarterly and I've checked the database directly and all the relevant clients are scooped up when the code is run manually. As far as I can tell, there's really no rhyme or reason as to which clients pass/fail. The only exception is the fact that older clients tend to fail less, but there's no "hard cutoff" that passes/fails.
I teamed up with another engineer and we figured out that the machine was running out of memory during the calculation due to having to instantiate so many things.
Once the code was refactored to take this into account, it was fine.