diff --git a/app/controllers/servers_controller.rb b/app/controllers/servers_controller.rb index fd78dee51..bb2ce474d 100644 --- a/app/controllers/servers_controller.rb +++ b/app/controllers/servers_controller.rb @@ -96,7 +96,7 @@ def unsuspend private def safe_params(*extras) - params.require(:server).permit(:name, :mode, :ip_pool_id, *extras) + params.require(:server).permit(:name, :mode, :priority, :ip_pool_id, *extras) end end diff --git a/app/lib/worker/jobs/process_queued_messages_job.rb b/app/lib/worker/jobs/process_queued_messages_job.rb index 18489b578..f78a90040 100644 --- a/app/lib/worker/jobs/process_queued_messages_job.rb +++ b/app/lib/worker/jobs/process_queued_messages_job.rb @@ -40,12 +40,16 @@ def local_ip?(ip) end # Obtain a queued message from the database for processing + # Messages are prioritized based on the server's priority (higher priority first) + # and then by the message ID (ascending order). # # @return [void] def lock_message_for_processing - QueuedMessage.where(ip_address_id: [nil, @ip_addresses]) + QueuedMessage.joins(:server) + .where(ip_address_id: [nil, @ip_addresses]) .where(locked_by: nil, locked_at: nil) .ready_with_delayed_retry + .order("servers.priority DESC, queued_messages.id ASC") .limit(1) .update_all(locked_by: @locker, locked_at: @lock_time) end diff --git a/app/models/server.rb b/app/models/server.rb index 096133b19..2af53a2a5 100644 --- a/app/models/server.rb +++ b/app/models/server.rb @@ -78,7 +78,12 @@ class Server < ApplicationRecord validates :mode, inclusion: { in: MODES } validates :permalink, presence: true, uniqueness: { scope: :organization_id, case_sensitive: false }, format: { with: /\A[a-z0-9-]*\z/ }, exclusion: { in: RESERVED_PERMALINKS } validate :validate_ip_pool_belongs_to_organization - + validates :priority, presence: true, numericality: { + only_integer: true, + greater_than_or_equal_to: 0, + less_than_or_equal_to: 32767, + message: "must be a whole number between 0 and 32,767" + } before_validation(on: :create) do self.token = token.downcase if token end diff --git a/app/views/servers/_form.html.haml b/app/views/servers/_form.html.haml index 511970f18..7153d4fcc 100644 --- a/app/views/servers/_form.html.haml +++ b/app/views/servers/_form.html.haml @@ -20,6 +20,15 @@ e-mail will be routed normally to the intended recipients. When in Development mode, outgoing & incoming mail will be held and only visible in the web interface and will not be sent to any recipients or HTTP endpoints. + .fieldSet__field + = f.label :priority, "Sending Priority", :class => 'fieldSet__label' + .fieldSet__input + = f.text_field :priority, + :class => 'input input--text', + :placeholder => "e.g. 10" + %p.fieldSet__text + Set a priority for this server's outgoing mail. Messages from servers with a higher number will be sent first. + The default is 0. - if Postal.ip_pools? .fieldSet__field diff --git a/db/migrate/20250915065902_add_priority_to_server.rb b/db/migrate/20250915065902_add_priority_to_server.rb new file mode 100644 index 000000000..2b2e424ae --- /dev/null +++ b/db/migrate/20250915065902_add_priority_to_server.rb @@ -0,0 +1,5 @@ +class AddPriorityToServer < ActiveRecord::Migration[7.0] + def change + add_column :servers, :priority, :integer, limit: 2, unsigned: true, default: 0 + end +end diff --git a/db/schema.rb b/db/schema.rb index 9ab08fdb8..8d86cd6a5 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[7.0].define(version: 2024_03_11_205229) do +ActiveRecord::Schema[7.0].define(version: 2025_09_15_065902) do create_table "additional_route_endpoints", id: :integer, charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| t.integer "route_id" t.string "endpoint_type" @@ -255,6 +255,7 @@ t.index ["permalink"], name: "index_servers_on_permalink", length: 6 t.index ["token"], name: "index_servers_on_token", length: 6 t.index ["uuid"], name: "index_servers_on_uuid", length: 8 + t.integer "priority", limit: 2, default: 0, unsigned: true end create_table "smtp_endpoints", id: :integer, charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t|