Enhance strict typing and improve job initialization in FA and Inkbunny domains

- Refactored job classes in the FA domain to enforce strict typing with Sorbet, including the addition of type signatures in `FavsJob` and `Base` classes.
- Updated initialization methods to accept variable arguments and ensure proper type handling.
- Improved error handling in `ApiSearchPageProcessor` to gracefully manage null values for `last_file_update_datetime`.
- Added a new fixture for testing scenarios where `last_file_update_datetime` is null, enhancing test coverage.

These changes aim to improve type safety, maintainability, and robustness of the job processing logic.
This commit is contained in:
Dylan Knutson
2025-01-02 02:08:38 +00:00
parent e931897c6c
commit a9d639b66d
6 changed files with 188 additions and 8 deletions

View File

@@ -6,6 +6,12 @@ class Domain::Fa::Job::Base < Scraper::JobBase
:get_fa_http_client
end
sig { params(args: T.untyped).void }
def initialize(*args)
super(*T.unsafe(args))
@force_scan = T.let(false, T::Boolean)
end
protected
sig do

View File

@@ -1,20 +1,25 @@
# typed: true
# typed: strict
class Domain::Fa::Job::FavsJob < Domain::Fa::Job::Base
include HasBulkEnqueueJobs
queue_as :fa_user_favs
USERS_PER_FULL_PAGE = Rails.env.test? ? 9 : 190
USERS_PER_FULL_PAGE = T.let(Rails.env.test? ? 9 : 190, Integer)
def initialize(args)
super(args)
sig { params(args: T.untyped).void }
def initialize(*args)
super(*T.unsafe(args))
@seen_post_ids = T.let(Set.new, T::Set[Integer])
@page_id = T.let(nil, T.nilable(String))
@page_number = T.let(0, Integer)
@total_items_seen = T.let(0, Integer)
@caused_by_entry = T.let(nil, T.nilable(HttpLogEntry))
@first_job_entry = T.let(nil, T.nilable(HttpLogEntry))
@full_scan = T.let(false, T::Boolean)
@force_scan = T.let(false, T::Boolean)
@last_page_post_ids = T.let(Set.new, T::Set[Integer])
end
sig { params(args: T::Hash[Symbol, T.untyped]).void }
def perform(args)
@first_job_entry = nil
user = init_from_args!(args, build_user: false)
@@ -86,6 +91,7 @@ class Domain::Fa::Job::FavsJob < Domain::Fa::Job::Base
private
sig { params(user: Domain::Fa::User).returns(T.nilable(Symbol)) }
def scan_page(user:)
ret = nil
@@ -165,6 +171,7 @@ class Domain::Fa::Job::FavsJob < Domain::Fa::Job::Base
ret
end
sig { params(fa_ids: T::Array[Integer]).void }
def enqueue_new_post_scan_jobs(fa_ids)
bulk_enqueue_jobs do
fa_ids.each do |fa_id|

View File

@@ -161,8 +161,14 @@ class Domain::Inkbunny::Job::ApiSearchPageProcessor
post.shallow_updated_at = Time.zone.now
post.title = submission_json["title"]
post.posted_at = Time.zone.parse(submission_json["create_datetime"])
post.last_file_updated_at =
Time.zone.parse(submission_json["last_file_update_datetime"])
# rarely, a post will have a null last_file_update_datetime.
# This is a bug with Inkbunny, so handle it gracefully.
last_updated_str = submission_json["last_file_update_datetime"]
if last_updated_str.present?
post.last_file_updated_at = Time.zone.parse(last_updated_str)
end
post.num_files = submission_json["pagecount"]&.to_i
post.rating = submission_json["rating_id"]&.to_i
post.submission_type = submission_json["submission_type_id"]&.to_i

View File

@@ -9,8 +9,8 @@ class Scraper::JobBase < ApplicationJob
DeferredJob = Struct.new(:job_class, :params, :set_args)
sig { params(args: T.untyped).void }
def initialize(args)
super(args)
def initialize(*args)
super(*T.unsafe(args))
@deferred_jobs = T.let([], T::Array[DeferredJob])
@http_client = T.let(nil, T.nilable(Scraper::HttpClient))
@gallery_dl_client = T.let(nil, T.nilable(Scraper::GalleryDlClient))

View File

@@ -71,5 +71,50 @@ RSpec.describe Domain::Inkbunny::Job::UserGalleryJob do
expect(post_3507105.shallow_update_log_entry).to eq(log_entries[0])
end
end
context "when fetching posts with null last_file_update_datetime" do
let!(:log_entries) do
SpecUtil.init_http_client_mock(
http_client_mock,
[
{
uri:
"https://inkbunny.net/api_search.php?submissions_per_page=100&page=1&get_rid=yes&orderby=create_datetime&user_id=16532&keywords=no",
status_code: 200,
method: :post,
content_type: "application/json",
contents:
SpecUtil.read_fixture_file(
"domain/inkbunny/job/api_search_null_last_file_update.json",
),
caused_by_entry: nil,
},
],
)
end
let(:user) do
create(:domain_inkbunny_user, name: "the_user", ib_user_id: 16_532)
end
let(:args) { { user: user, caused_by_entry: nil } }
it "correctly handles posts with a null last_file_update_datetime" do
expect { perform_now(args) }.to(
change(Domain::Inkbunny::Post, :count).by(1),
)
user.reload
expect(user.name).to eq("Darkwitt")
expect(user.scanned_gallery_at).to be_present
expect(user.posts.count).to eq(1)
expect(user.shallow_update_log_entry).to eq(log_entries[0])
post_2855990 = user.posts.find_by(ib_post_id: 2_855_990)
expect(post_2855990).to be_present
expect(post_2855990.num_files).to eq(0)
expect(post_2855990.files.count).to eq(0)
expect(post_2855990.shallow_update_log_entry).to eq(log_entries[0])
end
end
end
end

View File

@@ -0,0 +1,116 @@
{
"sid": "9B5BPQqTZ,Mj-nYbL2tuIPoO,b",
"results_count_all": "564",
"results_count_thispage": 100,
"pages_count": 1,
"page": 1,
"user_location": "",
"rid": "dc55754e57",
"rid_ttl": "15 minutes",
"search_params": [
{
"param_name": "field_join_type",
"param_value": "or"
},
{
"param_name": "text",
"param_value": ""
},
{
"param_name": "string_join_type",
"param_value": "and"
},
{
"param_name": "keywords",
"param_value": "no"
},
{
"param_name": "keyword_id",
"param_value": false
},
{
"param_name": "title",
"param_value": "no"
},
{
"param_name": "description",
"param_value": "no"
},
{
"param_name": "md5",
"param_value": "no"
},
{
"param_name": "username",
"param_value": ""
},
{
"param_name": "user_id",
"param_value": "16532"
},
{
"param_name": "favs_user_id",
"param_value": ""
},
{
"param_name": "unread_submissions",
"param_value": "no"
},
{
"param_name": "type",
"param_value": ""
},
{
"param_name": "pool_id",
"param_value": ""
},
{
"param_name": "orderby",
"param_value": "create_datetime"
},
{
"param_name": "dayslimit",
"param_value": ""
},
{
"param_name": "random",
"param_value": "no"
},
{
"param_name": "scraps",
"param_value": "both"
},
{
"param_name": "count_limit",
"param_value": 18000
}
],
"submissions": [
{
"submission_id": "2855990",
"hidden": "f",
"username": "Darkwitt",
"user_id": "16532",
"create_datetime": "2022-11-23 11:19:51.482781+00",
"create_datetime_usertime": "23 Nov 2022 12:19 CET",
"last_file_update_datetime": null,
"last_file_update_datetime_usertime": "01 Jan 1970 01:00 CET",
"file_name": null,
"title": "New Submission",
"deleted": "f",
"public": "t",
"mimetype": null,
"pagecount": "0",
"rating_id": "2",
"rating_name": "Adult",
"file_url_full": false,
"file_url_screen": false,
"file_url_preview": false,
"submission_type_id": "1",
"type_name": "Picture/Pinup",
"friends_only": "f",
"guest_block": "f",
"scraps": "f"
}
]
}