From 21a8d890459958375d4a49a5b7f31f4900a9e8b1 Mon Sep 17 00:00:00 2001 From: Adam Cooke Date: Tue, 27 Jul 2021 21:25:07 +0000 Subject: [PATCH] feat: add priorities to IP address assignment --- app/controllers/ip_addresses_controller.rb | 2 +- app/models/ip_address.rb | 22 +++++++++++++++++++ app/models/queued_message.rb | 2 +- app/views/ip_addresses/_form.html.haml | 13 +++++++++++ app/views/ip_pools/_form.html.haml | 11 ++++++---- ...0727210551_add_priority_to_ip_addresses.rb | 6 +++++ db/schema.rb | 3 ++- 7 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 db/migrate/20210727210551_add_priority_to_ip_addresses.rb diff --git a/app/controllers/ip_addresses_controller.rb b/app/controllers/ip_addresses_controller.rb index 088b82c..b5c76e0 100644 --- a/app/controllers/ip_addresses_controller.rb +++ b/app/controllers/ip_addresses_controller.rb @@ -33,7 +33,7 @@ class IPAddressesController < ApplicationController private def safe_params - params.require(:ip_address).permit(:ipv4, :ipv6, :hostname) + params.require(:ip_address).permit(:ipv4, :ipv6, :hostname, :priority) end end diff --git a/app/models/ip_address.rb b/app/models/ip_address.rb index c1a4694..eac06e9 100644 --- a/app/models/ip_address.rb +++ b/app/models/ip_address.rb @@ -9,6 +9,7 @@ # created_at :datetime # updated_at :datetime # hostname :string(255) +# priority :integer # class IPAddress < ApplicationRecord @@ -18,5 +19,26 @@ class IPAddress < ApplicationRecord validates :ipv4, :presence => true, :uniqueness => true validates :hostname, :presence => true validates :ipv6, :uniqueness => {:allow_blank => true} + validates :priority, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 100, only_integer: true } + + scope :order_by_priority, -> { order(priority: :desc) } + + before_validation :set_default_priority + + private + + def set_default_priority + return if priority.present? + + self.priority = 100 + end + + class << self + + def select_by_priority + order(Arel.sql("RAND() * priority DESC")).first + end + + end end diff --git a/app/models/queued_message.rb b/app/models/queued_message.rb index 79f4c78..43a2976 100644 --- a/app/models/queued_message.rb +++ b/app/models/queued_message.rb @@ -63,7 +63,7 @@ class QueuedMessage < ApplicationRecord def allocate_ip_address if Postal.ip_pools? && self.message && pool = self.server.ip_pool_for_message(self.message) - self.ip_address = pool.ip_addresses.order("RAND()").first + self.ip_address = pool.ip_addresses.select_by_priority end end diff --git a/app/views/ip_addresses/_form.html.haml b/app/views/ip_addresses/_form.html.haml index d8249ed..ea8053f 100644 --- a/app/views/ip_addresses/_form.html.haml +++ b/app/views/ip_addresses/_form.html.haml @@ -10,6 +10,19 @@ .fieldSet__field = f.label :hostname, :class => 'fieldSet__label' .fieldSet__input= f.text_field :hostname, :class => 'input input--text' + .fieldSet__field + = f.label :priority, :class => 'fieldSet__label' + .fieldSet__input + = f.text_field :priority, :class => 'input input--text', placeholder: '100' + %p.fieldSet__text + This priority will determine the likelihood of this IP address being selected + for use when sending a message. The higher the number the more likely the IP + is to be chosen. By defalt, the priority is set to the maximum value of 100. + This can be used to warm up new IP addresses by adding them with a low priority. + To give an indication of how this works, if you have three IPs with 1, 50 and 100 + as their priorities, and you send 100,000 emails, the priority 1 address will receive + a tiny percentage, the priority 50 will receive roughly 25% and the priority 100 will + receive roughly 75%. .fieldSetSubmit.buttonSet = f.submit :class => 'button button--positive js-form-submit' diff --git a/app/views/ip_pools/_form.html.haml b/app/views/ip_pools/_form.html.haml index 293d1c2..15b547a 100644 --- a/app/views/ip_pools/_form.html.haml +++ b/app/views/ip_pools/_form.html.haml @@ -12,16 +12,19 @@ %td IPv4 %td IPv6 %td Hostname + %td Priority %tbody - - if @ip_pool.ip_addresses.empty? + - ips = @ip_pool.ip_addresses.order_by_priority + - if ips.empty? %tr %td.dataTable__empty{:colspan => 3} There are no IP addresses assigned to this pool yet. - else - - for ip in @ip_pool.ip_addresses + - for ip in ips %tr %td{:width => "20%"}= link_to ip.ipv4, [:edit, @ip_pool, ip], :class => "u-link" - %td{:width => "40%"}= ip.ipv6 - %td{:width => "40%"}= ip.hostname + %td{:width => "35%"}= ip.ipv6 + %td{:width => "35%"}= ip.hostname + %td{:width => "10%"}= ip.priority %p= link_to "Add an IP address to pool", [:new, @ip_pool, :ip_address], :class => "u-link" diff --git a/db/migrate/20210727210551_add_priority_to_ip_addresses.rb b/db/migrate/20210727210551_add_priority_to_ip_addresses.rb new file mode 100644 index 0000000..3db1367 --- /dev/null +++ b/db/migrate/20210727210551_add_priority_to_ip_addresses.rb @@ -0,0 +1,6 @@ +class AddPriorityToIPAddresses < ActiveRecord::Migration[5.2] + def change + add_column :ip_addresses, :priority, :integer + IPAddress.where(priority: nil).update_all(priority: 100) + end +end diff --git a/db/schema.rb b/db/schema.rb index d649b24..020e443 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2020_07_17_083943) do +ActiveRecord::Schema.define(version: 2021_07_27_210551) do create_table "additional_route_endpoints", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| t.integer "route_id" @@ -124,6 +124,7 @@ ActiveRecord::Schema.define(version: 2020_07_17_083943) do t.datetime "created_at", precision: 6 t.datetime "updated_at", precision: 6 t.string "hostname" + t.integer "priority" end create_table "ip_pool_rules", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t|