{ "pm.process_idle_timeout", &fpm_conf_set_time, WPO(pm_process_idle_timeout) },
{ "pm.max_requests", &fpm_conf_set_integer, WPO(pm_max_requests) },
{ "pm.status_path", &fpm_conf_set_string, WPO(pm_status_path) },
+ { "pm.status_listen", &fpm_conf_set_string, WPO(pm_status_listen) },
{ "ping.path", &fpm_conf_set_string, WPO(ping_path) },
{ "ping.response", &fpm_conf_set_string, WPO(ping_response) },
{ "access.log", &fpm_conf_set_string, WPO(access_log) },
}
/* }}} */
+#define FPM_WPC_STR_CP_EX(_cfg, _scfg, _sf, _df) \
+ do { \
+ if (_scfg->_df && !(_cfg->_sf = strdup(_scfg->_df))) { \
+ return -1; \
+ } \
+ } while (0)
+#define FPM_WPC_STR_CP(_cfg, _scfg, _field) FPM_WPC_STR_CP_EX(_cfg, _scfg, _field, _field)
+
+static int fpm_worker_pool_shared_status_alloc(struct fpm_worker_pool_s *shared_wp) { /* {{{ */
+ struct fpm_worker_pool_config_s *config, *shared_config;
+ config = fpm_worker_pool_config_alloc();
+ if (!config) {
+ return -1;
+ }
+ shared_config = shared_wp->config;
+
+ config->name = malloc(strlen(shared_config->name) + sizeof("_status"));
+ if (!config->name) {
+ return -1;
+ }
+ strcpy(config->name, shared_config->name);
+ strcpy(config->name + strlen(shared_config->name), "_status");
+
+ if (!shared_config->pm_status_path) {
+ shared_config->pm_status_path = strdup("/");
+ }
+
+ FPM_WPC_STR_CP_EX(config, shared_config, listen_address, pm_status_listen);
+#ifdef HAVE_FPM_ACL
+ FPM_WPC_STR_CP(config, shared_config, listen_acl_groups);
+ FPM_WPC_STR_CP(config, shared_config, listen_acl_users);
+#endif
+ FPM_WPC_STR_CP(config, shared_config, listen_allowed_clients);
+ FPM_WPC_STR_CP(config, shared_config, listen_group);
+ FPM_WPC_STR_CP(config, shared_config, listen_owner);
+ FPM_WPC_STR_CP(config, shared_config, listen_mode);
+ FPM_WPC_STR_CP(config, shared_config, user);
+ FPM_WPC_STR_CP(config, shared_config, group);
+ FPM_WPC_STR_CP(config, shared_config, pm_status_path);
+
+ config->pm = PM_STYLE_ONDEMAND;
+ config->pm_max_children = 2;
+ /* set to 1 to not warn about max children for shared pool */
+ shared_wp->warn_max_children = 1;
+
+ current_wp->shared = shared_wp;
+
+ return 0;
+}
+/* }}} */
+
static int fpm_evaluate_full_path(char **path, struct fpm_worker_pool_s *wp, char *default_prefix, int expand) /* {{{ */
{
char *prefix = NULL;
}
/* status */
+ if (wp->config->pm_status_listen && fpm_worker_pool_shared_status_alloc(wp)) {
+ zlog(ZLOG_ERROR, "[pool %s] failed to initialize a status listener pool", wp->config->name);
+ }
+
if (wp->config->pm_status_path && *wp->config->pm_status_path) {
size_t i;
char *status = wp->config->pm_status_path;
return -1;
}
- if (strlen(status) < 2) {
+ if (!wp->config->pm_status_listen && !wp->shared && strlen(status) < 2) {
zlog(ZLOG_ERROR, "[pool %s] the status path '%s' is not long enough", wp->config->name, status);
return -1;
}
for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
struct key_value_s *kv;
- if (!wp->config) continue;
+
+ if (!wp->config || wp->shared) {
+ continue;
+ }
+
zlog(ZLOG_NOTICE, "[%s]", STR2STR(wp->config->name));
zlog(ZLOG_NOTICE, "\tprefix = %s", STR2STR(wp->config->prefix));
zlog(ZLOG_NOTICE, "\tuser = %s", STR2STR(wp->config->user));
zlog(ZLOG_NOTICE, "\tpm.process_idle_timeout = %d", wp->config->pm_process_idle_timeout);
zlog(ZLOG_NOTICE, "\tpm.max_requests = %d", wp->config->pm_max_requests);
zlog(ZLOG_NOTICE, "\tpm.status_path = %s", STR2STR(wp->config->pm_status_path));
+ zlog(ZLOG_NOTICE, "\tpm.status_listen = %s", STR2STR(wp->config->pm_status_listen));
zlog(ZLOG_NOTICE, "\tping.path = %s", STR2STR(wp->config->ping_path));
zlog(ZLOG_NOTICE, "\tping.response = %s", STR2STR(wp->config->ping_response));
zlog(ZLOG_NOTICE, "\taccess.log = %s", STR2STR(wp->config->access_log));
--- /dev/null
+--TEST--
+FPM: Status listen test
+--SKIPIF--
+<?php include "skipif.inc"; ?>
+--FILE--
+<?php
+
+require_once "tester.inc";
+
+$cfg = <<<EOT
+[global]
+error_log = {{FILE:LOG}}
+[unconfined]
+listen = {{ADDR}}
+pm = static
+pm.max_children = 1
+pm.status_listen = {{ADDR[status]}}
+pm.status_path = /status
+EOT;
+
+$expectedStatusData = [
+ 'pool' => 'unconfined',
+ 'process manager' => 'static',
+ 'listen queue' => 0,
+ 'max listen queue' => 0,
+ 'idle processes' => 1,
+ 'active processes' => 0,
+ 'total processes' => 1,
+ 'max active processes' => 1,
+ 'max children reached' => 0,
+ 'slow requests' => 0,
+];
+
+$tester = new FPM\Tester($cfg);
+$tester->start();
+$tester->expectLogStartNotices();
+$tester->request()->expectEmptyBody();
+$tester->status($expectedStatusData, '{{ADDR[status]}}');
+$tester->terminate();
+$tester->expectLogTerminatingNotices();
+$tester->close();
+
+?>
+Done
+--EXPECT--
+Done
+--CLEAN--
+<?php
+require_once "tester.inc";
+FPM\Tester::clean();
+?>