discourse/migrations/lib/common/fork_manager.rb
Gerhard Schlager 7c3a29c9d6
DEV: Add converter framework for migrations-tooling (#28540)
* Updates GitHub Actions
* Switches from `bundler/inline` to an optional group in the `Gemfile` because the previous solution didn't work well with rspec
* Adds the converter framework and tests
* Allows loading private converters (see README)
* Switches from multiple CLI tools to a single CLI
* Makes DB connections reusable and adds a new abstraction for the `IntermediateDB`
* `IntermediateDB` acts as an interface for IPC calls when a converter steps runs in parallel (forks). Only the main process writes to the DB.
* Includes a simple example implementation of a converter for now.
2024-09-09 17:14:39 +02:00

106 lines
2.4 KiB
Ruby

# frozen_string_literal: true
module Migrations
module ForkManager
@before_fork_hooks = []
@after_fork_parent_hooks = []
@after_fork_child_hooks = []
@execute_parent_forks = true
class << self
def batch_forks
@execute_parent_forks = false
run_before_fork_hooks
yield
run_after_fork_parent_hooks
@execute_parent_forks = true
end
def before_fork(run_once: false, &block)
if block
@before_fork_hooks << { run_once:, block: }
block
end
end
def remove_before_fork_hook(block)
@before_fork_hooks.delete_if { |hook| hook[:block] == block }
end
def after_fork_parent(run_once: false, &block)
if block
@after_fork_parent_hooks << { run_once:, block: }
block
end
end
def remove_after_fork_parent_hook(block)
@after_fork_parent_hooks.delete_if { |hook| hook[:block] == block }
end
def after_fork_child(&block)
if block
@after_fork_child_hooks << { run_once: true, block: }
block
end
end
def remove_after_fork_child_hook(block)
@after_fork_child_hooks.delete_if { |hook| hook[:block] == block }
end
def fork
run_before_fork_hooks if @execute_parent_forks
pid =
Process.fork do
run_after_fork_child_hooks
yield
end
@after_fork_child_hooks.clear
run_after_fork_parent_hooks if @execute_parent_forks
pid
end
def size
@before_fork_hooks.size + @after_fork_parent_hooks.size + @after_fork_child_hooks.size
end
def clear!
@before_fork_hooks.clear
@after_fork_parent_hooks.clear
@after_fork_child_hooks.clear
end
private
def run_before_fork_hooks
run_hooks(@before_fork_hooks)
end
def run_after_fork_parent_hooks
run_hooks(@after_fork_parent_hooks)
cleanup_run_once_hooks(@after_fork_child_hooks)
end
def run_after_fork_child_hooks
run_hooks(@after_fork_child_hooks)
end
def run_hooks(hooks)
hooks.each { |hook| hook[:block].call }
cleanup_run_once_hooks(hooks)
end
def cleanup_run_once_hooks(hooks)
hooks.delete_if { |hook| hook[:run_once] }
end
end
end
end