Previously, an exit hook installed during context teardown, for example
by a promise job queued by the exit hook, was kept in the context. When
the context was reused, the hook was called during the teardown of a
later request.
Now hooks are cleared together with the pending events, after the last
user code of the request has run.
The issue was introduced in
04f6dfb9 (0.9.2).
ngx_qjs_log_exception(e, ctx->log, "unhandled rejection");
}
+ qjs_clear_hooks(cx);
ngx_qjs_clear_events(ctx);
ngx_qjs_detach_ctx(ctx, cx);
ngx.log(ngx.ERR, 'exit hook ' + r.uri);
});
+ } else if (mode === 'reinstall') {
+ njs.on('exit', () => {
+ Promise.resolve().then(() => {
+ njs.on('exit', late('reinstalled exit hook'));
+ });
+ });
+
}
r.return(200, 'ok');
export default {content};
EOF
-$t->try_run('no njs available')->plan(9);
+$t->try_run('no njs available')->plan(11);
###############################################################################
for my $scope ('zero', 'reuse') {
- for my $mode ('timer', 'fetch', 'exit') {
+ for my $mode ('timer', 'fetch', 'exit', 'reinstall') {
like(http_get("/$scope?mode=$mode"), qr/ok$/, "$scope $mode");
}
}
}
+void
+qjs_clear_hooks(JSContext *ctx)
+{
+ unsigned i;
+ qjs_njs_t *njs;
+
+ njs = qjs_njs(ctx);
+ if (njs == NULL) {
+ return;
+ }
+
+ for (i = 0; i < njs_nitems(njs->hooks); i++) {
+ JS_FreeValue(ctx, njs->hooks[i]);
+ njs->hooks[i] = JS_UNDEFINED;
+ }
+}
+
+
static int
qjs_add_intrinsic_njs(JSContext *cx, JSValueConst global)
{
JSContext *qjs_new_context(JSRuntime *rt, qjs_module_t **addons);
JSValue qjs_call_exit_hook(JSContext *ctx);
+void qjs_clear_hooks(JSContext *ctx);
void *qjs_chb_ctx_alloc(void *ctx, size_t size);
void qjs_chb_ctx_free(void *ctx, void *p);
void *qjs_chb_rt_alloc(void *rt, size_t size);