Last active
May 18, 2016 20:44
-
-
Save kirkland/eb3902d4d60c43f8b9a9657448fc5e7d to your computer and use it in GitHub Desktop.
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
Delayed::Backend::ActiveRecord::Job.class_eval do | |
def self.build_ready_scope(worker, max_run_time) | |
ready_scope = ready_to_run(worker.name, max_run_time) | |
ready_scope = ready_scope.by_priority | |
ready_scope = ready_scope.where( | |
RandomUserIdQuery::SQL, db_time_now: db_time_now, | |
worker_name: worker.name, | |
locked_at_expired_at: db_time_now - max_run_time | |
) | |
ready_scope | |
end | |
def self.reserve(worker, max_run_time = Delayed::Worker.max_run_time) | |
reserve_with_scope(build_ready_scope(worker, max_run_time), worker, db_time_now) | |
end | |
end | |
class RandomUserIdQuery | |
def generate_sql | |
<<-EOSQL | |
user_id = | |
( | |
WITH | |
#{top_priority_cte}, | |
#{eligible_user_ids_cte} | |
SELECT user_id | |
FROM eligible_user_ids | |
ORDER BY random() | |
LIMIT 1 | |
) | |
EOSQL | |
end | |
private | |
# A job is runnable if it isn't locked or permanently failed, and the run_at time is not in the future | |
def runnable_filter | |
<<-EOSQL | |
( | |
run_at <= :db_time_now | |
AND (locked_at IS NULL OR locked_at < :locked_at_expired_at) | |
OR locked_by = :worker_name | |
) | |
AND failed_at IS NULL | |
AND "delayed_jobs"."blocked" = 'f' | |
EOSQL | |
end | |
# Calculate the highest priority among runnable jobs | |
def top_priority_cte | |
<<-EOSQL | |
top_priority AS | |
( | |
SELECT MIN(priority) AS top_priority | |
FROM delayed_jobs | |
WHERE #{runnable_filter} | |
) | |
EOSQL | |
end | |
def priority_filter | |
'delayed_jobs.priority = (SELECT top_priority FROM top_priority)' | |
end | |
# Only consider users that have a currently-runnable job and that has the highest priority among jobs | |
def eligible_user_ids_cte | |
<<-EOSQL | |
eligible_user_ids AS | |
( | |
SELECT DISTINCT user_id | |
FROM delayed_jobs | |
WHERE #{runnable_filter} AND #{priority_filter} | |
) | |
EOSQL | |
end | |
# We only need to generate this SQL once, the first time this file is loaded | |
SQL = new.generate_sql.freeze | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment