mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-09-06 13:41:28 +00:00
improvements in multiple interpreter management
This commit is contained in:
+7
-14
@@ -6,20 +6,18 @@ import rrdtool
|
||||
|
||||
s_freq = 10
|
||||
|
||||
# this is a cron emulator done with the Spooler :)
|
||||
def rrdtool_updater(env):
|
||||
uwsgi.set_spooler_frequency(s_freq)
|
||||
rrdtool.update('../test.rrd', str(int(time.time()))+':'+str(uwsgi.total_requests()))
|
||||
uwsgi.send_to_spooler({})
|
||||
# this task will be executed every s_freq seconds
|
||||
def rrdtool_updater(sig, sec):
|
||||
rrdtool.update('test.rrd', str(int(time.time()))+':'+str(uwsgi.total_requests()))
|
||||
|
||||
|
||||
uwsgi.spooler = rrdtool_updater
|
||||
uwsgi.register_timer(0, s_freq, uwsgi.KIND_WORKER, rrdtool_updater)
|
||||
|
||||
|
||||
|
||||
def hello_world(env, start_response):
|
||||
start_response('200 Ok', [('Content-type', 'text/plain')])
|
||||
yield 'Hello world !'
|
||||
return 'Hello world !'
|
||||
|
||||
|
||||
def graph(env, start_response):
|
||||
@@ -27,12 +25,7 @@ def graph(env, start_response):
|
||||
now = int(time.time())
|
||||
graph_range = (3600*24)
|
||||
rrdtool.graph('uwsgi_graph.png', '--start', str(now - graph_range), '--end', str(now), 'DEF:urequests=test.rrd:requests:AVERAGE', 'LINE2:urequests#00FF00')
|
||||
fd = open('uwsgi_graph.png', 'r')
|
||||
# send file to browser
|
||||
return env['wsgi.file_wrapper'](fd, 4096)
|
||||
|
||||
# start the simil-cron
|
||||
uwsgi.send_to_spooler({})
|
||||
|
||||
# send file to client
|
||||
uwsgi.sendfile('uwsgi_graph.png')
|
||||
|
||||
uwsgi.applications = {'/': hello_world, '/graph':graph}
|
||||
|
||||
+63
-12
@@ -18,11 +18,13 @@ PyMethodDef uwsgi_eventfd_read_method[] = { {"uwsgi_eventfd_read", py_eventfd_re
|
||||
PyMethodDef uwsgi_eventfd_write_method[] = { {"uwsgi_eventfd_write", py_eventfd_write, METH_VARARGS, ""}};
|
||||
#endif
|
||||
|
||||
int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, int new_interpreter) {
|
||||
int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThreadState *interpreter) {
|
||||
|
||||
PyObject *zero;
|
||||
PyObject *app_list = NULL, *applications = NULL;
|
||||
|
||||
int id = uwsgi.apps_cnt;
|
||||
int multiapp = 0;
|
||||
|
||||
#ifdef UWSGI_ASYNC
|
||||
int i;
|
||||
@@ -35,11 +37,11 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, int ne
|
||||
|
||||
if (wsgi_req->script_name_len == 0) {
|
||||
wsgi_req->script_name = "";
|
||||
if (!uwsgi.vhost) id = 0;
|
||||
}
|
||||
else if (wsgi_req->script_name_len == 1) {
|
||||
if (wsgi_req->script_name[0] == '/') {
|
||||
if (!uwsgi.vhost) id = 0;
|
||||
wsgi_req->script_name = "";
|
||||
wsgi_req->script_name_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +79,7 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, int ne
|
||||
|
||||
// Initialize a new environment for the new interpreter
|
||||
|
||||
if (new_interpreter && id) {
|
||||
if (interpreter == NULL && id) {
|
||||
wi->interpreter = Py_NewInterpreter();
|
||||
if (!wi->interpreter) {
|
||||
uwsgi_log( "unable to initialize the new python interpreter\n");
|
||||
@@ -93,6 +95,9 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, int ne
|
||||
init_uwsgi_vars();
|
||||
|
||||
}
|
||||
else if (interpreter) {
|
||||
wi->interpreter = interpreter;
|
||||
}
|
||||
else {
|
||||
wi->interpreter = up.main_thread;
|
||||
}
|
||||
@@ -105,6 +110,32 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, int ne
|
||||
goto doh;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// the module contains multiple apps
|
||||
if (PyDict_Check(wi->callable)) {
|
||||
applications = wi->callable;
|
||||
uwsgi_log("found a multiapp module...\n");
|
||||
app_list = PyDict_Keys(applications);
|
||||
multiapp = PyList_Size(app_list);
|
||||
if (multiapp < 1) {
|
||||
uwsgi_log("you have to define at least one app in the apllications dictionary\n");
|
||||
goto doh;
|
||||
}
|
||||
|
||||
PyObject *app_mnt = PyList_GetItem(app_list, 0);
|
||||
if (!PyString_Check(app_mnt)) {
|
||||
uwsgi_log("the app mountpoint must be a string\n");
|
||||
goto doh;
|
||||
}
|
||||
wi->mountpoint = PyString_AsString(app_mnt);
|
||||
wi->mountpoint_len = strlen(wi->mountpoint);
|
||||
wsgi_req->script_name = wi->mountpoint;
|
||||
wsgi_req->script_name_len = wi->mountpoint_len;
|
||||
uwsgi_log("main mountpoint = %s\n", wi->mountpoint);
|
||||
wi->callable = PyDict_GetItem(applications, app_mnt);
|
||||
}
|
||||
|
||||
#ifdef UWSGI_ASYNC
|
||||
wi->environ = malloc(sizeof(PyObject*)*uwsgi.cores);
|
||||
if (!wi->environ) {
|
||||
@@ -216,7 +247,7 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, int ne
|
||||
#endif
|
||||
}
|
||||
|
||||
if (new_interpreter && id) {
|
||||
if (interpreter == NULL && id) {
|
||||
// if we have multiple threads we need to initialize a PyThreadState for each one
|
||||
if (uwsgi.threads > 1) {
|
||||
for(i=0;i<uwsgi.threads;i++) {
|
||||
@@ -240,23 +271,35 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, int ne
|
||||
uwsgi_log( "WSGI application %d (SCRIPT_NAME=%.*s) ready on interpreter %p", id, wi->mountpoint_len, wi->mountpoint, wi->interpreter);
|
||||
}
|
||||
|
||||
if (id == 0) {
|
||||
if (!wsgi_req->script_name_len) {
|
||||
uwsgi_log(" (default app)");
|
||||
uwsgi.default_app = 0;
|
||||
if (uwsgi.vhost) uwsgi.apps_cnt++;
|
||||
}
|
||||
else {
|
||||
uwsgi.apps_cnt++;
|
||||
uwsgi.default_app = id;
|
||||
}
|
||||
|
||||
uwsgi.apps_cnt++;
|
||||
|
||||
uwsgi_log("\n");
|
||||
|
||||
if (multiapp > 1) {
|
||||
for(i=1;i<multiapp;i++) {
|
||||
PyObject *app_mnt = PyList_GetItem(app_list, i);
|
||||
if (!PyString_Check(app_mnt)) {
|
||||
uwsgi_log("applications dictionary key must be a string, skipping.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
wsgi_req->script_name = PyString_AsString(app_mnt);
|
||||
wsgi_req->script_name_len = strlen(wsgi_req->script_name);
|
||||
init_uwsgi_app(LOADER_CALLABLE, PyDict_GetItem(applications, app_mnt), wsgi_req, wi->interpreter);
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
|
||||
doh:
|
||||
free(mountpoint);
|
||||
PyErr_Print();
|
||||
if (new_interpreter && id) {
|
||||
if (interpreter == NULL && id) {
|
||||
Py_EndInterpreter(wi->interpreter);
|
||||
if (uwsgi.threads > 1) {
|
||||
PyThreadState_Swap((PyThreadState *) pthread_getspecific(up.upt_save_key));
|
||||
@@ -308,6 +351,8 @@ PyObject *uwsgi_uwsgi_loader(void *arg1) {
|
||||
char *quick_callable;
|
||||
|
||||
PyObject *tmp_callable;
|
||||
PyObject *applications;
|
||||
PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi");
|
||||
|
||||
char *module = (char *) arg1;
|
||||
|
||||
@@ -330,6 +375,12 @@ PyObject *uwsgi_uwsgi_loader(void *arg1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
applications = PyDict_GetItemString(uwsgi_dict, "applications");
|
||||
if (applications) return applications;
|
||||
|
||||
applications = PyDict_GetItemString(wsgi_dict, "applications");
|
||||
if (applications) return applications;
|
||||
|
||||
// quick callable -> thanks gunicorn for the idea
|
||||
// we have extended the concept a bit...
|
||||
if (quick_callable[strlen(quick_callable) -2 ] == '(' && quick_callable[strlen(quick_callable) -1] ==')') {
|
||||
|
||||
+21
-130
@@ -91,6 +91,7 @@ int uwsgi_python_init() {
|
||||
|
||||
up.main_thread = PyThreadState_Get();
|
||||
|
||||
uwsgi_log("Python main interpreter initialized at %p\n", up.main_thread);
|
||||
|
||||
#ifdef UWSGI_MINTERPRETERS
|
||||
init_uwsgi_embedded_module();
|
||||
@@ -337,125 +338,6 @@ void init_uwsgi_vars() {
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_uwsgi_config(char *module) {
|
||||
|
||||
#ifdef UWSGI_EMBEDDED
|
||||
PyObject *uwsgi_module, *uwsgi_dict;
|
||||
#endif
|
||||
PyObject *applications;
|
||||
PyObject *app_list;
|
||||
Py_ssize_t i;
|
||||
PyObject *app_mnt, *app_app = NULL;
|
||||
char *quick_callable;
|
||||
|
||||
quick_callable = get_uwsgi_pymodule(module);
|
||||
if (quick_callable == NULL) {
|
||||
if (up.callable) {
|
||||
quick_callable = up.callable;
|
||||
}
|
||||
else {
|
||||
quick_callable = "application";
|
||||
}
|
||||
}
|
||||
|
||||
up.loader_dict = get_uwsgi_pydict(module);
|
||||
if (!up.loader_dict) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_log( "...getting the applications list from the '%s' module...\n", module);
|
||||
|
||||
#ifdef UWSGI_EMBEDDED
|
||||
uwsgi_module = PyImport_ImportModule("uwsgi");
|
||||
if (!uwsgi_module) {
|
||||
PyErr_Print();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_dict = PyModule_GetDict(uwsgi_module);
|
||||
if (!uwsgi_dict) {
|
||||
PyErr_Print();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
applications = PyDict_GetItemString(uwsgi_dict, "applications");
|
||||
if (!PyDict_Check(applications)) {
|
||||
uwsgi_log( "uwsgi.applications dictionary is not defined, trying with the \"applications\" one...\n");
|
||||
#endif
|
||||
applications = PyDict_GetItemString(up.loader_dict, "applications");
|
||||
if (!applications) {
|
||||
uwsgi_log( "applications dictionary is not defined, trying with the \"application\" callable.\n");
|
||||
quick_callable = uwsgi_concat3(module, ":", quick_callable);
|
||||
if (init_uwsgi_app(LOADER_UWSGI, (void *) quick_callable, uwsgi.wsgi_req, 0) < 0) {
|
||||
uwsgi_log( "...goodbye cruel world...\n");
|
||||
exit(1);
|
||||
}
|
||||
free(quick_callable);
|
||||
return;
|
||||
}
|
||||
#ifdef UWSGI_EMBEDDED
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!PyDict_Check(applications)) {
|
||||
uwsgi_log( "The 'applications' object must be a dictionary.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
app_list = PyDict_Keys(applications);
|
||||
if (!app_list) {
|
||||
PyErr_Print();
|
||||
exit(1);
|
||||
}
|
||||
if (PyList_Size(app_list) < 1) {
|
||||
uwsgi_log( "You must define an app.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i = 0; i < PyList_Size(app_list); i++) {
|
||||
app_mnt = PyList_GetItem(app_list, i);
|
||||
|
||||
if (!PyString_Check(app_mnt)) {
|
||||
uwsgi_log( "the app mountpoint must be a bytestring.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
uwsgi.wsgi_req->script_name = PyString_AsString(app_mnt);
|
||||
uwsgi.wsgi_req->script_name_len = strlen(uwsgi.wsgi_req->script_name);
|
||||
|
||||
app_app = PyDict_GetItem(applications, app_mnt);
|
||||
|
||||
if (!PyString_Check(app_app) && !PyFunction_Check(app_app) && !PyCallable_Check(app_app)) {
|
||||
uwsgi_log( "the app callable must be a string, a function or a callable. (found %s)\n", app_app->ob_type->tp_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef PYTHREE
|
||||
if (PyUnicode_Check(app_app)) {
|
||||
#else
|
||||
if (PyString_Check(app_app)) {
|
||||
#endif
|
||||
if (init_uwsgi_app(LOADER_STRING_CALLABLE, (void *) PyString_AsString(app_app), uwsgi.wsgi_req, 0) < 0) {
|
||||
uwsgi_log( "...goodbye cruel world...\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else {
|
||||
if (init_uwsgi_app(LOADER_CALLABLE, (void *) app_app, uwsgi.wsgi_req, 0) < 0) {
|
||||
uwsgi_log( "...goodbye cruel world...\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
Py_DECREF(app_mnt);
|
||||
Py_DECREF(app_app);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifdef PYTHREE
|
||||
static PyModuleDef uwsgi_module3 = {
|
||||
@@ -755,26 +637,29 @@ int uwsgi_python_mount_app(char *mountpoint, char *app) {
|
||||
|
||||
uwsgi.wsgi_req->script_name = mountpoint;
|
||||
uwsgi.wsgi_req->script_name_len = strlen(mountpoint);
|
||||
return init_uwsgi_app(LOADER_MOUNT, app, uwsgi.wsgi_req, uwsgi.single_interpreter-1);
|
||||
if (uwsgi.single_interpreter) {
|
||||
return init_uwsgi_app(LOADER_MOUNT, app, uwsgi.wsgi_req, up.main_thread);
|
||||
}
|
||||
return init_uwsgi_app(LOADER_MOUNT, app, uwsgi.wsgi_req, NULL);
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_python_init_apps() {
|
||||
|
||||
if (up.wsgi_config != NULL) {
|
||||
init_uwsgi_app(LOADER_UWSGI, up.wsgi_config, uwsgi.wsgi_req, 0);
|
||||
init_uwsgi_app(LOADER_UWSGI, up.wsgi_config, uwsgi.wsgi_req, up.main_thread);
|
||||
}
|
||||
|
||||
if (up.file_config != NULL) {
|
||||
init_uwsgi_app(LOADER_FILE, up.file_config, uwsgi.wsgi_req, 0);
|
||||
init_uwsgi_app(LOADER_FILE, up.file_config, uwsgi.wsgi_req, up.main_thread);
|
||||
}
|
||||
#ifdef UWSGI_PASTE
|
||||
if (up.paste != NULL) {
|
||||
init_uwsgi_app(LOADER_PASTE, up.paste, uwsgi.wsgi_req, 0);
|
||||
init_uwsgi_app(LOADER_PASTE, up.paste, uwsgi.wsgi_req, up.main_thread);
|
||||
}
|
||||
#endif
|
||||
if (up.eval != NULL) {
|
||||
init_uwsgi_app(LOADER_EVAL, up.eval, uwsgi.wsgi_req, 0);
|
||||
init_uwsgi_app(LOADER_EVAL, up.eval, uwsgi.wsgi_req, up.main_thread);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -806,17 +691,23 @@ int uwsgi_python_mount_app(char *mountpoint, char *app) {
|
||||
|
||||
int uwsgi_python_xml(char *node, char *content) {
|
||||
|
||||
PyThreadState *interpreter = NULL;
|
||||
|
||||
if (uwsgi.single_interpreter) {
|
||||
interpreter = up.main_thread;
|
||||
}
|
||||
|
||||
if (!strcmp("script", node)) {
|
||||
return init_uwsgi_app(LOADER_UWSGI, content, uwsgi.wsgi_req, uwsgi.single_interpreter-1);
|
||||
return init_uwsgi_app(LOADER_UWSGI, content, uwsgi.wsgi_req, interpreter);
|
||||
}
|
||||
else if (!strcmp("file", node)) {
|
||||
return init_uwsgi_app(LOADER_FILE, content, uwsgi.wsgi_req, uwsgi.single_interpreter-1);
|
||||
return init_uwsgi_app(LOADER_FILE, content, uwsgi.wsgi_req, interpreter);
|
||||
}
|
||||
else if (!strcmp("eval", node)) {
|
||||
return init_uwsgi_app(LOADER_EVAL, content, uwsgi.wsgi_req, uwsgi.single_interpreter-1);
|
||||
return init_uwsgi_app(LOADER_EVAL, content, uwsgi.wsgi_req, interpreter);
|
||||
}
|
||||
else if (!strcmp("wsgi", node)) {
|
||||
return init_uwsgi_app(LOADER_EVAL, content, uwsgi.wsgi_req, uwsgi.single_interpreter-1);
|
||||
return init_uwsgi_app(LOADER_EVAL, content, uwsgi.wsgi_req, interpreter);
|
||||
}
|
||||
else if (!strcmp("module", node)) {
|
||||
uwsgi.wsgi_req->module = content;
|
||||
@@ -827,7 +718,7 @@ int uwsgi_python_xml(char *node, char *content) {
|
||||
uwsgi.wsgi_req->callable++;
|
||||
uwsgi.wsgi_req->callable_len = strlen(uwsgi.wsgi_req->callable);
|
||||
uwsgi.wsgi_req->module_len = strlen(uwsgi.wsgi_req->module);
|
||||
return init_uwsgi_app(LOADER_DYN, uwsgi.wsgi_req, uwsgi.wsgi_req, uwsgi.single_interpreter-1);
|
||||
return init_uwsgi_app(LOADER_DYN, uwsgi.wsgi_req, uwsgi.wsgi_req, interpreter);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -839,7 +730,7 @@ int uwsgi_python_xml(char *node, char *content) {
|
||||
else if (!strcmp("callable", node)) {
|
||||
uwsgi.wsgi_req->callable = content;
|
||||
uwsgi.wsgi_req->callable_len = strlen(content);
|
||||
return init_uwsgi_app(LOADER_DYN, uwsgi.wsgi_req, uwsgi.wsgi_req, uwsgi.single_interpreter-1);
|
||||
return init_uwsgi_app(LOADER_DYN, uwsgi.wsgi_req, uwsgi.wsgi_req, interpreter);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -137,7 +137,7 @@ void uwsgi_paste_config(char *);
|
||||
void uwsgi_file_config(char *);
|
||||
void uwsgi_eval_config(char *);
|
||||
|
||||
int init_uwsgi_app(int, void *, struct wsgi_request *wsgi_req, int);
|
||||
int init_uwsgi_app(int, void *, struct wsgi_request *wsgi_req, PyThreadState *);
|
||||
|
||||
|
||||
PyObject *py_eventfd_read(PyObject *, PyObject *);
|
||||
|
||||
@@ -153,7 +153,12 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
|
||||
pthread_mutex_lock(&up.lock_pyloaders);
|
||||
}
|
||||
UWSGI_GET_GIL
|
||||
wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, uwsgi.single_interpreter-1);
|
||||
if (uwsgi.single_interpreter) {
|
||||
wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, up.main_thread);
|
||||
}
|
||||
else {
|
||||
wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, NULL);
|
||||
}
|
||||
UWSGI_RELEASE_GIL
|
||||
if (uwsgi.threads > 1) {
|
||||
pthread_mutex_unlock(&up.lock_pyloaders);
|
||||
@@ -186,7 +191,7 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
|
||||
|
||||
wi = &uwsgi.apps[wsgi_req->app_id];
|
||||
|
||||
if (uwsgi.single_interpreter == 0 && wsgi_req->app_id > 0) {
|
||||
if (uwsgi.single_interpreter == 0 && wi->interpreter != up.main_thread) {
|
||||
if (!wi->interpreter) {
|
||||
internal_server_error(wsgi_req->poll.fd, "wsgi application's %d interpreter not found");
|
||||
goto clear2;
|
||||
@@ -339,7 +344,7 @@ clear:
|
||||
|
||||
UWSGI_GET_GIL
|
||||
|
||||
if (uwsgi.single_interpreter == 0 && wsgi_req->app_id > 0) {
|
||||
if (uwsgi.single_interpreter == 0 && wi->interpreter != up.main_thread) {
|
||||
// restoring main interpreter
|
||||
if (uwsgi.threads > 1) {
|
||||
PyThreadState_Swap((PyThreadState *) pthread_getspecific(up.upt_save_key));
|
||||
|
||||
+1
-1
@@ -525,7 +525,7 @@ int uwsgi_parse_vars(struct wsgi_request *wsgi_req) {
|
||||
wsgi_req->var_cnt++;
|
||||
script_name = wsgi_req->var_cnt;
|
||||
}
|
||||
for(i=1;i<uwsgi.apps_cnt;i++) {
|
||||
for(i=0;i<uwsgi.apps_cnt;i++) {
|
||||
uwsgi_log("app mountpoint = %.*s\n", uwsgi.apps[i].mountpoint_len, uwsgi.apps[i].mountpoint);
|
||||
if (orig_path_info_len >= uwsgi.apps[i].mountpoint_len) {
|
||||
if (!uwsgi_startswith(orig_path_info, uwsgi.apps[i].mountpoint, uwsgi.apps[i].mountpoint_len) && uwsgi.apps[i].mountpoint_len > best_found) {
|
||||
|
||||
@@ -907,6 +907,7 @@ int uwsgi_get_app_id(char *script_name, int script_name_len, int modifier1) {
|
||||
int i;
|
||||
|
||||
for(i=0;i<uwsgi.apps_cnt;i++) {
|
||||
uwsgi_log("searching for %.*s in %.*s %p\n", script_name_len, script_name, uwsgi.apps[i].mountpoint_len, uwsgi.apps[i].mountpoint, uwsgi.apps[i].callable);
|
||||
if (!uwsgi.apps[i].mountpoint_len) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user