Improved Setting.get and Setting.set - reduced database access and moved from 2 minutes to 15 seconds ttl for reading.
This commit is contained in:
parent
6bf970b85d
commit
1eaf46f466
2 changed files with 88 additions and 122 deletions
|
@ -7,22 +7,21 @@ class Setting < ApplicationModel
|
||||||
store :preferences
|
store :preferences
|
||||||
before_create :state_check, :set_initial, :check_broadcast
|
before_create :state_check, :set_initial, :check_broadcast
|
||||||
before_update :state_check, :check_broadcast
|
before_update :state_check, :check_broadcast
|
||||||
after_create :reset_cache
|
after_create :reset_change_id
|
||||||
after_update :reset_cache
|
after_update :reset_change_id
|
||||||
after_destroy :reset_cache
|
|
||||||
|
|
||||||
attr_accessor :state
|
attr_accessor :state
|
||||||
|
|
||||||
@@current = {} # rubocop:disable Style/ClassVars
|
@@current = {} # rubocop:disable Style/ClassVars
|
||||||
@@change_id = nil # rubocop:disable Style/ClassVars
|
@@raw = {} # rubocop:disable Style/ClassVars
|
||||||
@@lookup_at = nil # rubocop:disable Style/ClassVars
|
@@change_id = nil # rubocop:disable Style/ClassVars
|
||||||
@@lookup_timeout = if ENV['ZAMMAD_SETTING_TTL'] # rubocop:disable Style/ClassVars
|
@@last_changed_at = nil # rubocop:disable Style/ClassVars
|
||||||
ENV['ZAMMAD_SETTING_TTL'].to_i.seconds
|
@@lookup_at = nil # rubocop:disable Style/ClassVars
|
||||||
elsif Rails.env.production?
|
@@lookup_timeout = if ENV['ZAMMAD_SETTING_TTL'] # rubocop:disable Style/ClassVars
|
||||||
2.minutes
|
ENV['ZAMMAD_SETTING_TTL'].to_i.seconds
|
||||||
else
|
else
|
||||||
15.seconds
|
15.seconds
|
||||||
end
|
end
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
@ -38,7 +37,7 @@ set config setting
|
||||||
raise "Can't find config setting '#{name}'"
|
raise "Can't find config setting '#{name}'"
|
||||||
end
|
end
|
||||||
setting.state_current = { value: value }
|
setting.state_current = { value: value }
|
||||||
setting.save
|
setting.save!
|
||||||
logger.info "Setting.set(#{name}, #{value.inspect})"
|
logger.info "Setting.set(#{name}, #{value.inspect})"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -52,7 +51,7 @@ get config setting
|
||||||
|
|
||||||
def self.get(name)
|
def self.get(name)
|
||||||
load
|
load
|
||||||
@@current[:settings_config][name]
|
@@current[name]
|
||||||
end
|
end
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
@ -69,10 +68,8 @@ reset config setting to default
|
||||||
raise "Can't find config setting '#{name}'"
|
raise "Can't find config setting '#{name}'"
|
||||||
end
|
end
|
||||||
setting.state_current = setting.state_initial
|
setting.state_current = setting.state_initial
|
||||||
setting.save
|
setting.save!
|
||||||
logger.info "Setting.reset(#{name}, #{setting.state_current.inspect})"
|
logger.info "Setting.reset(#{name}, #{setting.state_current.inspect})"
|
||||||
load
|
|
||||||
@@current[:settings_config][name]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
@ -84,6 +81,7 @@ reload config settings
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def self.reload
|
def self.reload
|
||||||
|
@@last_changed_at = nil # rubocop:disable Style/ClassVars
|
||||||
load(true)
|
load(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -93,27 +91,36 @@ reload config settings
|
||||||
def self.load(force = false)
|
def self.load(force = false)
|
||||||
|
|
||||||
# check if config is already generated
|
# check if config is already generated
|
||||||
if !force && @@current[:settings_config]
|
return false if !force && @@current.present? && cache_valid?
|
||||||
return false if cache_valid?
|
|
||||||
|
# read all or only changed since last read
|
||||||
|
latest = Setting.order(updated_at: :desc).limit(1).pluck(:updated_at)
|
||||||
|
settings = if @@last_changed_at && @@current.present?
|
||||||
|
Setting.where('updated_at > ?', @@last_changed_at).order(:id).pluck(:name, :state_current)
|
||||||
|
else
|
||||||
|
Setting.order(:id).pluck(:name, :state_current)
|
||||||
|
end
|
||||||
|
if latest
|
||||||
|
@@last_changed_at = latest[0] # rubocop:disable Style/ClassVars
|
||||||
end
|
end
|
||||||
|
|
||||||
# read all config settings
|
if settings.present?
|
||||||
config = {}
|
settings.each { |setting|
|
||||||
Setting.select('name, state_current').order(:id).each { |setting|
|
@@raw[setting[0]] = setting[1]['value']
|
||||||
config[setting.name] = setting.state_current[:value]
|
|
||||||
}
|
|
||||||
|
|
||||||
# config lookups
|
|
||||||
config.each { |key, value|
|
|
||||||
next if value.class.to_s != 'String'
|
|
||||||
|
|
||||||
config[key].gsub!(/\#\{config\.(.+?)\}/) {
|
|
||||||
config[$1].to_s
|
|
||||||
}
|
}
|
||||||
}
|
@@raw.each { |key, value|
|
||||||
|
if value.class != String
|
||||||
|
@@current[key] = value
|
||||||
|
next
|
||||||
|
end
|
||||||
|
@@current[key] = value.gsub(/\#\{config\.(.+?)\}/) {
|
||||||
|
@@raw[$1].to_s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
# store for class requests
|
@@change_id = Cache.get('Setting::ChangeId') # rubocop:disable Style/ClassVars
|
||||||
cache(config)
|
@@lookup_at = Time.zone.now # rubocop:disable Style/ClassVars
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
private_class_method :load
|
private_class_method :load
|
||||||
|
@ -123,37 +130,27 @@ reload config settings
|
||||||
self.state_initial = state_current
|
self.state_initial = state_current
|
||||||
end
|
end
|
||||||
|
|
||||||
# set new cache
|
def reset_change_id
|
||||||
def self.cache(config)
|
@@current[name] = state_current[:value]
|
||||||
@@change_id = Cache.get('Setting::ChangeId') # rubocop:disable Style/ClassVars
|
change_id = rand(999_999_999).to_s
|
||||||
@@current[:settings_config] = config
|
logger.debug "Setting.reset_change_id: set new cache, #{change_id}"
|
||||||
logger.debug "Setting.cache: set cache, #{@@change_id}"
|
Cache.write('Setting::ChangeId', change_id, { expires_in: 24.hours })
|
||||||
@@lookup_at = Time.zone.now # rubocop:disable Style/ClassVars
|
@@lookup_at = nil # rubocop:disable Style/ClassVars
|
||||||
end
|
|
||||||
private_class_method :cache
|
|
||||||
|
|
||||||
# reset cache
|
|
||||||
def reset_cache
|
|
||||||
@@change_id = rand(999_999_999).to_s # rubocop:disable Style/ClassVars
|
|
||||||
logger.debug "Setting.reset_cache: set new cache, #{@@change_id}"
|
|
||||||
|
|
||||||
Cache.write('Setting::ChangeId', @@change_id, { expires_in: 24.hours })
|
|
||||||
@@current[:settings_config] = nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# check if cache is still valid
|
# check if cache is still valid
|
||||||
def self.cache_valid?
|
def self.cache_valid?
|
||||||
if @@lookup_at && @@lookup_at > Time.zone.now - @@lookup_timeout
|
if @@lookup_at && @@lookup_at > Time.zone.now - @@lookup_timeout
|
||||||
#logger.debug 'Setting.cache_valid?: cache_id has beed set within last 2 minutes'
|
#logger.debug "Setting.cache_valid?: cache_id has been set within last #{@@lookup_timeout} seconds"
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
change_id = Cache.get('Setting::ChangeId')
|
change_id = Cache.get('Setting::ChangeId')
|
||||||
if change_id == @@change_id
|
if change_id == @@change_id
|
||||||
@@lookup_at = Time.zone.now # rubocop:disable Style/ClassVars
|
@@lookup_at = Time.zone.now # rubocop:disable Style/ClassVars
|
||||||
logger.debug "Setting.cache_valid?: cache still valid, #{@@change_id}/#{change_id}"
|
#logger.debug "Setting.cache_valid?: cache still valid, #{@@change_id}/#{change_id}"
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
logger.debug "Setting.cache_valid?: cache has changed, #{@@change_id}/#{change_id}"
|
#logger.debug "Setting.cache_valid?: cache has changed, #{@@change_id}/#{change_id}"
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
private_class_method :cache_valid?
|
private_class_method :cache_valid?
|
||||||
|
|
|
@ -7,65 +7,34 @@ class SipgateControllerTest < ActionDispatch::IntegrationTest
|
||||||
|
|
||||||
Cti::Log.destroy_all
|
Cti::Log.destroy_all
|
||||||
|
|
||||||
Setting.create_or_update(
|
Setting.set('sipgate_integration', true)
|
||||||
title: 'sipgate.io integration',
|
Setting.set('sipgate_config', {
|
||||||
name: 'sipgate_integration',
|
outbound: {
|
||||||
area: 'Integration::Switch',
|
routing_table: [
|
||||||
description: 'Define if sipgate.io (http://www.sipgate.io) is enabled or not.',
|
{
|
||||||
options: {
|
dest: '41*',
|
||||||
form: [
|
caller_id: '41715880339000',
|
||||||
{
|
},
|
||||||
display: '',
|
{
|
||||||
null: true,
|
dest: '491714000000',
|
||||||
name: 'sipgate_integration',
|
caller_id: '41715880339000',
|
||||||
tag: 'boolean',
|
},
|
||||||
options: {
|
],
|
||||||
true => 'yes',
|
default_caller_id: '4930777000000',
|
||||||
false => 'no',
|
},
|
||||||
},
|
inbound: {
|
||||||
},
|
block_caller_ids: [
|
||||||
],
|
{
|
||||||
},
|
caller_id: '491715000000',
|
||||||
state: true,
|
note: 'some note',
|
||||||
preferences: { prio: 1 },
|
}
|
||||||
frontend: false
|
],
|
||||||
)
|
notify_user_ids: {
|
||||||
Setting.create_or_update(
|
2 => true,
|
||||||
title: 'sipgate.io config',
|
4 => false,
|
||||||
name: 'sipgate_config',
|
},
|
||||||
area: 'Integration::Sipgate',
|
}
|
||||||
description: 'Define the sipgate.io config.',
|
},)
|
||||||
options: {},
|
|
||||||
state: {
|
|
||||||
outbound: {
|
|
||||||
routing_table: [
|
|
||||||
{
|
|
||||||
dest: '41*',
|
|
||||||
caller_id: '41715880339000',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
dest: '491714000000',
|
|
||||||
caller_id: '41715880339000',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
default_caller_id: '4930777000000',
|
|
||||||
},
|
|
||||||
inbound: {
|
|
||||||
block_caller_ids: [
|
|
||||||
{
|
|
||||||
caller_id: '491715000000',
|
|
||||||
note: 'some note',
|
|
||||||
}
|
|
||||||
],
|
|
||||||
notify_user_ids: {
|
|
||||||
2 => true,
|
|
||||||
4 => false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
frontend: false,
|
|
||||||
preferences: { prio: 2 },
|
|
||||||
)
|
|
||||||
|
|
||||||
groups = Group.where(name: 'Users')
|
groups = Group.where(name: 'Users')
|
||||||
roles = Role.where(name: %w(Agent))
|
roles = Role.where(name: %w(Agent))
|
||||||
|
@ -262,7 +231,7 @@ class SipgateControllerTest < ActionDispatch::IntegrationTest
|
||||||
assert_equal('out', log.direction)
|
assert_equal('out', log.direction)
|
||||||
assert_equal('user 1', log.from_comment)
|
assert_equal('user 1', log.from_comment)
|
||||||
assert_equal('CallerId Customer1', log.to_comment)
|
assert_equal('CallerId Customer1', log.to_comment)
|
||||||
assert_equal(nil, log.comment)
|
assert_nil(log.comment)
|
||||||
assert_equal('newCall', log.state)
|
assert_equal('newCall', log.state)
|
||||||
assert_equal(true, log.done)
|
assert_equal(true, log.done)
|
||||||
|
|
||||||
|
@ -292,7 +261,7 @@ class SipgateControllerTest < ActionDispatch::IntegrationTest
|
||||||
assert_equal('out', log.direction)
|
assert_equal('out', log.direction)
|
||||||
assert_equal('user 1', log.from_comment)
|
assert_equal('user 1', log.from_comment)
|
||||||
assert_equal('CallerId Customer1', log.to_comment)
|
assert_equal('CallerId Customer1', log.to_comment)
|
||||||
assert_equal(nil, log.comment)
|
assert_nil(log.comment)
|
||||||
assert_equal('newCall', log.state)
|
assert_equal('newCall', log.state)
|
||||||
assert_equal(true, log.done)
|
assert_equal(true, log.done)
|
||||||
|
|
||||||
|
@ -307,7 +276,7 @@ class SipgateControllerTest < ActionDispatch::IntegrationTest
|
||||||
assert_equal('out', log.direction)
|
assert_equal('out', log.direction)
|
||||||
assert_equal('user 1', log.from_comment)
|
assert_equal('user 1', log.from_comment)
|
||||||
assert_equal('CallerId Customer1', log.to_comment)
|
assert_equal('CallerId Customer1', log.to_comment)
|
||||||
assert_equal(nil, log.comment)
|
assert_nil(log.comment)
|
||||||
assert_equal('answer', log.state)
|
assert_equal('answer', log.state)
|
||||||
assert_equal(true, log.done)
|
assert_equal(true, log.done)
|
||||||
|
|
||||||
|
@ -337,7 +306,7 @@ class SipgateControllerTest < ActionDispatch::IntegrationTest
|
||||||
assert_equal('in', log.direction)
|
assert_equal('in', log.direction)
|
||||||
assert_equal('user 1', log.to_comment)
|
assert_equal('user 1', log.to_comment)
|
||||||
assert_equal('CallerId Customer1', log.from_comment)
|
assert_equal('CallerId Customer1', log.from_comment)
|
||||||
assert_equal(nil, log.comment)
|
assert_nil(log.comment)
|
||||||
assert_equal('newCall', log.state)
|
assert_equal('newCall', log.state)
|
||||||
assert_equal(true, log.done)
|
assert_equal(true, log.done)
|
||||||
|
|
||||||
|
@ -352,7 +321,7 @@ class SipgateControllerTest < ActionDispatch::IntegrationTest
|
||||||
assert_equal('in', log.direction)
|
assert_equal('in', log.direction)
|
||||||
assert_equal('user 1', log.to_comment)
|
assert_equal('user 1', log.to_comment)
|
||||||
assert_equal('CallerId Customer1', log.from_comment)
|
assert_equal('CallerId Customer1', log.from_comment)
|
||||||
assert_equal(nil, log.comment)
|
assert_nil(log.comment)
|
||||||
assert_equal('answer', log.state)
|
assert_equal('answer', log.state)
|
||||||
assert_equal(true, log.done)
|
assert_equal(true, log.done)
|
||||||
|
|
||||||
|
@ -382,7 +351,7 @@ class SipgateControllerTest < ActionDispatch::IntegrationTest
|
||||||
assert_equal('in', log.direction)
|
assert_equal('in', log.direction)
|
||||||
assert_equal('user 1,user 2', log.to_comment)
|
assert_equal('user 1,user 2', log.to_comment)
|
||||||
assert_equal('CallerId Customer1', log.from_comment)
|
assert_equal('CallerId Customer1', log.from_comment)
|
||||||
assert_equal(nil, log.comment)
|
assert_nil(log.comment)
|
||||||
assert_equal('newCall', log.state)
|
assert_equal('newCall', log.state)
|
||||||
assert_equal(true, log.done)
|
assert_equal(true, log.done)
|
||||||
|
|
||||||
|
@ -397,7 +366,7 @@ class SipgateControllerTest < ActionDispatch::IntegrationTest
|
||||||
assert_equal('in', log.direction)
|
assert_equal('in', log.direction)
|
||||||
assert_equal('voicemail', log.to_comment)
|
assert_equal('voicemail', log.to_comment)
|
||||||
assert_equal('CallerId Customer1', log.from_comment)
|
assert_equal('CallerId Customer1', log.from_comment)
|
||||||
assert_equal(nil, log.comment)
|
assert_nil(log.comment)
|
||||||
assert_equal('answer', log.state)
|
assert_equal('answer', log.state)
|
||||||
assert_equal(true, log.done)
|
assert_equal(true, log.done)
|
||||||
|
|
||||||
|
@ -427,7 +396,7 @@ class SipgateControllerTest < ActionDispatch::IntegrationTest
|
||||||
assert_equal('in', log.direction)
|
assert_equal('in', log.direction)
|
||||||
assert_equal('user 1,user 2', log.to_comment)
|
assert_equal('user 1,user 2', log.to_comment)
|
||||||
assert_equal('CallerId Customer1', log.from_comment)
|
assert_equal('CallerId Customer1', log.from_comment)
|
||||||
assert_equal(nil, log.comment)
|
assert_nil(log.comment)
|
||||||
assert_equal('newCall', log.state)
|
assert_equal('newCall', log.state)
|
||||||
assert_equal(true, log.done)
|
assert_equal(true, log.done)
|
||||||
|
|
||||||
|
@ -459,7 +428,7 @@ class SipgateControllerTest < ActionDispatch::IntegrationTest
|
||||||
assert_equal('CallerId Customer3,CallerId Customer2', log.from_comment)
|
assert_equal('CallerId Customer3,CallerId Customer2', log.from_comment)
|
||||||
assert_not(log.preferences['to'])
|
assert_not(log.preferences['to'])
|
||||||
assert(log.preferences['from'])
|
assert(log.preferences['from'])
|
||||||
assert_equal(nil, log.comment)
|
assert_nil(log.comment)
|
||||||
assert_equal('newCall', log.state)
|
assert_equal('newCall', log.state)
|
||||||
assert_equal(true, log.done)
|
assert_equal(true, log.done)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue