مراية لـ
https://github.com/postalserver/postal.git
تم المزامنة 2026-03-03 14:24:06 +00:00
Compare commits
8 الالتزامات
| المؤلف | SHA1 | التاريخ | |
|---|---|---|---|
|
|
19e3bc20c6 | ||
|
|
f05c2e4503 | ||
|
|
7bc5230cba | ||
|
|
b9edcf5b7d | ||
|
|
54306a9748 | ||
|
|
304828a672 | ||
|
|
4528a14d27 | ||
|
|
96ba4b8f30 |
@@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
".": "2.2.0"
|
".": "2.2.2"
|
||||||
}
|
}
|
||||||
|
|||||||
26
CHANGELOG.md
26
CHANGELOG.md
@@ -2,6 +2,32 @@
|
|||||||
|
|
||||||
This file contains all the latest changes and updates to Postal.
|
This file contains all the latest changes and updates to Postal.
|
||||||
|
|
||||||
|
## [2.2.2](https://github.com/postalserver/postal/compare/2.2.1...2.2.2) (2024-02-06)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* adds new connection pool which will discard failed clients ([54306a9](https://github.com/postalserver/postal/commit/54306a974802c2e4d17e0980531e2d0dba08150a)), closes [#2780](https://github.com/postalserver/postal/issues/2780)
|
||||||
|
* re-add reconnect: true to database ([7bc5230](https://github.com/postalserver/postal/commit/7bc5230cbaae58fb6f8512d1d1b0e6a2eb989b56))
|
||||||
|
* upgrade nokogiri ([f05c2e4](https://github.com/postalserver/postal/commit/f05c2e4503688e59a5ef513a5a1064d0ebbb5813))
|
||||||
|
|
||||||
|
|
||||||
|
### Tests
|
||||||
|
|
||||||
|
* rename database spec file ([b9edcf5](https://github.com/postalserver/postal/commit/b9edcf5b7dda7f4976a9d3f90668bbdacea57350))
|
||||||
|
|
||||||
|
## [2.2.1](https://github.com/postalserver/postal/compare/2.2.0...2.2.1) (2024-02-03)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fixes issue starting application in production mode ([4528a14](https://github.com/postalserver/postal/commit/4528a14d273c141e5719f19c3b08c00364b47638))
|
||||||
|
|
||||||
|
|
||||||
|
### Code Refactoring
|
||||||
|
|
||||||
|
* remove Postal.database_url ([96ba4b8](https://github.com/postalserver/postal/commit/96ba4b8f309cfcd1d605e5c7fc05507b21c78c6f))
|
||||||
|
|
||||||
## [2.2.0](https://github.com/postalserver/postal/compare/2.1.6...2.2.0) (2024-02-01)
|
## [2.2.0](https://github.com/postalserver/postal/compare/2.1.6...2.2.0) (2024-02-01)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
12
Gemfile.lock
12
Gemfile.lock
@@ -156,7 +156,7 @@ GEM
|
|||||||
marcel (1.0.2)
|
marcel (1.0.2)
|
||||||
method_source (1.0.0)
|
method_source (1.0.0)
|
||||||
mini_mime (1.1.2)
|
mini_mime (1.1.2)
|
||||||
mini_portile2 (2.8.1)
|
mini_portile2 (2.8.5)
|
||||||
minitest (5.18.0)
|
minitest (5.18.0)
|
||||||
moonrope (2.0.2)
|
moonrope (2.0.2)
|
||||||
deep_merge (~> 1.0)
|
deep_merge (~> 1.0)
|
||||||
@@ -177,19 +177,19 @@ GEM
|
|||||||
activerecord (>= 4.0.0)
|
activerecord (>= 4.0.0)
|
||||||
activesupport (>= 4.0.0)
|
activesupport (>= 4.0.0)
|
||||||
nio4r (2.7.0)
|
nio4r (2.7.0)
|
||||||
nokogiri (1.14.3)
|
nokogiri (1.16.2)
|
||||||
mini_portile2 (~> 2.8.0)
|
mini_portile2 (~> 2.8.2)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.14.3-arm64-darwin)
|
nokogiri (1.16.2-arm64-darwin)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.14.3-x86_64-linux)
|
nokogiri (1.16.2-x86_64-linux)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
parallel (1.22.1)
|
parallel (1.22.1)
|
||||||
parser (3.2.1.1)
|
parser (3.2.1.1)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
puma (6.4.2)
|
puma (6.4.2)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
racc (1.6.2)
|
racc (1.7.3)
|
||||||
rack (2.2.6.4)
|
rack (2.2.6.4)
|
||||||
rack-test (2.1.0)
|
rack-test (2.1.0)
|
||||||
rack (>= 1.3)
|
rack (>= 1.3)
|
||||||
|
|||||||
@@ -1,8 +1,19 @@
|
|||||||
|
default: &default
|
||||||
|
adapter: mysql2
|
||||||
|
reconnect: true
|
||||||
|
encoding: <%= Postal.config.main_db.encoding %>
|
||||||
|
pool: <%= Postal.config.main_db.pool_size %>
|
||||||
|
username: <%= Postal.config.main_db.username %>
|
||||||
|
password: <%= Postal.config.main_db.password %>
|
||||||
|
host: <%= Postal.config.main_db.host %>
|
||||||
|
port: <%= Postal.config.main_db.port %>
|
||||||
|
database: <%= Postal.config.main_db.database %>
|
||||||
|
|
||||||
development:
|
development:
|
||||||
url: <%= Postal.database_url %>
|
<<: *default
|
||||||
|
|
||||||
production:
|
production:
|
||||||
url: <%= Postal.database_url %>
|
<<: *default
|
||||||
|
|
||||||
test:
|
test:
|
||||||
url: <%= Postal.database_url %>
|
<<: *default
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ ActiveSupport::Inflector.inflections(:en) do |inflect|
|
|||||||
|
|
||||||
inflect.acronym "API"
|
inflect.acronym "API"
|
||||||
inflect.acronym "DNS"
|
inflect.acronym "DNS"
|
||||||
|
inflect.acronym "MySQL"
|
||||||
|
|
||||||
inflect.acronym "DB"
|
inflect.acronym "DB"
|
||||||
inflect.acronym "IP"
|
inflect.acronym "IP"
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
require "postal"
|
require "postal"
|
||||||
require "postal/message_db/mysql"
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ main_db:
|
|||||||
password: <%= ENV.fetch('MAIN_DB_PASSWORD', '') %>
|
password: <%= ENV.fetch('MAIN_DB_PASSWORD', '') %>
|
||||||
database: <%= ENV.fetch('MAIN_DB_DATABASE', 'postal') %>
|
database: <%= ENV.fetch('MAIN_DB_DATABASE', 'postal') %>
|
||||||
pool_size: <%= ENV.fetch('MAIN_DB_POOL_SIZE', '5') %>
|
pool_size: <%= ENV.fetch('MAIN_DB_POOL_SIZE', '5') %>
|
||||||
|
encoding: <%= ENV.fetch('MAIN_DB_ENCODING', 'utf8mb4') %>
|
||||||
|
|
||||||
message_db:
|
message_db:
|
||||||
host: <%= ENV.fetch('MESSAGE_DB_HOST', '127.0.0.1') %>
|
host: <%= ENV.fetch('MESSAGE_DB_HOST', '127.0.0.1') %>
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ require_relative "version"
|
|||||||
|
|
||||||
module Postal
|
module Postal
|
||||||
|
|
||||||
|
class Config
|
||||||
|
end
|
||||||
|
|
||||||
def self.host
|
def self.host
|
||||||
@host ||= config.web.host || "localhost:5000"
|
@host ||= config.web.host || "localhost:5000"
|
||||||
end
|
end
|
||||||
@@ -86,14 +89,6 @@ module Postal
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.database_url
|
|
||||||
if config.main_db
|
|
||||||
"mysql2://#{CGI.escape(config.main_db.username.to_s)}:#{CGI.escape(config.main_db.password.to_s)}@#{config.main_db.host}:#{config.main_db.port}/#{config.main_db.database}?reconnect=true&encoding=#{config.main_db.encoding || 'utf8mb4'}&pool=#{config.main_db.pool_size}"
|
|
||||||
else
|
|
||||||
"mysql2://root@localhost/postal"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.logger_for(name)
|
def self.logger_for(name)
|
||||||
@loggers ||= {}
|
@loggers ||= {}
|
||||||
@loggers[name.to_sym] ||= begin
|
@loggers[name.to_sym] ||= begin
|
||||||
|
|||||||
66
lib/postal/message_db/connection_pool.rb
Normal file
66
lib/postal/message_db/connection_pool.rb
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
module Postal
|
||||||
|
module MessageDB
|
||||||
|
class ConnectionPool
|
||||||
|
|
||||||
|
attr_reader :connections
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@connections = []
|
||||||
|
@lock = Mutex.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def use
|
||||||
|
connection = checkout
|
||||||
|
do_not_checkin = false
|
||||||
|
begin
|
||||||
|
yield connection
|
||||||
|
rescue Mysql2::Error => e
|
||||||
|
if e.message =~ /(lost connection|gone away|not connected)/i
|
||||||
|
# If the connection has failed for a connectivity reason
|
||||||
|
# we won't add it back in to the pool so that it'll reconnect
|
||||||
|
# next time.
|
||||||
|
do_not_checkin = true
|
||||||
|
end
|
||||||
|
|
||||||
|
raise
|
||||||
|
ensure
|
||||||
|
checkin(connection) unless do_not_checkin
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def checkout
|
||||||
|
@lock.synchronize do
|
||||||
|
return @connections.pop unless @connections.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
add_new_connection
|
||||||
|
checkout
|
||||||
|
end
|
||||||
|
|
||||||
|
def checkin(connection)
|
||||||
|
@lock.synchronize do
|
||||||
|
@connections << connection
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_new_connection
|
||||||
|
@lock.synchronize do
|
||||||
|
@connections << establish_connection
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def establish_connection
|
||||||
|
Mysql2::Client.new(
|
||||||
|
host: Postal.config.message_db.host,
|
||||||
|
username: Postal.config.message_db.username,
|
||||||
|
password: Postal.config.message_db.password,
|
||||||
|
port: Postal.config.message_db.port,
|
||||||
|
encoding: Postal.config.message_db.encoding || "utf8mb4"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -2,6 +2,14 @@ module Postal
|
|||||||
module MessageDB
|
module MessageDB
|
||||||
class Database
|
class Database
|
||||||
|
|
||||||
|
class << self
|
||||||
|
|
||||||
|
def connection_pool
|
||||||
|
@connection_pool ||= ConnectionPool.new
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
def initialize(organization_id, server_id)
|
def initialize(organization_id, server_id)
|
||||||
@organization_id = organization_id
|
@organization_id = organization_id
|
||||||
@server_id = server_id
|
@server_id = server_id
|
||||||
@@ -339,7 +347,7 @@ module Postal
|
|||||||
end
|
end
|
||||||
|
|
||||||
def with_mysql(&block)
|
def with_mysql(&block)
|
||||||
MessageDB::MySQL.client(&block)
|
self.class.connection_pool.use(&block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_where_string(attributes, joiner = ", ")
|
def build_where_string(attributes, joiner = ", ")
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
module Postal
|
|
||||||
module MessageDB
|
|
||||||
module MySQL
|
|
||||||
|
|
||||||
# This exists here because it needs to be required when the application loads
|
|
||||||
# so that it isn't unloaded in development. If it was unloaded in development,
|
|
||||||
# it would be undesirable as we'd just end up with lots of connections.
|
|
||||||
|
|
||||||
def self.new_client
|
|
||||||
Mysql2::Client.new(host: Postal.config.message_db.host, username: Postal.config.message_db.username, password: Postal.config.message_db.password, port: Postal.config.message_db.port, reconnect: true, encoding: Postal.config.message_db.encoding || "utf8mb4")
|
|
||||||
end
|
|
||||||
|
|
||||||
@free_clients = []
|
|
||||||
|
|
||||||
def self.client(&block)
|
|
||||||
client = @free_clients.shift || new_client
|
|
||||||
return_value = nil
|
|
||||||
tries = 2
|
|
||||||
begin
|
|
||||||
return_value = block.call(client)
|
|
||||||
rescue Mysql2::Error => e
|
|
||||||
raise unless e.message =~ /(lost connection|gone away)/i && (tries -= 1) > 0
|
|
||||||
|
|
||||||
retry
|
|
||||||
ensure
|
|
||||||
@free_clients << client
|
|
||||||
end
|
|
||||||
return_value
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -11,4 +11,6 @@ module Postal
|
|||||||
VERSION
|
VERSION
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Version = VERSION
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
45
spec/lib/postal/message_db/connection_pool_spec.rb
Normal file
45
spec/lib/postal/message_db/connection_pool_spec.rb
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
require "rails_helper"
|
||||||
|
|
||||||
|
describe Postal::MessageDB::ConnectionPool do
|
||||||
|
|
||||||
|
subject(:pool) { described_class.new }
|
||||||
|
|
||||||
|
describe '#use' do
|
||||||
|
it 'yields a connection' do
|
||||||
|
counter = 0
|
||||||
|
pool.use do |connection|
|
||||||
|
expect(connection).to be_a Mysql2::Client
|
||||||
|
counter += 1
|
||||||
|
end
|
||||||
|
expect(counter).to eq 1
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'checks in a connection after the block has executed' do
|
||||||
|
connection = nil
|
||||||
|
pool.use do |c|
|
||||||
|
expect(pool.connections).to be_empty
|
||||||
|
connection = c
|
||||||
|
end
|
||||||
|
expect(pool.connections).to eq [connection]
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'checks in a connection if theres an error in the block' do
|
||||||
|
expect do
|
||||||
|
pool.use do |c|
|
||||||
|
raise StandardError
|
||||||
|
end
|
||||||
|
end.to raise_error StandardError
|
||||||
|
expect(pool.connections).to match [kind_of(Mysql2::Client)]
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not check in connections when there is a connection error' do
|
||||||
|
expect do
|
||||||
|
pool.use do
|
||||||
|
raise Mysql2::Error, "lost connection to server"
|
||||||
|
end
|
||||||
|
end.to raise_error Mysql2::Error
|
||||||
|
expect(pool.connections).to eq []
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
المرجع في مشكلة جديدة
حظر مستخدم