···1111 @user = user
1212 end
13131414- def start(sets, include_pending)
1414+ def start(sets)
1515 queued_items = []
1616 importers = []
1717 sets = [sets] unless sets.is_a?(Array)
···1919 sets.each do |set|
2020 case set
2121 when 'likes'
2222- queued_items += @user.likes.pending.to_a if include_pending
2222+ queued_items += @user.likes.in_queue(:import).to_a
2323 importers << LikesImporter.new(@user)
2424 when 'reposts'
2525- queued_items += @user.reposts.pending.to_a if include_pending
2525+ queued_items += @user.reposts.in_queue(:import).to_a
2626 importers << RepostsImporter.new(@user)
2727 when 'posts'
2828- queued_items += @user.quotes.pending.to_a + @user.pins.pending.to_a if include_pending
2828+ queued_items += @user.quotes.in_queue(:import).to_a + @user.pins.in_queue(:import).to_a
2929 importers << PostsImporter.new(@user)
3030 when 'all'
3131- queued_items += @user.all_pending_items if include_pending
3131+ queued_items += @user.all_items_in_queue(:import)
3232 importers += [
3333 LikesImporter.new(@user),
3434 RepostsImporter.new(@user),
+1-1
app/import_worker.rb
···2323 def run(collections)
2424 import = ImportManager.new(@user)
2525 import.report = BasicReport.new if @verbose
2626- import.start(collections, false)
2626+ import.start(collections)
2727 end
2828 end
2929
+1-1
app/importers/likes_importer.rb
···18181919 records.each do |record|
2020 begin
2121- like = @user.likes.import_from_record(record['uri'], record['value'])
2121+ like = @user.likes.import_from_record(record['uri'], record['value'], queue: :import)
22222323 if like && like.pending? && @item_queue
2424 @item_queue.push(like)
+2-2
app/importers/posts_importer.rb
···18181919 records.each do |record|
2020 begin
2121- quote = @user.quotes.import_from_record(record['uri'], record['value'])
2222- pin = @user.pins.import_from_record(record['uri'], record['value'])
2121+ quote = @user.quotes.import_from_record(record['uri'], record['value'], queue: :import)
2222+ pin = @user.pins.import_from_record(record['uri'], record['value'], queue: :import)
23232424 if @item_queue
2525 if quote && quote.pending?
+1-1
app/importers/reposts_importer.rb
···18181919 records.each do |record|
2020 begin
2121- repost = @user.reposts.import_from_record(record['uri'], record['value'])
2121+ repost = @user.reposts.import_from_record(record['uri'], record['value'], queue: :import)
22222323 if repost && repost.pending? && @item_queue
2424 @item_queue.push(repost)
+11
app/models/importable.rb
···8899 included do
1010 scope :pending, -> { where(post: nil) }
1111+ scope :in_queue, ->(q) { where(queue: q) }
1212+1313+ enum :queue, { firehose: 0, import: 1 }
1414+1515+ validates_presence_of :post_uri, if: -> { post_id.nil? }
1616+ validate :check_queue
11171218 def pending?
1319 post_uri != nil
1420 end
15212222+ def check_queue
2323+ errors.add(:queue, 'must be nil if already processed') if queue && post
2424+ end
2525+1626 def import_item!
1727 post_uri = AT_URI(self.post_uri)
1828 return nil if !post_uri.is_post?
···2030 if post = Post.find_by_at_uri(post_uri)
2131 self.post = post
2232 self.post_uri = nil
3333+ self.queue = nil
2334 end
24352536 self.save!
···1919 before_destroy :delete_posts_cascading
20202121 has_many :likes, foreign_key: 'actor_id', dependent: :delete_all do
2222- def import_from_record(like_uri, record)
2222+ def import_from_record(like_uri, record, **args)
2323 like = self.new_from_record(like_uri, record)
2424 return nil if like.nil? || self.where(rkey: like.rkey).exists?
25252626+ like.assign_attributes(args)
2627 like.import_item!
2728 end
2829 end
29303031 has_many :reposts, foreign_key: 'actor_id', dependent: :delete_all do
3131- def import_from_record(repost_uri, record)
3232+ def import_from_record(repost_uri, record, **args)
3233 repost = self.new_from_record(repost_uri, record)
3334 return nil if repost.nil? || self.where(rkey: repost.rkey).exists?
34353636+ repost.assign_attributes(args)
3537 repost.import_item!
3638 end
3739 end
38403941 has_many :quotes, foreign_key: 'actor_id', dependent: :delete_all do
4040- def import_from_record(post_uri, record)
4242+ def import_from_record(post_uri, record, **args)
4143 quote = self.new_from_record(post_uri, record)
4244 return nil if quote.nil? || self.where(rkey: quote.rkey).exists?
43454646+ quote.assign_attributes(args)
4447 quote.import_item!
4548 end
4649 end
47504851 has_many :pins, foreign_key: 'actor_id', dependent: :delete_all do
4949- def import_from_record(post_uri, record)
5252+ def import_from_record(post_uri, record, **args)
5053 pin = self.new_from_record(post_uri, record)
5154 return nil if pin.nil? || self.where(rkey: pin.rkey).exists?
52555656+ pin.assign_attributes(args)
5357 pin.import_item!
5458 end
5559 end
···68726973 def all_pending_items
7074 [:likes, :reposts, :quotes, :pins].map { |x| self.send(x).pending.to_a }.reduce(&:+)
7575+ end
7676+7777+ def all_items_in_queue(queue)
7878+ [:likes, :reposts, :quotes, :pins].map { |x| self.send(x).in_queue(queue).to_a }.reduce(&:+)
7179 end
72807381 def delete_posts_cascading
+5-1
app/post_downloader.rb
···8888 end
89899090 def update_item(item, post)
9191- item.update!(post: post, post_uri: nil)
9191+ item.update!(post: post, post_uri: nil, queue: nil)
92929393 @total_count += 1
9494 @oldest_imported = [@oldest_imported, item.time].min
···147147 # delete reference if the account's PDS is the old bsky.social (so it must have been deleted pre Nov 2023)
148148 item.destroy if hostname == 'bsky.social'
149149 end
150150+ end
151151+152152+ if !item.destroyed?
153153+ item.update!(queue: nil)
150154 end
151155 end
152156 end
+7
db/migrate/20250923014702_add_queued_field.rb
···11+class AddQueuedField < ActiveRecord::Migration[7.2]
22+ def change
33+ [:likes, :reposts, :quotes, :pins].each do |table|
44+ add_column(table, :queue, :smallint, null: true)
55+ end
66+ end
77+end
+5-1
db/schema.rb
···1010#
1111# It's strongly recommended that you check this file into your version control system.
12121313-ActiveRecord::Schema[7.2].define(version: 2025_09_20_182018) do
1313+ActiveRecord::Schema[7.2].define(version: 2025_09_23_014702) do
1414 # These are extensions that must be enabled in order to support this database
1515 enable_extension "plpgsql"
1616···3434 t.datetime "time", null: false
3535 t.bigint "post_id"
3636 t.string "post_uri"
3737+ t.integer "queue", limit: 2
3738 t.index ["actor_id", "rkey"], name: "index_likes_on_actor_id_and_rkey", unique: true
3839 t.index ["actor_id", "time", "id"], name: "index_likes_on_actor_id_and_time_and_id", order: { time: :desc, id: :desc }
3940 end
···4546 t.text "pin_text", null: false
4647 t.bigint "post_id"
4748 t.string "post_uri"
4949+ t.integer "queue", limit: 2
4850 t.index ["actor_id", "rkey"], name: "index_pins_on_actor_id_and_rkey", unique: true
4951 t.index ["actor_id", "time", "id"], name: "index_pins_on_actor_id_and_time_and_id", order: { time: :desc, id: :desc }
5052 end
···6668 t.text "quote_text", null: false
6769 t.bigint "post_id"
6870 t.string "post_uri"
7171+ t.integer "queue", limit: 2
6972 t.index ["actor_id", "rkey"], name: "index_quotes_on_actor_id_and_rkey", unique: true
7073 t.index ["actor_id", "time", "id"], name: "index_quotes_on_actor_id_and_time_and_id", order: { time: :desc, id: :desc }
7174 end
···7679 t.datetime "time", null: false
7780 t.bigint "post_id"
7881 t.string "post_uri"
8282+ t.integer "queue", limit: 2
7983 t.index ["actor_id", "rkey"], name: "index_reposts_on_actor_id_and_rkey", unique: true
8084 t.index ["actor_id", "time", "id"], name: "index_reposts_on_actor_id_and_time_and_id", order: { time: :desc, id: :desc }
8185 end