nxt_python_asgi_lifespan.c (1697:73a335d2911d) nxt_python_asgi_lifespan.c (1872:9f8df8b810e0)
1
2/*
3 * Copyright (C) NGINX, Inc.
4 */
5
6
7#include <python/nxt_python.h>
8

--- 13 unchanged lines hidden (view full) ---

22 int shutdown_received;
23 int shutdown_sent;
24 int shutdown_called;
25 PyObject *startup_future;
26 PyObject *shutdown_future;
27 PyObject *receive_future;
28} nxt_py_asgi_lifespan_t;
29
1
2/*
3 * Copyright (C) NGINX, Inc.
4 */
5
6
7#include <python/nxt_python.h>
8

--- 13 unchanged lines hidden (view full) ---

22 int shutdown_received;
23 int shutdown_sent;
24 int shutdown_called;
25 PyObject *startup_future;
26 PyObject *shutdown_future;
27 PyObject *receive_future;
28} nxt_py_asgi_lifespan_t;
29
30
30static PyObject *nxt_py_asgi_lifespan_target_startup(
31 nxt_py_asgi_ctx_data_t *ctx_data, nxt_python_target_t *target);
32static int nxt_py_asgi_lifespan_target_shutdown(
33 nxt_py_asgi_lifespan_t *lifespan);
31static PyObject *nxt_py_asgi_lifespan_receive(PyObject *self, PyObject *none);
32static PyObject *nxt_py_asgi_lifespan_send(PyObject *self, PyObject *dict);
33static PyObject *nxt_py_asgi_lifespan_send_startup(
34 nxt_py_asgi_lifespan_t *lifespan, int v, PyObject *dict);
35static PyObject *nxt_py_asgi_lifespan_send_(nxt_py_asgi_lifespan_t *lifespan,
36 int v, int *sent, PyObject **future);
37static PyObject *nxt_py_asgi_lifespan_send_shutdown(
38 nxt_py_asgi_lifespan_t *lifespan, int v, PyObject *dict);

--- 25 unchanged lines hidden (view full) ---

64 .tp_iternext = nxt_py_asgi_next,
65 .tp_methods = nxt_py_asgi_lifespan_methods,
66};
67
68
69int
70nxt_py_asgi_lifespan_startup(nxt_py_asgi_ctx_data_t *ctx_data)
71{
34static PyObject *nxt_py_asgi_lifespan_receive(PyObject *self, PyObject *none);
35static PyObject *nxt_py_asgi_lifespan_send(PyObject *self, PyObject *dict);
36static PyObject *nxt_py_asgi_lifespan_send_startup(
37 nxt_py_asgi_lifespan_t *lifespan, int v, PyObject *dict);
38static PyObject *nxt_py_asgi_lifespan_send_(nxt_py_asgi_lifespan_t *lifespan,
39 int v, int *sent, PyObject **future);
40static PyObject *nxt_py_asgi_lifespan_send_shutdown(
41 nxt_py_asgi_lifespan_t *lifespan, int v, PyObject *dict);

--- 25 unchanged lines hidden (view full) ---

67 .tp_iternext = nxt_py_asgi_next,
68 .tp_methods = nxt_py_asgi_lifespan_methods,
69};
70
71
72int
73nxt_py_asgi_lifespan_startup(nxt_py_asgi_ctx_data_t *ctx_data)
74{
72 int rc;
75 size_t size;
76 PyObject *lifespan;
77 PyObject **target_lifespans;
78 nxt_int_t i;
79 nxt_python_target_t *target;
80
81 size = nxt_py_targets->count * sizeof(PyObject*);
82
83 target_lifespans = nxt_unit_malloc(NULL, size);
84 if (nxt_slow_path(target_lifespans == NULL)) {
85 nxt_unit_alert(NULL, "Failed to allocate lifespan data");
86 return NXT_UNIT_ERROR;
87 }
88
89 memset(target_lifespans, 0, size);
90
91 for (i = 0; i < nxt_py_targets->count; i++) {
92 target = &nxt_py_targets->target[i];
93
94 lifespan = nxt_py_asgi_lifespan_target_startup(ctx_data, target);
95 if (nxt_slow_path(lifespan == NULL)) {
96 return NXT_UNIT_ERROR;
97 }
98
99 target_lifespans[i] = lifespan;
100 }
101
102 ctx_data->target_lifespans = target_lifespans;
103
104 return NXT_UNIT_OK;
105}
106
107
108static PyObject *
109nxt_py_asgi_lifespan_target_startup(nxt_py_asgi_ctx_data_t *ctx_data,
110 nxt_python_target_t *target)
111{
73 PyObject *scope, *res, *py_task, *receive, *send, *done;
74 PyObject *stage2;
112 PyObject *scope, *res, *py_task, *receive, *send, *done;
113 PyObject *stage2;
75 nxt_py_asgi_lifespan_t *lifespan;
114 nxt_py_asgi_lifespan_t *lifespan, *ret;
76
77 if (nxt_slow_path(PyType_Ready(&nxt_py_asgi_lifespan_type) != 0)) {
78 nxt_unit_alert(NULL,
79 "Python failed to initialize the 'asgi_lifespan' type object");
115
116 if (nxt_slow_path(PyType_Ready(&nxt_py_asgi_lifespan_type) != 0)) {
117 nxt_unit_alert(NULL,
118 "Python failed to initialize the 'asgi_lifespan' type object");
80 return NXT_UNIT_ERROR;
119 return NULL;
81 }
82
83 lifespan = PyObject_New(nxt_py_asgi_lifespan_t, &nxt_py_asgi_lifespan_type);
84 if (nxt_slow_path(lifespan == NULL)) {
85 nxt_unit_alert(NULL, "Python failed to create lifespan object");
120 }
121
122 lifespan = PyObject_New(nxt_py_asgi_lifespan_t, &nxt_py_asgi_lifespan_type);
123 if (nxt_slow_path(lifespan == NULL)) {
124 nxt_unit_alert(NULL, "Python failed to create lifespan object");
86 return NXT_UNIT_ERROR;
125 return NULL;
87 }
88
126 }
127
89 rc = NXT_UNIT_ERROR;
128 ret = NULL;
90
91 receive = PyObject_GetAttrString((PyObject *) lifespan, "receive");
92 if (nxt_slow_path(receive == NULL)) {
93 nxt_unit_alert(NULL, "Python failed to get 'receive' method");
94 goto release_lifespan;
95 }
96
97 send = PyObject_GetAttrString((PyObject *) lifespan, "send");

--- 27 unchanged lines hidden (view full) ---

125 lifespan->shutdown_future = NULL;
126 lifespan->receive_future = NULL;
127
128 scope = nxt_py_asgi_new_scope(NULL, nxt_py_lifespan_str, nxt_py_2_0_str);
129 if (nxt_slow_path(scope == NULL)) {
130 goto release_future;
131 }
132
129
130 receive = PyObject_GetAttrString((PyObject *) lifespan, "receive");
131 if (nxt_slow_path(receive == NULL)) {
132 nxt_unit_alert(NULL, "Python failed to get 'receive' method");
133 goto release_lifespan;
134 }
135
136 send = PyObject_GetAttrString((PyObject *) lifespan, "send");

--- 27 unchanged lines hidden (view full) ---

164 lifespan->shutdown_future = NULL;
165 lifespan->receive_future = NULL;
166
167 scope = nxt_py_asgi_new_scope(NULL, nxt_py_lifespan_str, nxt_py_2_0_str);
168 if (nxt_slow_path(scope == NULL)) {
169 goto release_future;
170 }
171
133 if (!nxt_py_asgi_legacy) {
172 if (!target->asgi_legacy) {
134 nxt_unit_req_debug(NULL, "Python call ASGI 3.0 application");
135
173 nxt_unit_req_debug(NULL, "Python call ASGI 3.0 application");
174
136 res = PyObject_CallFunctionObjArgs(nxt_py_application,
175 res = PyObject_CallFunctionObjArgs(target->application,
137 scope, receive, send, NULL);
138
139 } else {
140 nxt_unit_req_debug(NULL, "Python call legacy application");
141
176 scope, receive, send, NULL);
177
178 } else {
179 nxt_unit_req_debug(NULL, "Python call legacy application");
180
142 res = PyObject_CallFunctionObjArgs(nxt_py_application, scope, NULL);
181 res = PyObject_CallFunctionObjArgs(target->application, scope, NULL);
143 if (nxt_slow_path(res == NULL)) {
144 nxt_unit_log(NULL, NXT_UNIT_LOG_INFO,
145 "ASGI Lifespan processing exception");
146 nxt_python_print_exception();
147
148 lifespan->disabled = 1;
182 if (nxt_slow_path(res == NULL)) {
183 nxt_unit_log(NULL, NXT_UNIT_LOG_INFO,
184 "ASGI Lifespan processing exception");
185 nxt_python_print_exception();
186
187 lifespan->disabled = 1;
149 rc = NXT_UNIT_OK;
150
188
189 Py_INCREF(lifespan);
190 ret = lifespan;
191
151 goto release_scope;
152 }
153
154 if (nxt_slow_path(PyCallable_Check(res) == 0)) {
155 nxt_unit_req_error(NULL,
156 "Legacy ASGI application returns not a callable");
157
158 Py_DECREF(res);

--- 47 unchanged lines hidden (view full) ---

206 nxt_unit_alert(NULL, "Python failed to call loop.run_until_complete");
207 nxt_python_print_exception();
208 goto release_task;
209 }
210
211 Py_DECREF(res);
212
213 if (lifespan->startup_sent == 1 || lifespan->disabled) {
192 goto release_scope;
193 }
194
195 if (nxt_slow_path(PyCallable_Check(res) == 0)) {
196 nxt_unit_req_error(NULL,
197 "Legacy ASGI application returns not a callable");
198
199 Py_DECREF(res);

--- 47 unchanged lines hidden (view full) ---

247 nxt_unit_alert(NULL, "Python failed to call loop.run_until_complete");
248 nxt_python_print_exception();
249 goto release_task;
250 }
251
252 Py_DECREF(res);
253
254 if (lifespan->startup_sent == 1 || lifespan->disabled) {
214 ctx_data->lifespan = (PyObject *) lifespan;
215 Py_INCREF(ctx_data->lifespan);
255 Py_INCREF(lifespan);
216
256
217 rc = NXT_UNIT_OK;
257 ret = lifespan;
218 }
219
220release_task:
221 Py_DECREF(py_task);
222release_scope:
223 Py_DECREF(scope);
224release_future:
225 Py_CLEAR(lifespan->startup_future);
226release_done:
227 Py_DECREF(done);
228release_send:
229 Py_DECREF(send);
230release_receive:
231 Py_DECREF(receive);
232release_lifespan:
233 Py_DECREF(lifespan);
234
258 }
259
260release_task:
261 Py_DECREF(py_task);
262release_scope:
263 Py_DECREF(scope);
264release_future:
265 Py_CLEAR(lifespan->startup_future);
266release_done:
267 Py_DECREF(done);
268release_send:
269 Py_DECREF(send);
270release_receive:
271 Py_DECREF(receive);
272release_lifespan:
273 Py_DECREF(lifespan);
274
235 return rc;
275 return (PyObject *) ret;
236}
237
238
239int
240nxt_py_asgi_lifespan_shutdown(nxt_unit_ctx_t *ctx)
241{
276}
277
278
279int
280nxt_py_asgi_lifespan_shutdown(nxt_unit_ctx_t *ctx)
281{
242 PyObject *msg, *future, *res;
282 nxt_int_t i, ret;
243 nxt_py_asgi_lifespan_t *lifespan;
244 nxt_py_asgi_ctx_data_t *ctx_data;
245
246 ctx_data = ctx->data;
247
283 nxt_py_asgi_lifespan_t *lifespan;
284 nxt_py_asgi_ctx_data_t *ctx_data;
285
286 ctx_data = ctx->data;
287
248 lifespan = (nxt_py_asgi_lifespan_t *) ctx_data->lifespan;
288 for (i = 0; i < nxt_py_targets->count; i++) {
289 lifespan = (nxt_py_asgi_lifespan_t *)ctx_data->target_lifespans[i];
249
290
291 ret = nxt_py_asgi_lifespan_target_shutdown(lifespan);
292 if (nxt_slow_path(ret != NXT_UNIT_OK)) {
293 return NXT_UNIT_ERROR;
294 }
295 }
296
297 nxt_unit_free(NULL, ctx_data->target_lifespans);
298
299 return NXT_UNIT_OK;
300}
301
302
303static int
304nxt_py_asgi_lifespan_target_shutdown(nxt_py_asgi_lifespan_t *lifespan)
305{
306 PyObject *msg, *future, *res;
307 nxt_py_asgi_ctx_data_t *ctx_data;
308
309 ctx_data = lifespan->ctx_data;
310
250 if (nxt_slow_path(lifespan == NULL || lifespan->disabled)) {
251 return NXT_UNIT_OK;
252 }
253
254 lifespan->shutdown_called = 1;
255
256 if (lifespan->receive_future != NULL) {
257 future = lifespan->receive_future;

--- 289 unchanged lines hidden ---
311 if (nxt_slow_path(lifespan == NULL || lifespan->disabled)) {
312 return NXT_UNIT_OK;
313 }
314
315 lifespan->shutdown_called = 1;
316
317 if (lifespan->receive_future != NULL) {
318 future = lifespan->receive_future;

--- 289 unchanged lines hidden ---