allow to specify how many times we can try to connect to the database at startup
add config options: db_startup_connection_max_attempts - default 0 (infinite) db_startup_connection_attempt_delay - delay in seconds between attempts (default 5) BREAKING CHANGE: WINIX_PLUGIN_INIT plugin message requires to set result status, you have to set the result status to true (env.res) if your plugin was initialized correctly, otherwise winix will not start
This commit is contained in:
parent
c6c50a5d23
commit
da2dec447b
|
@ -178,7 +178,7 @@ Log & App::GetMainLog()
|
|||
|
||||
|
||||
|
||||
void App::InitPlugins()
|
||||
void App::LoadPlugins()
|
||||
{
|
||||
plugin.LoadPlugins(config.plugins_dir, config.plugin_file);
|
||||
}
|
||||
|
@ -350,8 +350,26 @@ bool App::TryToMakeDatabaseMigration()
|
|||
}
|
||||
|
||||
|
||||
bool App::InitializePlugins()
|
||||
{
|
||||
PluginRes plugin_res = plugin.Call((Session*)0, WINIX_PLUGIN_INIT);
|
||||
|
||||
if( plugin_res.res_false > 0 )
|
||||
{
|
||||
log << log1 << "App: " << plugin_res.res_false << " plugin(s) cannot initialize itself, exiting" << logend;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool App::Init()
|
||||
{
|
||||
// load plugins before loading sessions - session_manager.LoadSessions()
|
||||
// because some of the plugins can init its own sessions dates
|
||||
LoadPlugins();
|
||||
|
||||
if( !config.db_conn_string.empty() )
|
||||
postgresql_connector.set_conn_param(config.db_conn_string);
|
||||
else
|
||||
|
@ -359,7 +377,11 @@ bool App::Init()
|
|||
|
||||
postgresql_connector.set_logger(log);
|
||||
postgresql_connector.set_log_queries(config.log_db_query);
|
||||
postgresql_connector.wait_for_connection();
|
||||
|
||||
if( !postgresql_connector.wait_for_connection(config.db_startup_connection_max_attempts, config.db_startup_connection_attempt_delay) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
model_connector.set_flat_connector(json_connector);
|
||||
model_connector.set_db_connector(postgresql_connector);
|
||||
|
@ -378,6 +400,7 @@ bool App::Init()
|
|||
model_connector.set_winix_time_zones(&system.time_zones);
|
||||
model_connector.set_winix_pattern_cacher(&TemplatesFunctions::pattern_cacher);
|
||||
|
||||
// CHECKME this will call WINIX_MAKE_DATABASE_MIGRATION, but WINIX_PLUGIN_INIT was not called yet, it is correct?
|
||||
if( !TryToMakeDatabaseMigration() )
|
||||
return false;
|
||||
|
||||
|
@ -387,13 +410,17 @@ bool App::Init()
|
|||
else
|
||||
db_conn.SetConnParam(config.db_host, config.db_hostaddr, config.db_port, config.db_database, config.db_user, config.db_pass);
|
||||
|
||||
db_conn.WaitForConnection();
|
||||
if( !db_conn.WaitForConnection(config.db_startup_connection_max_attempts, config.db_startup_connection_attempt_delay) )
|
||||
return false;
|
||||
|
||||
db.LogQueries(config.log_db_query);
|
||||
|
||||
cur.request->Clear();
|
||||
compress.set_dependency(&winix_base);
|
||||
compress.Init();
|
||||
system.Init();
|
||||
|
||||
if( !system.Init() )
|
||||
return false;
|
||||
|
||||
functions.Init();
|
||||
templates.Init(); // init templates after functions are created
|
||||
|
@ -414,9 +441,10 @@ bool App::Init()
|
|||
|
||||
cookie_parser.set_dependency(&winix_model);
|
||||
|
||||
plugin.Call((Session*)0, WINIX_PLUGIN_INIT);
|
||||
if( !AddSystemThreads() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return InitializePlugins();
|
||||
}
|
||||
|
||||
|
||||
|
@ -2788,6 +2816,15 @@ int sig;
|
|||
}
|
||||
|
||||
|
||||
bool App::AddSystemThreads()
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
ok = ok && system.thread_manager.Add(&session_manager, L"session_manager");
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
void App::StartThreads()
|
||||
{
|
||||
|
@ -2797,7 +2834,7 @@ void App::StartThreads()
|
|||
// special thread only for signals
|
||||
pthread_create(&signal_thread, 0, SpecialThreadForSignals, this);
|
||||
|
||||
system.thread_manager.Add(&session_manager, L"session_manager");
|
||||
// start all threads from thread manager
|
||||
system.thread_manager.StartAll();
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,8 @@ public:
|
|||
bool DropPrivileges();
|
||||
void InitLoggers();
|
||||
Log & GetMainLog();
|
||||
void InitPlugins();
|
||||
void LoadPlugins();
|
||||
bool InitializePlugins();
|
||||
bool Init();
|
||||
void Start();
|
||||
void Close();
|
||||
|
@ -188,6 +189,8 @@ private:
|
|||
// file logger, one object for all Log objects
|
||||
FileLog file_log;
|
||||
|
||||
bool AddSystemThreads();
|
||||
|
||||
bool TranslateFCGInames(char * sock, char * sock_user, char * sock_group);
|
||||
bool InitFCGIChmodChownSocket(char * sock, char * sock_user, char * sock_group);
|
||||
bool DropPrivileges(char * user, char * group);
|
||||
|
|
|
@ -187,9 +187,12 @@ void Config::AssignValues()
|
|||
db_database = Text(L"db_database");
|
||||
db_user = Text(L"db_user");
|
||||
db_pass = Text(L"db_pass");
|
||||
db_startup_connection_max_attempts = Size(L"db_startup_connection_max_attempts", 0);
|
||||
db_startup_connection_attempt_delay = Size(L"db_startup_connection_attempt_delay", 5);
|
||||
db_make_migration_if_needed = Bool(L"db_make_migration_if_needed", true);
|
||||
db_stop_if_migration_fails = Bool(L"db_stop_if_migration_fails", true);
|
||||
|
||||
|
||||
item_url_empty = Text(L"item_url_empty");
|
||||
|
||||
url_proto = Text(L"url_proto", L"http://");
|
||||
|
|
|
@ -242,12 +242,21 @@ public:
|
|||
std::wstring db_user;
|
||||
std::wstring db_pass;
|
||||
|
||||
// specify how many times we can try to connect to the database at startup
|
||||
// default 0 (infinite)
|
||||
size_t db_startup_connection_max_attempts;
|
||||
|
||||
// delay between each connection attempt at startup
|
||||
// default 5 (seconds)
|
||||
size_t db_startup_connection_attempt_delay;
|
||||
|
||||
// make database migration if needed
|
||||
//
|
||||
bool db_make_migration_if_needed;
|
||||
|
||||
// if a migration fails then stop winix
|
||||
bool db_stop_if_migration_fails;
|
||||
|
||||
|
||||
// the name of the cookie which has the session identifier
|
||||
std::wstring http_session_id_name;
|
||||
|
||||
|
|
|
@ -144,6 +144,8 @@ namespace Winix
|
|||
// winix is initialized,
|
||||
// now you can initialize your plugin
|
||||
// session pointer is null
|
||||
// you have to set the result status to true (env.res) if your
|
||||
// plugin was initialized correctly, otherwise winix will not start
|
||||
#define WINIX_PLUGIN_INIT 30080
|
||||
|
||||
// winix is ready to remove a plugin
|
||||
|
|
|
@ -124,7 +124,7 @@ void System::ReadTimeZones()
|
|||
}
|
||||
|
||||
|
||||
void System::Init()
|
||||
bool System::Init()
|
||||
{
|
||||
//thread_manager.SetSynchro(synchro);
|
||||
thread_manager.Init();
|
||||
|
@ -157,21 +157,24 @@ void System::Init()
|
|||
notify.SetUsers(&users);
|
||||
notify.SetDirs(&dirs);
|
||||
notify.SetThreadManager(&thread_manager);
|
||||
notify.Init();
|
||||
|
||||
if( !notify.Init() )
|
||||
return false;
|
||||
|
||||
image.SetDb(db);
|
||||
image.SetConfig(config);
|
||||
image.SetSystem(this);
|
||||
thread_manager.Add(&image, L"image");
|
||||
|
||||
|
||||
|
||||
if( !thread_manager.Add(&image, L"image") )
|
||||
return false;
|
||||
|
||||
// SetSynchro will be called by ThreadManager itself
|
||||
// job.ReadFromFile();
|
||||
thread_manager.Add(&job, L"job");
|
||||
if( !thread_manager.Add(&job, L"job") )
|
||||
return false;
|
||||
|
||||
ReadTimeZones();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ public:
|
|||
|
||||
void set_dependency(WinixModelDeprecated * winix_model);
|
||||
|
||||
void Init();
|
||||
bool Init();
|
||||
|
||||
void AddParams(const ParamTab & param_tab, std::wstring & str, bool clear_str = true);
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ sigset_t set;
|
|||
|
||||
|
||||
|
||||
void ThreadManager::Add(BaseThread * pbase, const wchar_t * thread_name)
|
||||
bool ThreadManager::Add(BaseThread * pbase, const wchar_t * thread_name)
|
||||
{
|
||||
thread_tab.emplace_back();
|
||||
ThreadItem & item = thread_tab.back();
|
||||
|
@ -96,7 +96,14 @@ void ThreadManager::Add(BaseThread * pbase, const wchar_t * thread_name)
|
|||
|
||||
data.postgresql_connector.set_logger(item.object->get_logger());
|
||||
data.postgresql_connector.set_log_queries(config->log_db_query);
|
||||
data.postgresql_connector.wait_for_connection();
|
||||
|
||||
if( !data.postgresql_connector.wait_for_connection(config->db_startup_connection_max_attempts, config->db_startup_connection_attempt_delay) )
|
||||
{
|
||||
Log * plog = item.object->get_logger();
|
||||
(*plog) << logsave;
|
||||
return false;
|
||||
}
|
||||
|
||||
data.model_connector.set_db_connector(data.postgresql_connector);
|
||||
data.model_connector.set_flat_connector(data.json_connector);
|
||||
data.model_connector.set_logger(item.object->get_logger());
|
||||
|
@ -125,23 +132,26 @@ void ThreadManager::Add(BaseThread * pbase, const wchar_t * thread_name)
|
|||
log << log4 << "TM: added a thread to the queue, number: " << (thread_tab.size()-1)
|
||||
<< ", name: " << thread_name << logend;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void ThreadManager::Add(BaseThread & pbase, const wchar_t * thread_name)
|
||||
bool ThreadManager::Add(BaseThread & pbase, const wchar_t * thread_name)
|
||||
{
|
||||
Add(&pbase, thread_name);
|
||||
return Add(&pbase, thread_name);
|
||||
}
|
||||
|
||||
|
||||
void ThreadManager::Add(BaseThread * pbase, const std::wstring & thread_name)
|
||||
bool ThreadManager::Add(BaseThread * pbase, const std::wstring & thread_name)
|
||||
{
|
||||
Add(pbase, thread_name.c_str());
|
||||
return Add(pbase, thread_name.c_str());
|
||||
}
|
||||
|
||||
void ThreadManager::Add(BaseThread & pbase, const std::wstring & thread_name)
|
||||
|
||||
bool ThreadManager::Add(BaseThread & pbase, const std::wstring & thread_name)
|
||||
{
|
||||
Add(&pbase, thread_name.c_str());
|
||||
return Add(&pbase, thread_name.c_str());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -59,10 +59,10 @@ public:
|
|||
// adding a new thread to the queue
|
||||
// the thread will be running only if we call StartAll() before
|
||||
// otherwise the thread will be waiting for StartAll()
|
||||
void Add(BaseThread * pbase, const wchar_t * thread_name);
|
||||
void Add(BaseThread & pbase, const wchar_t * thread_name);
|
||||
void Add(BaseThread * pbase, const std::wstring & thread_name);
|
||||
void Add(BaseThread & pbase, const std::wstring & thread_name);
|
||||
bool Add(BaseThread * pbase, const wchar_t * thread_name);
|
||||
bool Add(BaseThread & pbase, const wchar_t * thread_name);
|
||||
bool Add(BaseThread * pbase, const std::wstring & thread_name);
|
||||
bool Add(BaseThread & pbase, const std::wstring & thread_name);
|
||||
|
||||
// starting all threads
|
||||
void StartAll();
|
||||
|
|
|
@ -130,26 +130,63 @@ void DbConn::Connect()
|
|||
}
|
||||
|
||||
|
||||
void DbConn::LogNoConnection(size_t attempts)
|
||||
{
|
||||
log << log2 << "Db: connection to the database cannot be established";
|
||||
log << ", (" << attempts << " attempt(s))" << logend;
|
||||
log << logsave;
|
||||
}
|
||||
|
||||
|
||||
void DbConn::LogConnectionSocket()
|
||||
{
|
||||
log << log2 << "Db: connection to the database works fine" << logend;
|
||||
log << log3 << "Db: connection socket: " << PQsocket(pg_conn) << logend;
|
||||
log << logsave;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DbConn::WaitForConnection()
|
||||
bool DbConn::WaitForConnection(size_t attempts_max, size_t attempt_delay)
|
||||
{
|
||||
size_t attempts = 0;
|
||||
bool attempts_exceeded = false;
|
||||
|
||||
if( attempt_delay == 0 )
|
||||
attempt_delay = 1;
|
||||
|
||||
if( attempt_delay > 120 )
|
||||
attempt_delay = 120;
|
||||
|
||||
if( !pg_conn || PQstatus(pg_conn) != CONNECTION_OK )
|
||||
{
|
||||
log << log3 << "Db: waiting for the db to be ready...." << logend << logsave;
|
||||
|
||||
while( !AssertConnection(false, false) )
|
||||
sleep(5);
|
||||
while( !attempts_exceeded && !AssertConnection(false, false) )
|
||||
{
|
||||
if( attempts_max != 0 )
|
||||
{
|
||||
attempts += 1;
|
||||
attempts_exceeded = (attempts >= attempts_max);
|
||||
}
|
||||
|
||||
if( !attempts_exceeded )
|
||||
{
|
||||
sleep(attempt_delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( attempts_exceeded )
|
||||
{
|
||||
LogNoConnection(attempts);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogConnectionSocket();
|
||||
}
|
||||
|
||||
return !attempts_exceeded;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ public:
|
|||
void SetConnParam(const std::wstring & host, const std::wstring & hostaddr, const std::wstring & port,
|
||||
const std::wstring & database, const std::wstring & user, const std::wstring & pass);
|
||||
void Connect();
|
||||
void WaitForConnection();
|
||||
bool WaitForConnection(size_t attempts_max, size_t attempt_delay);
|
||||
void Close();
|
||||
bool AssertConnection(bool put_log = true, bool throw_if_no_connection = true);
|
||||
void SetDbParameters();
|
||||
|
@ -65,6 +65,7 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
void LogNoConnection(size_t attempts);
|
||||
void LogConnectionSocket();
|
||||
|
||||
PGconn * pg_conn;
|
||||
|
|
|
@ -353,10 +353,6 @@ using Winix::app;
|
|||
app.LogUserGroups();
|
||||
Winix::SavePidFile(log);
|
||||
|
||||
// load plugins before loading sessions - session_manager.LoadSessions()
|
||||
// because some of the plugins can init its own sessions dates
|
||||
app.InitPlugins();
|
||||
|
||||
// app.Init() starts other threads as well (they will be waiting on the lock)
|
||||
if( !app.Init() )
|
||||
{
|
||||
|
|
|
@ -85,14 +85,16 @@ void Notify::SetThreadManager(ThreadManager * pmanager)
|
|||
|
||||
|
||||
|
||||
void Notify::Init()
|
||||
bool Notify::Init()
|
||||
{
|
||||
//notify_thread.SetConfig(config);
|
||||
notify_thread.SetUsers(users);
|
||||
notify_thread.SetNotifyPool(¬ify_pool);
|
||||
notify_thread.SetPatterns(&patterns);
|
||||
//notify_thread.SetFileLog(file_log);
|
||||
thread_manager->Add(¬ify_thread, L"notifications");
|
||||
|
||||
if( !thread_manager->Add(¬ify_thread, L"notifications") )
|
||||
return false;
|
||||
|
||||
patterns.SetDirectories(config->txt_templates_dir, config->txt_templates_dir_default);
|
||||
patterns.SetLocale(&TemplatesFunctions::locale);
|
||||
|
@ -103,6 +105,8 @@ void Notify::Init()
|
|||
notify_template_reset_password = AddTemplate(L"notify_reset_password.txt");
|
||||
|
||||
plugin->Call((Session*)0, WINIX_NOTIFY_ADD_TEMPLATE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ public:
|
|||
void SetThreadManager(ThreadManager * pmanager);
|
||||
//void SetFileLog(FileLog * file_log);
|
||||
|
||||
void Init();
|
||||
bool Init();
|
||||
|
||||
size_t AddTemplate(const std::wstring & file_name);
|
||||
void ReadTemplates();
|
||||
|
|
|
@ -87,7 +87,7 @@ void InitPlugin(PluginInfo & info)
|
|||
{
|
||||
export_thread.SetBaseUrl(info.config->base_url);
|
||||
|
||||
info.system->thread_manager.Add(&export_thread, L"export");
|
||||
info.res = info.system->thread_manager.Add(&export_thread, L"export");
|
||||
|
||||
export_info.ReadExportDirs();
|
||||
}
|
||||
|
|
|
@ -156,6 +156,7 @@ void ProcessRequest(PluginInfo & info)
|
|||
void InitPlugin(PluginInfo & info)
|
||||
{
|
||||
ConfigReload(info);
|
||||
info.res = true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -176,6 +176,12 @@ void Rescan(PluginInfo & info)
|
|||
}
|
||||
}
|
||||
|
||||
void PluginInit(PluginInfo & info)
|
||||
{
|
||||
Rescan(info);
|
||||
info.res = true;
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
|
@ -202,7 +208,7 @@ using namespace Thread;
|
|||
info.plugin->Assign(WINIX_PL_THREAD_PREPARE_THREAD, PrepareThread);
|
||||
|
||||
// temporarily
|
||||
info.plugin->Assign(WINIX_PLUGIN_INIT, Rescan);
|
||||
info.plugin->Assign(WINIX_PLUGIN_INIT, PluginInit);
|
||||
|
||||
tdb.SetConn(info.db->GetConn());
|
||||
tdb.LogQueries(info.config->log_db_query);
|
||||
|
|
|
@ -130,6 +130,7 @@ void RemoveTicket(PluginInfo & info)
|
|||
void InitTicket(PluginInfo & info)
|
||||
{
|
||||
ticket_info.progress_prefix = info.config->Text(L"ticket_form_progress_prefix", L"progress");
|
||||
info.res = true;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue