Skip to content

Commit f27fbd9

Browse files
committed
Python: using default event_loop for main thread for ASGI.
Unit's ASGI implementation creates a new event loop to run an application for each thread since 542b5b8c0647. This may cause unexpected exceptions or strange bugs if asyncio synchronisation primitives are initialised before the application starts (e.g. globally). Although the approach with a new event loop for the main thread is consistent and helps to prepare the application to run in multiple threads, it can be a source of pain for people who just want to run single-threaded ASGI applications in Unit. This is related to #560 issue on GitHub.
1 parent dfbdc1c commit f27fbd9

File tree

4 files changed

+22
-16
lines changed

4 files changed

+22
-16
lines changed

src/python/nxt_python.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ nxt_python_start(nxt_task_t *task, nxt_process_data_t *data)
264264
goto fail;
265265
}
266266

267-
rc = nxt_py_proto.ctx_data_alloc(&python_init.ctx_data);
267+
rc = nxt_py_proto.ctx_data_alloc(&python_init.ctx_data, 1);
268268
if (nxt_slow_path(rc != NXT_UNIT_OK)) {
269269
goto fail;
270270
}
@@ -504,7 +504,7 @@ nxt_python_init_threads(nxt_python_app_conf_t *c)
504504
for (i = 0; i < c->threads - 1; i++) {
505505
ti = &nxt_py_threads[i];
506506

507-
res = nxt_py_proto.ctx_data_alloc(&ti->ctx_data);
507+
res = nxt_py_proto.ctx_data_alloc(&ti->ctx_data, 0);
508508
if (nxt_slow_path(res != NXT_UNIT_OK)) {
509509
return NXT_UNIT_ERROR;
510510
}

src/python/nxt_python.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ typedef struct {
6060

6161

6262
typedef struct {
63-
int (*ctx_data_alloc)(void **pdata);
63+
int (*ctx_data_alloc)(void **pdata, int main);
6464
void (*ctx_data_free)(void *data);
6565
int (*startup)(void *data);
6666
int (*run)(nxt_unit_ctx_t *ctx);

src/python/nxt_python_asgi.c

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818

1919
static PyObject *nxt_python_asgi_get_func(PyObject *obj);
20-
static int nxt_python_asgi_ctx_data_alloc(void **pdata);
20+
static int nxt_python_asgi_ctx_data_alloc(void **pdata, int main);
2121
static void nxt_python_asgi_ctx_data_free(void *data);
2222
static int nxt_python_asgi_startup(void *data);
2323
static int nxt_python_asgi_run(nxt_unit_ctx_t *ctx);
@@ -194,10 +194,11 @@ nxt_python_asgi_init(nxt_unit_init_t *init, nxt_python_proto_t *proto)
194194

195195

196196
static int
197-
nxt_python_asgi_ctx_data_alloc(void **pdata)
197+
nxt_python_asgi_ctx_data_alloc(void **pdata, int main)
198198
{
199199
uint32_t i;
200-
PyObject *asyncio, *loop, *new_event_loop, *obj;
200+
PyObject *asyncio, *loop, *event_loop, *obj;
201+
const char *event_loop_func;
201202
nxt_py_asgi_ctx_data_t *ctx_data;
202203

203204
ctx_data = nxt_unit_malloc(NULL, sizeof(nxt_py_asgi_ctx_data_t));
@@ -232,23 +233,28 @@ nxt_python_asgi_ctx_data_alloc(void **pdata)
232233
goto fail;
233234
}
234235

235-
new_event_loop = PyDict_GetItemString(PyModule_GetDict(asyncio),
236-
"new_event_loop");
237-
if (nxt_slow_path(new_event_loop == NULL)) {
236+
event_loop_func = main ? "get_event_loop" : "new_event_loop";
237+
238+
event_loop = PyDict_GetItemString(PyModule_GetDict(asyncio),
239+
event_loop_func);
240+
if (nxt_slow_path(event_loop == NULL)) {
238241
nxt_unit_alert(NULL,
239-
"Python failed to get 'new_event_loop' from module 'asyncio'");
242+
"Python failed to get '%s' from module 'asyncio'",
243+
event_loop_func);
240244
goto fail;
241245
}
242246

243-
if (nxt_slow_path(PyCallable_Check(new_event_loop) == 0)) {
247+
if (nxt_slow_path(PyCallable_Check(event_loop) == 0)) {
244248
nxt_unit_alert(NULL,
245-
"'asyncio.new_event_loop' is not a callable object");
249+
"'asyncio.%s' is not a callable object",
250+
event_loop_func);
246251
goto fail;
247252
}
248253

249-
loop = PyObject_CallObject(new_event_loop, NULL);
254+
loop = PyObject_CallObject(event_loop, NULL);
250255
if (nxt_slow_path(loop == NULL)) {
251-
nxt_unit_alert(NULL, "Python failed to call 'asyncio.new_event_loop'");
256+
nxt_unit_alert(NULL, "Python failed to call 'asyncio.%s'",
257+
event_loop_func);
252258
goto fail;
253259
}
254260

src/python/nxt_python_wsgi.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ typedef struct {
5151
} nxt_python_ctx_t;
5252

5353

54-
static int nxt_python_wsgi_ctx_data_alloc(void **pdata);
54+
static int nxt_python_wsgi_ctx_data_alloc(void **pdata, int main);
5555
static void nxt_python_wsgi_ctx_data_free(void *data);
5656
static int nxt_python_wsgi_run(nxt_unit_ctx_t *ctx);
5757
static void nxt_python_wsgi_done(void);
@@ -210,7 +210,7 @@ nxt_python_wsgi_init(nxt_unit_init_t *init, nxt_python_proto_t *proto)
210210

211211

212212
static int
213-
nxt_python_wsgi_ctx_data_alloc(void **pdata)
213+
nxt_python_wsgi_ctx_data_alloc(void **pdata, int main)
214214
{
215215
nxt_python_ctx_t *pctx;
216216

0 commit comments

Comments
 (0)