-
Notifications
You must be signed in to change notification settings - Fork 71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
finished_at_start/end job filters #111
base: main
Are you sure you want to change the base?
Conversation
Hi @rosa! Don't mean to bother you but in case you missed this this PR is ready for review :) |
@Xeitor thanks for letting me know, I'll try to review soon! |
Hi @rosa, hope you are doing great Sorry to bother you, wanted to know if you were able to take a look at the PR :) |
Hey @Xeitor, so sorry about this huge delay! I haven't had time to focus on Mission Control lately, but it's definitely in the plans for October, I need to spend a week or so just working on all pending PRs and missing features 😳 |
for sure no problem |
Hey @Xeitor, I'm finally back with Mission Control. Are you still interested in working on this one? I'd understand if not, given how long it's been, so sorry about that! If you're no longer interested, I'm happy to take it from here. |
hi @rosa, glad to have you back. For sure, no worries, I 'll take a look at the comments in the next days |
lib/active_job/jobs_relation.rb
Outdated
worker_id: worker_id, | ||
recurring_task_id: recurring_task_id | ||
recurring_task_id: recurring_task_id, | ||
}.compact.collect { |key, value| [ key, value.to_s ] }.to_h | ||
|
||
arguments.merge!(finished_at: finished_at) if finished_at.present? && !finished_at.to_s.match?(/^..$/) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like Rails does the right thing when you provide a beginless and endless range in a condition value, so you don't need to worry about checking this here. This can be kept as:
arguments = { job_class_name: job_class_name,
queue_name: queue_name,
worker_id: worker_id,
recurring_task_id: recurring_task_id,
finished_at: finished_at,
}.compact.collect { |key, value| [ key, value.to_s ] }.to_h
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure about this, for example:
dummy(dev)> hash = { finished_at: nil..nil }.compact
=> {:finished_at=>nil..}
dummy(dev)> hash.collect { |key, value| [ key, value.to_s ] }.to_h
=> {:finished_at=>".."}
will override finished_at to an empty range
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's not an empty range, but an "infinite" range, a range without start and end.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
besides, I did not want not stringity the range, check out this behaviour:
dummy(dev)> ActiveJob.jobs.finished.where(finished_at: (..Time.now).to_s).first
SolidQueue::Job Load (0.2ms) SELECT "solid_queue_jobs".* FROM "solid_queue_jobs" WHERE "solid_queue_jobs"."finished_at" IS NOT NULL AND "solid_queue_jobs"."finished_at" = ? ORDER BY "solid_queue_jobs"."finished_at" DESC LIMIT ? OFFSET ? [["finished_at", "2024-11-17 19:53:22"], ["LIMIT", 1000], ["OFFSET", 0]]
=> nil
dummy(dev)> ActiveJob.jobs.finished.where(finished_at: ..Time.now).first
SolidQueue::Job Load (0.5ms) SELECT "solid_queue_jobs".* FROM "solid_queue_jobs" WHERE "solid_queue_jobs"."finished_at" IS NOT NULL AND "solid_queue_jobs"."finished_at" <= ? ORDER BY "solid_queue_jobs"."finished_at" DESC LIMIT ? OFFSET ? [["finished_at", "2024-11-17 19:53:28.197854"], ["LIMIT", 1000], ["OFFSET", 0]]
=>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why would you convert the range into a string? That wouldn't work in the query.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
}.compact.collect { |key, value| [ key, value.to_s ] }.to_h |
this line will do the .to_s
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and sorry yes you are right, we could just do: arguments.merge!(finished_at: finished_at)
without the condition I wrote
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, sorry! Yes, we don't want to do that to the range. My comment was more addressed at this part:
if finished_at.present? && !finished_at.to_s.match?(/^..$/)
I meant we don't need that and we could just initialize arguments[:finished_at]
with the value.
In any case, I think we can get rid of the to_s
call on the values 🤔 It was added here because we didn't have the compact
before, but I don't think we need it. You can try to remove it and see if any tests fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great!! thanks :)
@@ -40,7 +40,7 @@ def supported_job_statuses | |||
end | |||
|
|||
def supported_job_filters(*) | |||
[ :queue_name, :job_class_name ] | |||
[ :queue_name, :job_class_name, :finished_at_start, :finished_at_end ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we want finished_at
here 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, no, this had to be split into supported_natively
and supported_in_memory
, but in any case, it should be just finished_at
when added to supported_natively
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had something like this in mind:
diff --git a/lib/active_job/jobs_relation.rb b/lib/active_job/jobs_relation.rb
index e4e19ee..a92af46 100644
--- a/lib/active_job/jobs_relation.rb
+++ b/lib/active_job/jobs_relation.rb
@@ -23,7 +23,6 @@ class ActiveJob::JobsRelation
include Enumerable
STATUSES = %i[ pending failed in_progress blocked scheduled finished ]
- FILTERS = %i[ queue_name job_class_name finished_at ]
PROPERTIES = %i[ queue_name status offset_value limit_value job_class_name worker_id recurring_task_id finished_at ]
attr_reader *PROPERTIES, :default_page_size
@@ -276,8 +275,7 @@ class ActiveJob::JobsRelation
end
def filters
- # @filetrs ||= queue_adapter.supported_job_filters(self).select { |property| public_send(property).present? && !queue_adapter.natively_supported_job_filters?(self, property) }
- @filters ||= FILTERS.select { |property| public_send(property).present? && !queue_adapter.supports_job_filter?(self, property) }
+ @filters ||= queue_adapter.supported_job_filters(self).select { |property| public_send(property).present? && !queue_adapter.natively_supported_job_filters(self).include?(property) }
end
def ensure_failed_status
diff --git a/lib/active_job/queue_adapters/resque_ext.rb b/lib/active_job/queue_adapters/resque_ext.rb
index 17b2fbf..d7d28af 100644
--- a/lib/active_job/queue_adapters/resque_ext.rb
+++ b/lib/active_job/queue_adapters/resque_ext.rb
@@ -48,6 +48,10 @@ module ActiveJob::QueueAdapters::ResqueExt
end
def supported_job_filters(jobs_relation)
+ [ :queue_name, :job_class_name ]
+ end
+
+ def natively_supported_job_filters(jobs_relation)
if jobs_relation.pending? then [ :queue_name ]
else []
end
diff --git a/lib/active_job/queue_adapters/solid_queue_ext.rb b/lib/active_job/queue_adapters/solid_queue_ext.rb
index 2db9ea1..b069504 100644
--- a/lib/active_job/queue_adapters/solid_queue_ext.rb
+++ b/lib/active_job/queue_adapters/solid_queue_ext.rb
@@ -39,8 +39,14 @@ module ActiveJob::QueueAdapters::SolidQueueExt
SolidQueueJobs::STATUS_MAP.keys
end
- def supported_job_filters(*)
- [ :queue_name, :job_class_name, :finished_at_start, :finished_at_end ]
+ def supported_job_filters(jobs_relation)
+ filters = [ :queue_name, :job_class_name ]
+ filters << :finished_at if jobs_relation.finished?
+ filters
+ end
+
+ def natively_supported_job_filters(*)
+ [ :queue_name, :job_class_name, :finished_at ]
end
def jobs_count(jobs_relation)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could also raise query errors if you try to use unsupported filters for a given job relation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think natively_supported_job_filters
should take a job_relation
as well and do the check jobs_relation.finished?
. Then you just use that in supported_job_filters
🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a little recap to see if we both are in the same page:
given that JobsRelations
is the interface to the adapters and therefore knows all the generic filters that can be applied: FILTERS
(with the extra parametrs in where method), I think the most reasonable way to select
the filters that should be performed in memory is to first ask the adapter if the filter is supported but not natively.
translating this thoughts to code I was thinking something like this:
def filters
@filters ||= FILTERS.select do |property|
public_send(property).present? && should_perform_filter_in_memory?(filter)
end
end
def should_perform_filter_in_memory?(filter)
# example: finished_at is supported only if the status is finished
queue_adapter.supports_job_filter?(self, property) &&
!queue_adapter.natively_supported_job_filters?(self).include?(property)
end
Co-authored-by: Rosa Gutierrez <rosa.ge@gmail.com>
@@ -274,6 +276,7 @@ def satisfy_filter?(job) | |||
end | |||
|
|||
def filters | |||
# @filetrs ||= queue_adapter.supported_job_filters(self).select { |property| public_send(property).present? && !queue_adapter.natively_supported_job_filters?(self, property) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# @filetrs ||= queue_adapter.supported_job_filters(self).select { |property| public_send(property).present? && !queue_adapter.natively_supported_job_filters?(self, property) } | |
# @filetrs ||= queue_adapter.supported_job_filters(self).select { |property| public_send(property).present? && !queue_adapter.supports_job_filter_natively?(self, property) } |
To be consistent with the other method, supports_job_filter?
.
@@ -60,7 +60,7 @@ module ActiveJob::QueueAdapters::AdapterTesting::DiscardJobs | |||
5.times { FailingJob.perform_later } | |||
10.times { FailingReloadedJob.perform_later } | |||
perform_enqueued_jobs | |||
ActiveJob.jobs.failed.where(queue_name: :queue_1).discard_all | |||
ActiveJob.jobs.failed.where(queue_name: 'queue_1').discard_all |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this change? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh that is because we got rid of the .to_s
in the JobsRelation#where
method and made the test fail
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ohhh, I see! In that case let's bring that back for queue_name
. We want to be able to use symbols there! Sorry, I didn't think of that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep makes sense, no problem
Changelog
Issue: #30
PD: I'll split the different filters in different PRs for easier review