Skip to content
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

Database create many #160

Closed
wants to merge 7 commits into from
Closed

Conversation

eserna27
Copy link

@eserna27 eserna27 commented Oct 6, 2021

In briq.mx, we have this problem #137.

Here we have tried to solve it using insert_all to create all the notifications at once.

We have changed Noticed::Base#deliver to pass all recipients to run_delivery.

def run_delivery(recipients, enqueue: true)
  delivery_methods = self.class.delivery_methods.dup
  # Run database delivery inline first if it exists so other methods have access to the record
  if (index = delivery_methods.find_index { |m| m[:name] == :database })
      delivery_method = delivery_methods.delete_at(index)
      records = run_database_delivery_method(delivery_method, recipients: recipients, enqueue: false)
    end

    recipients.each do |recipient|
        record = Array.wrap(records).detect{|record| record.recipient == recipient}
        delivery_methods.each do |delivery_method|
        run_delivery_method(delivery_method, recipient: recipient, enqueue: enqueue, record: record)
    end
  end
end

Copy link

@bhserna bhserna left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eserna27 I have not tested it yet, but here are some things that maybe you can consider.

@@ -10,7 +10,7 @@ class Base
class_attribute :param_names, instance_writer: false, default: []

# Gives notifications access to the record and recipient during delivery
attr_accessor :record, :recipient
attr_accessor :record, :recipient, :records
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that here records is not needed.

method = delivery_method_for(delivery_method[:name], delivery_method[:options])

# If the queue is `nil`, ActiveJob will use a default queue name.
queue = delivery_method.dig(:options, :queue)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are not using this part any more... I think that you can delete it

}

run_callbacks delivery_method[:name] do
method = delivery_method_for(delivery_method[:name], delivery_method[:options])
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe here you can use :database directly?

Suggested change
method = delivery_method_for(delivery_method[:name], delivery_method[:options])
method = delivery_method_for(:database, delivery_method[:options])

Comment on lines 64 to 70
if bulk?
ids = klass.insert_all!(notifications).rows
records = klass.find(ids)
else
records = klass.create!(notifications)
end
records
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if bulk?
ids = klass.insert_all!(notifications).rows
records = klass.find(ids)
else
records = klass.create!(notifications)
end
records
if bulk?
ids = klass.insert_all!(notifications).rows
klass.find(ids)
else
klass.create!(notifications)
end

Comment on lines 86 to 91
recipients.each do |recipient|
record = Array.wrap(records).detect{|record| record.recipient == recipient}
delivery_methods.each do |delivery_method|
run_delivery_method(delivery_method, recipient: recipient, enqueue: enqueue, record: record)
end
end
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to do It like this?

Suggested change
recipients.each do |recipient|
record = Array.wrap(records).detect{|record| record.recipient == recipient}
delivery_methods.each do |delivery_method|
run_delivery_method(delivery_method, recipient: recipient, enqueue: enqueue, record: record)
end
end
records.each do |recipient|
delivery_methods.each do |delivery_method|
run_delivery_method(delivery_method, recipient: record.recipient, enqueue: enqueue, record: record)
end
end

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, when you do the bulk insert, you are "finding" the notifications but you are not preloading the recipient (as far as I know)... I think that we should preload it.

@eserna27
Copy link
Author

eserna27 commented Oct 8, 2021

Captura de Pantalla 2021-10-08 a la(s) 12 49 02

Comment on lines +66 to +71
if bulk?
ids = klass.insert_all!(notifications).rows
klass.preload(:recipient).find(ids)
else
klass.create!(notifications)
end
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also... maybe instead of asking for the rails version and the current adapter, we can ask if klass responds to insert_all. Don't you think?

Suggested change
if bulk?
ids = klass.insert_all!(notifications).rows
klass.preload(:recipient).find(ids)
else
klass.create!(notifications)
end
if klass.respond_to?(:insert_all!)
ids = klass.insert_all!(notifications).rows
klass.preload(:recipient).find(ids)
else
klass.create!(notifications)
end

@excid3
Copy link
Owner

excid3 commented Oct 9, 2021

insert_all only seems to return the IDs on Postgres. This needs to be compatible with MySQL and SQLite too, so I'm not sure insert_all will make sense to use here.

@excid3 excid3 closed this Jan 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants