mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
Fix #1635, support auto reaload config by inotify. 3.0.129
This commit is contained in:
parent
4b395f6e16
commit
9b663c070a
10 changed files with 193 additions and 14 deletions
|
@ -146,6 +146,7 @@ For previous versions, please read:
|
||||||
|
|
||||||
## V3 changes
|
## V3 changes
|
||||||
|
|
||||||
|
* v3.0, 2020-03-12, For [#1635][bug #1635], support auto reaload config by inotify. 3.0.129
|
||||||
* v3.0, 2020-03-12, For [#1630][bug #1630], disable cache for stream changing, and drop dup header. 3.0.128
|
* v3.0, 2020-03-12, For [#1630][bug #1630], disable cache for stream changing, and drop dup header. 3.0.128
|
||||||
* v3.0, 2020-03-12, For [#1594][bug #1594], detect and disable daemon for docker. 3.0.127
|
* v3.0, 2020-03-12, For [#1594][bug #1594], detect and disable daemon for docker. 3.0.127
|
||||||
* v3.0, 2020-03-12, For [#1634][bug #1634], always check status in thread loop. 3.0.126
|
* v3.0, 2020-03-12, For [#1634][bug #1634], always check status in thread loop. 3.0.126
|
||||||
|
@ -1668,6 +1669,7 @@ Winlin
|
||||||
[bug #1634]: https://github.com/ossrs/srs/issues/1634
|
[bug #1634]: https://github.com/ossrs/srs/issues/1634
|
||||||
[bug #1594]: https://github.com/ossrs/srs/issues/1594
|
[bug #1594]: https://github.com/ossrs/srs/issues/1594
|
||||||
[bug #1630]: https://github.com/ossrs/srs/issues/1630
|
[bug #1630]: https://github.com/ossrs/srs/issues/1630
|
||||||
|
[bug #1635]: https://github.com/ossrs/srs/issues/1635
|
||||||
[bug #yyyyyyyyyyyyy]: https://github.com/ossrs/srs/issues/yyyyyyyyyyyyy
|
[bug #yyyyyyyyyyyyy]: https://github.com/ossrs/srs/issues/yyyyyyyyyyyyy
|
||||||
|
|
||||||
[exo #828]: https://github.com/google/ExoPlayer/pull/828
|
[exo #828]: https://github.com/google/ExoPlayer/pull/828
|
||||||
|
|
|
@ -97,6 +97,13 @@ force_grace_quit off;
|
||||||
# If on, it will set daemon to off in docker, even daemon is on.
|
# If on, it will set daemon to off in docker, even daemon is on.
|
||||||
# default: on
|
# default: on
|
||||||
disable_daemon_for_docker on;
|
disable_daemon_for_docker on;
|
||||||
|
# Whether auto reload by watching the config file by inotify.
|
||||||
|
# default: off
|
||||||
|
inotify_auto_reload off;
|
||||||
|
# Whether enable inotify_auto_reload for docker.
|
||||||
|
# If on, it will set inotify_auto_reload to on in docker, even it's off.
|
||||||
|
# default: on
|
||||||
|
auto_reload_for_docker on;
|
||||||
|
|
||||||
#############################################################################################
|
#############################################################################################
|
||||||
# heartbeat/stats sections
|
# heartbeat/stats sections
|
||||||
|
|
|
@ -3489,6 +3489,7 @@ srs_error_t SrsConfig::check_normal_config()
|
||||||
&& n != "utc_time" && n != "work_dir" && n != "asprocess"
|
&& n != "utc_time" && n != "work_dir" && n != "asprocess"
|
||||||
&& n != "ff_log_level" && n != "grace_final_wait" && n != "force_grace_quit"
|
&& n != "ff_log_level" && n != "grace_final_wait" && n != "force_grace_quit"
|
||||||
&& n != "grace_start_wait" && n != "empty_ip_ok" && n != "disable_daemon_for_docker"
|
&& n != "grace_start_wait" && n != "empty_ip_ok" && n != "disable_daemon_for_docker"
|
||||||
|
&& n != "inotify_auto_reload" && n != "auto_reload_for_docker"
|
||||||
) {
|
) {
|
||||||
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal directive %s", n.c_str());
|
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal directive %s", n.c_str());
|
||||||
}
|
}
|
||||||
|
@ -4111,6 +4112,30 @@ bool SrsConfig::disable_daemon_for_docker()
|
||||||
return SRS_CONF_PERFER_TRUE(conf->arg0());
|
return SRS_CONF_PERFER_TRUE(conf->arg0());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SrsConfig::inotify_auto_reload()
|
||||||
|
{
|
||||||
|
static bool DEFAULT = false;
|
||||||
|
|
||||||
|
SrsConfDirective* conf = root->get("inotify_auto_reload");
|
||||||
|
if (!conf || conf->arg0().empty()) {
|
||||||
|
return DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SRS_CONF_PERFER_FALSE(conf->arg0());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SrsConfig::auto_reload_for_docker()
|
||||||
|
{
|
||||||
|
static bool DEFAULT = true;
|
||||||
|
|
||||||
|
SrsConfDirective* conf = root->get("auto_reload_for_docker");
|
||||||
|
if (!conf || conf->arg0().empty()) {
|
||||||
|
return DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SRS_CONF_PERFER_TRUE(conf->arg0());
|
||||||
|
}
|
||||||
|
|
||||||
vector<SrsConfDirective*> SrsConfig::get_stream_casters()
|
vector<SrsConfDirective*> SrsConfig::get_stream_casters()
|
||||||
{
|
{
|
||||||
srs_assert(root);
|
srs_assert(root);
|
||||||
|
|
|
@ -478,6 +478,10 @@ public:
|
||||||
virtual bool is_force_grace_quit();
|
virtual bool is_force_grace_quit();
|
||||||
// Whether disable daemon for docker.
|
// Whether disable daemon for docker.
|
||||||
virtual bool disable_daemon_for_docker();
|
virtual bool disable_daemon_for_docker();
|
||||||
|
// Whether use inotify to auto reload by watching config file changes.
|
||||||
|
virtual bool inotify_auto_reload();
|
||||||
|
// Whether enable auto reload config for docker.
|
||||||
|
virtual bool auto_reload_for_docker();
|
||||||
// stream_caster section
|
// stream_caster section
|
||||||
public:
|
public:
|
||||||
// Get all stream_caster in config file.
|
// Get all stream_caster in config file.
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <sys/inotify.h>
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#include <srs_kernel_log.hpp>
|
#include <srs_kernel_log.hpp>
|
||||||
|
@ -457,6 +458,114 @@ void SrsSignalManager::sig_catcher(int signo)
|
||||||
errno = err;
|
errno = err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Whether we are in docker, defined in main module.
|
||||||
|
extern bool _srs_in_docker;
|
||||||
|
|
||||||
|
SrsInotifyWorker::SrsInotifyWorker(SrsServer* s)
|
||||||
|
{
|
||||||
|
server = s;
|
||||||
|
trd = new SrsSTCoroutine("inotify", this);
|
||||||
|
inotify_fd = NULL;
|
||||||
|
watch_fd = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsInotifyWorker::~SrsInotifyWorker()
|
||||||
|
{
|
||||||
|
srs_freep(trd);
|
||||||
|
srs_close_stfd(inotify_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsInotifyWorker::start()
|
||||||
|
{
|
||||||
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
// Whether enable auto reload config.
|
||||||
|
bool auto_reload = _srs_config->inotify_auto_reload();
|
||||||
|
if (!auto_reload && _srs_in_docker && _srs_config->auto_reload_for_docker()) {
|
||||||
|
srs_warn("enable auto reload for docker");
|
||||||
|
auto_reload = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!auto_reload) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create inotify to watch config file.
|
||||||
|
int fd = ::inotify_init1(IN_NONBLOCK);
|
||||||
|
if (fd < 0) {
|
||||||
|
return srs_error_new(ERROR_INOTIFY_CREATE, "create inotify");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch the config file events.
|
||||||
|
string config_file = _srs_config->config();
|
||||||
|
watch_fd = ::inotify_add_watch(fd, config_file.c_str(), IN_ALL_EVENTS);
|
||||||
|
if (watch_fd < 0) {
|
||||||
|
::close(fd);
|
||||||
|
return srs_error_new(ERROR_INOTIFY_WATCH, "watch %s", config_file.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open as stfd to read by ST.
|
||||||
|
if ((inotify_fd = srs_netfd_open(fd)) == NULL) {
|
||||||
|
::close(fd);
|
||||||
|
return srs_error_new(ERROR_INOTIFY_OPENFD, "open fd=%d, file=%s, wd=%d", fd, config_file.c_str(), watch_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((err = srs_fd_closeexec(fd))) != srs_success) {
|
||||||
|
return srs_error_new(ERROR_INOTIFY_OPENFD, "closeexec fd=%d, file=%s, wd=%d", fd, config_file.c_str(), watch_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_trace("auto reload watching %s, fd=%d, wd=%d", config_file.c_str(), fd, watch_fd);
|
||||||
|
|
||||||
|
if ((err = trd->start()) != srs_success) {
|
||||||
|
return srs_error_wrap(err, "inotify");
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsInotifyWorker::cycle()
|
||||||
|
{
|
||||||
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
char buf[4096];
|
||||||
|
ssize_t nn = srs_read(inotify_fd, buf, (size_t)sizeof(buf), SRS_UTIME_NO_TIMEOUT);
|
||||||
|
if (nn < 0) {
|
||||||
|
srs_warn("inotify ignore read failed, nn=%d", (int)nn);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Whether config file changed.
|
||||||
|
bool do_reload = false;
|
||||||
|
|
||||||
|
// Parse all inotify events.
|
||||||
|
for (int i = 0; i < (int)nn && !do_reload; i += (int)sizeof(inotify_event)) {
|
||||||
|
inotify_event* ie = (inotify_event*)(buf + i);
|
||||||
|
if (ie->wd != watch_fd) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only care about the modify or create event.
|
||||||
|
// @see https://github.com/ossrs/srs/issues/1635#issuecomment-598077374
|
||||||
|
if ((ie->mask&IN_MODIFY) != IN_MODIFY && (ie->mask&IN_CREATE) != IN_CREATE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
do_reload = true;
|
||||||
|
srs_trace("inotify event wd=%d, mask=%#x, len=%d, name=%s", ie->wd, ie->mask, ie->len, ie->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify server to do reload.
|
||||||
|
if (do_reload) {
|
||||||
|
server->on_signal(SRS_SIGNAL_RELOAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_usleep(100 * SRS_UTIME_MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
ISrsServerCycle::ISrsServerCycle()
|
ISrsServerCycle::ISrsServerCycle()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -849,7 +958,16 @@ srs_error_t SrsServer::ingest()
|
||||||
|
|
||||||
srs_error_t SrsServer::cycle()
|
srs_error_t SrsServer::cycle()
|
||||||
{
|
{
|
||||||
srs_error_t err = do_cycle();
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
// Start the inotify auto reload by watching config file.
|
||||||
|
SrsInotifyWorker inotify(this);
|
||||||
|
if ((err = inotify.start()) != srs_success) {
|
||||||
|
return srs_error_wrap(err, "start inotify");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do server main cycle.
|
||||||
|
err = do_cycle();
|
||||||
|
|
||||||
#ifdef SRS_AUTO_GPERF_MC
|
#ifdef SRS_AUTO_GPERF_MC
|
||||||
destroy();
|
destroy();
|
||||||
|
|
|
@ -184,6 +184,25 @@ private:
|
||||||
static void sig_catcher(int signo);
|
static void sig_catcher(int signo);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Auto reload by inotify.
|
||||||
|
// @see https://github.com/ossrs/srs/issues/1635
|
||||||
|
class SrsInotifyWorker : public ISrsCoroutineHandler
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
SrsServer* server;
|
||||||
|
SrsCoroutine* trd;
|
||||||
|
srs_netfd_t inotify_fd;
|
||||||
|
int watch_fd;
|
||||||
|
public:
|
||||||
|
SrsInotifyWorker(SrsServer* s);
|
||||||
|
virtual ~SrsInotifyWorker();
|
||||||
|
public:
|
||||||
|
virtual srs_error_t start();
|
||||||
|
// Interface ISrsEndlessThreadHandler.
|
||||||
|
public:
|
||||||
|
virtual srs_error_t cycle();
|
||||||
|
};
|
||||||
|
|
||||||
// A handler to the handle cycle in SRS RTMP server.
|
// A handler to the handle cycle in SRS RTMP server.
|
||||||
class ISrsServerCycle
|
class ISrsServerCycle
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,6 +24,6 @@
|
||||||
#ifndef SRS_CORE_VERSION3_HPP
|
#ifndef SRS_CORE_VERSION3_HPP
|
||||||
#define SRS_CORE_VERSION3_HPP
|
#define SRS_CORE_VERSION3_HPP
|
||||||
|
|
||||||
#define SRS_VERSION3_REVISION 128
|
#define SRS_VERSION3_REVISION 129
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -284,6 +284,9 @@
|
||||||
#define ERROR_MP4_ILLEGAL_MOOF 3089
|
#define ERROR_MP4_ILLEGAL_MOOF 3089
|
||||||
#define ERROR_OCLUSTER_DISCOVER 3090
|
#define ERROR_OCLUSTER_DISCOVER 3090
|
||||||
#define ERROR_OCLUSTER_REDIRECT 3091
|
#define ERROR_OCLUSTER_REDIRECT 3091
|
||||||
|
#define ERROR_INOTIFY_CREATE 3092
|
||||||
|
#define ERROR_INOTIFY_WATCH 3093
|
||||||
|
#define ERROR_INOTIFY_OPENFD 3094
|
||||||
|
|
||||||
///////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////
|
||||||
// HTTP/StreamCaster protocol error.
|
// HTTP/StreamCaster protocol error.
|
||||||
|
|
|
@ -352,11 +352,12 @@ string srs_getenv(const char* name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect docker by https://stackoverflow.com/a/41559867
|
// Detect docker by https://stackoverflow.com/a/41559867
|
||||||
srs_error_t srs_detect_docker(bool* is_docker)
|
bool _srs_in_docker = false;
|
||||||
|
srs_error_t srs_detect_docker()
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
*is_docker = false;
|
_srs_in_docker = false;
|
||||||
|
|
||||||
SrsFileReader fr;
|
SrsFileReader fr;
|
||||||
if ((err = fr.open("/proc/1/cgroup")) != srs_success) {
|
if ((err = fr.open("/proc/1/cgroup")) != srs_success) {
|
||||||
|
@ -375,7 +376,7 @@ srs_error_t srs_detect_docker(bool* is_docker)
|
||||||
|
|
||||||
string s(buf, nn);
|
string s(buf, nn);
|
||||||
if (srs_string_contains(s, "/docker")) {
|
if (srs_string_contains(s, "/docker")) {
|
||||||
*is_docker = true;
|
_srs_in_docker = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
@ -385,6 +386,11 @@ srs_error_t run(SrsServer* svr)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
// Ignore any error while detecting docker.
|
||||||
|
if ((err = srs_detect_docker()) != srs_success) {
|
||||||
|
srs_error_reset(err);
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the whole system, set hooks to handle server level events.
|
// Initialize the whole system, set hooks to handle server level events.
|
||||||
if ((err = svr->initialize(NULL)) != srs_success) {
|
if ((err = svr->initialize(NULL)) != srs_success) {
|
||||||
return srs_error_wrap(err, "server initialize");
|
return srs_error_wrap(err, "server initialize");
|
||||||
|
@ -393,15 +399,9 @@ srs_error_t run(SrsServer* svr)
|
||||||
// Load daemon from config, disable it for docker.
|
// Load daemon from config, disable it for docker.
|
||||||
// @see https://github.com/ossrs/srs/issues/1594
|
// @see https://github.com/ossrs/srs/issues/1594
|
||||||
bool in_daemon = _srs_config->get_daemon();
|
bool in_daemon = _srs_config->get_daemon();
|
||||||
if (in_daemon && _srs_config->disable_daemon_for_docker()) {
|
if (in_daemon && _srs_in_docker && _srs_config->disable_daemon_for_docker()) {
|
||||||
bool is_docker = false;
|
srs_warn("disable daemon for docker");
|
||||||
err = srs_detect_docker(&is_docker);
|
in_daemon = false;
|
||||||
srs_error_reset(err); // Ignore any error while detecting docker.
|
|
||||||
|
|
||||||
if (is_docker) {
|
|
||||||
srs_warn("disable daemon for docker");
|
|
||||||
in_daemon = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not daemon, directly run master.
|
// If not daemon, directly run master.
|
||||||
|
|
|
@ -45,6 +45,7 @@ ISrsThreadContext* _srs_context = new ISrsThreadContext();
|
||||||
// app module.
|
// app module.
|
||||||
SrsConfig* _srs_config = NULL;
|
SrsConfig* _srs_config = NULL;
|
||||||
SrsServer* _srs_server = NULL;
|
SrsServer* _srs_server = NULL;
|
||||||
|
bool _srs_in_docker = false;
|
||||||
|
|
||||||
#include <srs_app_st.hpp>
|
#include <srs_app_st.hpp>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue