Created
July 31, 2019 00:56
-
-
Save NickLaMuro/20dc0795410abf448402c54f707a59dc to your computer and use it in GitHub Desktop.
Example of the .git_transaction feature in https://github.com/ManageIQ/manageiq/pull/19074
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ bin/rails r tmp/test_git_transaction.rb | |
** Using session_store: ActionDispatch::Session::MemCacheStore | |
** ManageIQ master, codename: J-release | |
starting... | |
creating record... done! (id: 21) | |
> Process 53627 has started... | |
> Process 53628 has started... | |
> Process 53629 has started... | |
> Process.53628: starting .git_transaction... | |
> Process.53629: starting .git_transaction... | |
> Process.53628: lock aquired! | |
> Process.53628: > .update_repo... | |
> Process.53628: lockfile skip | |
> Process.53628: lockfile skip | |
> Process.53628: preforming clone... | |
> Process.53627: starting .git_transaction... | |
> Process.53628: > .transaction... | |
> Process.53628: > .refresh_branches... | |
> Process.53628: lockfile skip | |
> Process.53628: > .refresh_tags... | |
> Process.53628: lockfile skip | |
> Process.53628: > .save!... | |
> Process.53628: released lock! | |
> Process.53628: .git_transaction complete! | |
> Process.53629: lock aquired! | |
> Process.53629: > .update_repo... | |
> Process.53629: lockfile skip | |
> Process.53629: lockfile skip | |
> Process.53629: > .transaction... | |
> Process.53629: > .refresh_branches... | |
> Process.53629: lockfile skip | |
> Process.53629: > .refresh_tags... | |
> Process.53629: lockfile skip | |
> Process.53629: > .save!... | |
> Process.53629: released lock! | |
> Process.53629: .git_transaction complete! | |
> Process.53627: lock aquired! | |
> Process.53627: > .update_repo... | |
> Process.53627: lockfile skip | |
> Process.53627: lockfile skip | |
> Process.53627: > .transaction... | |
> Process.53627: > .refresh_branches... | |
> Process.53627: lockfile skip | |
> Process.53627: > .refresh_tags... | |
> Process.53627: lockfile skip | |
> Process.53627: > .save!... | |
> Process.53627: released lock! | |
> Process.53627: .git_transaction complete! | |
completed! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# test_git_transaction.rb | |
# | |
# Usage: bin/rails r test_git_transaction.rb | |
# | |
# A simple rails runner script for testing GitRepository#git_transaction | |
# | |
# Creates a GitRepository record in the main process, then spins up child | |
# processes (using fork) to run a quick sleep, and then a `git_transaction` | |
# where the child process will attempt to do a `GitRepository#refresh`. | |
# | |
# The outer `git_transaction` is unnecessary (I think), but it helps illustrate | |
# the nested usage of the method. The first process to get the filelock will | |
# be the only one that will perform the `git clone`. | |
module GitRepositoryPatch | |
# Re-written to add logging | |
def refresh | |
PIDColor.log " > .update_repo..." | |
update_repo | |
PIDColor.log " > .transaction..." | |
transaction do | |
PIDColor.log " > .refresh_branches..." | |
refresh_branches | |
PIDColor.log " > .refresh_tags..." | |
refresh_tags | |
self.last_refresh_on = Time.now.utc | |
PIDColor.log " > .save!..." | |
save! | |
end | |
end | |
private | |
# Slight overwrite to inject a puts for this script | |
def clone_repo | |
puts " > #{PIDColor.id 'Process.'}: preforming clone..." | |
super | |
end | |
# Log when we do and don't actually acquire a lock in a process | |
def acquire_git_lock | |
result = super | |
msg = result ? "lock aquired!" : "lockfile skip" | |
PIDColor.log msg | |
PIDColor.log " `defined? @git_lock`: #{(defined? @git_lock).inspect}" if $DEBUG | |
PIDColor.log " `@git_lock.nil?`: #{@git_lock.nil?.inspect}" if $DEBUG | |
result | |
end | |
# Log when when the lock is finally released | |
def release_git_lock | |
puts "calling .release_git_lock..." if $DEBUG | |
puts " before: @git_lock => #{@git_lock.inspect}" if $DEBUG | |
super | |
puts " after: @git_lock => #{@git_lock.inspect}" if $DEBUG | |
PIDColor.log "released lock!" if @git_lock.nil? | |
end | |
end | |
GitRepository # force autoload | |
class GitRepository | |
prepend GitRepositoryPatch | |
end | |
class PIDColor | |
def self.id prefix = "" | |
if STDOUT.tty? && $pid_color | |
id ||= "\e[#{$pid_color}m#{prefix}#{Process.pid}\e[0m" | |
else | |
Process.pid.to_s | |
end | |
end | |
def self.log msg | |
puts " > #{id 'Process.'}: #{msg}" | |
end | |
end | |
# Ugh... thanks Obama... | |
# | |
# just kidding, I solely blame Apple... | |
# | |
# https://github.com/darkskyapp/forecast-ruby/issues/13 | |
# | |
# You will probably eactually have to export this in the terminal you are | |
# running this from: | |
# | |
# export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES | |
# | |
# cuz reasons... | |
# | |
ENV["OBJC_DISABLE_INITIALIZE_FORK_SAFETY"] = "YES" | |
threads = [] | |
git_url = "https://github.com/NickLaMuro/ansible-tower-samples.git" | |
$pid_color = 30 | |
puts "starting..." | |
print "creating record..." | |
new_repo = GitRepository.create!(:url => git_url) | |
puts " done! (id: #{new_repo.id})" | |
3.times do | |
$pid_color += 1 | |
fork do | |
puts " > Process #{PIDColor.id} has started..." | |
sleep 1 | |
git_repo = GitRepository.find(new_repo.id) | |
PIDColor.log "starting .git_transaction..." | |
git_repo.git_transaction do | |
git_repo.refresh | |
end | |
PIDColor.log ".git_transaction complete!" | |
end | |
end | |
Process.waitall | |
# Cleanup | |
begin | |
GitRepository.find(new_repo.id).destroy! | |
rescue ActiveRecord::StatementInvalid | |
# Most likely the other threads will kill the parent's database connection, | |
# so this makes sure we reconnect if the above fails, and tries again. | |
ActiveRecord::Base.connection.reconnect! | |
retry | |
end | |
puts "completed!" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment