]> git.kaiwu.me - njs.git/commitdiff
Added promises execution after njs.on('exit', ..) hook.
authorVadim Zhestikov <v.zhestikov@f5.com>
Wed, 5 Nov 2025 01:35:35 +0000 (17:35 -0800)
committerVadimZhestikov <108960056+VadimZhestikov@users.noreply.github.com>
Thu, 6 Nov 2025 23:27:06 +0000 (15:27 -0800)
external/njs_shell.c
nginx/ngx_js.c
nginx/t/js_exit.t
src/njs.h
src/njs_vm.c

index b29ccee238a204272c834ec46bf18d028a94229b..e459f5a653685d024213fea83b8bb7905bd9ada7 100644 (file)
@@ -1366,6 +1366,17 @@ njs_engine_njs_init(njs_engine_t *engine, njs_opts_t *opts)
 static njs_int_t
 njs_engine_njs_destroy(njs_engine_t *engine)
 {
+    njs_int_t  ret;
+
+    (void) njs_vm_call_exit_hook(engine->u.njs.vm);
+
+    for ( ;; ) {
+        ret = njs_vm_execute_pending_job(engine->u.njs.vm);
+        if (ret == NJS_OK) {
+            break;
+        }
+    }
+
     njs_vm_destroy(engine->u.njs.vm);
     njs_mp_destroy(engine->pool);
 
@@ -2697,13 +2708,22 @@ njs_engine_qjs_destroy(njs_engine_t *engine)
 {
     uint32_t                i;
     njs_ev_t                *ev;
+    njs_int_t               ret;
+    JSContext               *cx;
     njs_queue_t             *events;
     njs_console_t           *console;
     njs_262agent_t          *agent;
     njs_queue_link_t        *link;
     njs_rejected_promise_t  *rejected_promise;
 
-    qjs_call_exit_hook(engine->u.qjs.ctx);
+    (void) qjs_call_exit_hook(engine->u.qjs.ctx);
+
+    for ( ;; ) {
+        ret = JS_ExecutePendingJob(JS_GetRuntime(engine->u.qjs.ctx), &cx);
+        if (ret == 0) {
+            break;
+        }
+    }
 
     console = JS_GetRuntimeOpaque(engine->u.qjs.rt);
 
index b4e78159ecb310b141b3d8126da59bd20c20f5f0..b0b64d97447e09472743bce2d130aa875d6872ae 100644 (file)
@@ -827,10 +827,18 @@ static void
 ngx_engine_njs_destroy(ngx_engine_t *e, ngx_js_ctx_t *ctx,
     ngx_js_loc_conf_t *conf)
 {
+    njs_int_t           ret;
     ngx_js_event_t     *event;
     njs_rbtree_node_t  *node;
 
     if (ctx != NULL) {
+        ret = njs_vm_call_exit_hook(e->u.njs.vm);
+        if (ret != NJS_OK) {
+            ngx_js_log_exception(e->u.njs.vm, ctx->log, "exit hook exception");
+        }
+
+        (void) ngx_njs_execute_pending_jobs(e->u.njs.vm, ctx->log);
+
         node = njs_rbtree_min(&ctx->waiting_events);
 
         while (njs_rbtree_is_there_successor(&ctx->waiting_events, node)) {
@@ -1198,6 +1206,8 @@ ngx_engine_qjs_destroy(ngx_engine_t *e, ngx_js_ctx_t *ctx,
             ngx_qjs_log_exception(e, ctx->log, "exit hook exception");
         }
 
+        (void) ngx_qjs_execute_pending_jobs(cx, ctx->log);
+
         node = njs_rbtree_min(&ctx->waiting_events);
 
         while (njs_rbtree_is_there_successor(&ctx->waiting_events, node)) {
index ff9e1ad13cfe519bd6da192fb904d737da591b11..c89eb09012527a94cafece335ad140766a091a16 100644 (file)
@@ -60,6 +60,9 @@ $t->write_file('test.js', <<EOF);
     function test(r) {
         njs.on('exit', function() {
             ngx.log(ngx.WARN, `exit hook: bs: \${r.variables.bytes_sent}`);
+
+            new Promise((resolve) => {resolve()})
+            .then(v => ngx.log(ngx.WARN, "exit hook promise"));
         });
 
         r.return(200, `bs: \${r.variables.bytes_sent}`);
@@ -81,7 +84,7 @@ $t->write_file('test.js', <<EOF);
 
 EOF
 
-$t->try_run('no njs')->plan(3);
+$t->try_run('no njs')->plan(4);
 
 ###############################################################################
 
@@ -93,8 +96,10 @@ like(http(
 
 $t->stop();
 
-like($t->read_file('error.log'), qr/\[warn\].*exit hook: bs: \d+/,
-       'exit hook logged');
+my $error_log = $t->read_file('error.log');
+
+like($error_log, qr/\[warn\].*exit hook: bs: \d+/, 'exit hook logged');
+like($error_log, qr/\[warn\].*exit hook promise/, 'exit hook promise logged');
 like($t->read_file('access.log'), qr/\[var:\d+ header:626172 url:\/test\]/,
        'access log has bytes_sent');
 
index 1592a234177b5d7d9233e4f9f67c76508a17e647..b4fb2617e44f85a8a3bf4feeec12722124475595 100644 (file)
--- a/src/njs.h
+++ b/src/njs.h
@@ -310,6 +310,7 @@ typedef njs_int_t (*njs_iterator_handler_t)(njs_vm_t *vm,
 NJS_EXPORT void njs_vm_opt_init(njs_vm_opt_t *options);
 NJS_EXPORT njs_vm_t *njs_vm_create(njs_vm_opt_t *options);
 NJS_EXPORT void njs_vm_destroy(njs_vm_t *vm);
+NJS_EXPORT njs_int_t njs_vm_call_exit_hook(njs_vm_t *vm);
 
 NJS_EXPORT njs_int_t njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end);
 NJS_EXPORT void njs_vm_set_module_loader(njs_vm_t *vm,
index 4b4a881a2d11010fc2a46939e63d938e320dde1b..19f07db403838951499dd7d011f0daa84d05101f 100644 (file)
@@ -191,13 +191,20 @@ njs_vm_ctor_push(njs_vm_t *vm)
 }
 
 
-void
-njs_vm_destroy(njs_vm_t *vm)
+njs_int_t
+njs_vm_call_exit_hook(njs_vm_t *vm)
 {
     if (vm->hooks[NJS_HOOK_EXIT] != NULL) {
-        (void) njs_vm_call(vm, vm->hooks[NJS_HOOK_EXIT], NULL, 0);
+        return njs_vm_call(vm, vm->hooks[NJS_HOOK_EXIT], NULL, 0);
     }
 
+    return NJS_OK;
+}
+
+
+void
+njs_vm_destroy(njs_vm_t *vm)
+{
     njs_mp_destroy(vm->mem_pool);
 }