Skip to content

Instantly share code, notes, and snippets.

@jenny-codes
Created December 10, 2021 05:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jenny-codes/89f5f4f8afb9b5012d56f24c172710d2 to your computer and use it in GitHub Desktop.
Save jenny-codes/89f5f4f8afb9b5012d56f24c172710d2 to your computer and use it in GitHub Desktop.
Simulate race condition during backup collage upload
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>scraps</key>
<array>
<dict>
<key>image</key>
<dict>
<key>source_url</key>
<string>race_condition</string>
</dict>
<key>scrap_type</key>
<string>image</string>
</dict>
</array>
</dict>
</plist>
# frozen_string_literal: true
# This contains destructive operations, so run with RAILS_ENV=test
# Usage:
# 1. Copy the file collage_struct_template.plist to project root
# 2. Run setup: `rake race_condition:setup`
# 3. Run script: `rake race_condition`
desc 'race condition setup'
task 'race_condition:setup' do
`mkdir race_condition 2>/dev/null`
`mkdir race_condition/prep 2>/dev/null`
10.times do |n|
`cat collage_struct_template.plist | sed "s/race_condition/&#{n}/" > race_condition/prep/#{n}.plist`
end
end
desc 'simulating race condition'
task race_condition: :environment do
# =============================
# Arrange
puts 'Resetting DB tables'
ActiveRecord::Base.connection.execute('TRUNCATE assets RESTART IDENTITY')
ActiveRecord::Base.connection.execute('TRUNCATE collages RESTART IDENTITY')
puts 'Creating collages'
n = 10
cids_with_index = n.times.each_with_object({}) do |num, memo|
struct_json = CB::Plist.parse(File.open("race_condition/#{num}.plist").read).to_json
memo[num] = Collage.create!(struct_json: struct_json).id
end
puts "Preparation done. Created #{n} collages."
# =============================
# Act
puts 'Creating thumbnanil and assets'
cids_with_index.each do |idx, cid|
metadata = { 'collage_id' => cid }
[
Thread.new { ImageAsset.create!(provenance: ImageAsset::Provenance::COLLAGE_THUMBNAIL, metadata: metadata) },
Thread.new { ImageAsset.create!(client_side_name: "race_condition#{idx}", provenance: ImageAsset::Provenance::COLLAGE_ASSET, metadata: metadata) }
].each(&:join)
end
# =============================
# Observe
cs = Collage.all
non_downloadables = cs.reject(&:is_downloadable)
puts '[Result]'
puts "- # of all collages: #{cs.count}"
puts "- # of non_downloadables: #{non_downloadables.count}"
puts "\nRecalculating..."
still_non_downloadables = non_downloadables.count do |c|
c.update(is_downloadable: c.calculate_is_downloadable)
!c.is_downloadable
end
puts "- # of non_downloadable collages: #{still_non_downloadables}"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment