Created
May 20, 2021 10:16
-
-
Save ocanty/66a820989d98568b73201a2fc4565b76 to your computer and use it in GitHub Desktop.
rbhooks.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff -r 03648307ff8c -r dbe215b6bda2 src/nxt_application.h | |
--- a/src/nxt_application.h Mon May 17 14:28:38 2021 -0700 | |
+++ b/src/nxt_application.h Tue May 18 05:41:06 2021 +0000 | |
@@ -73,6 +73,7 @@ typedef struct { | |
typedef struct { | |
nxt_str_t script; | |
uint32_t threads; | |
+ nxt_str_t hooks; | |
} nxt_ruby_app_conf_t; | |
diff -r 03648307ff8c -r dbe215b6bda2 src/nxt_conf_validation.c | |
--- a/src/nxt_conf_validation.c Mon May 17 14:28:38 2021 -0700 | |
+++ b/src/nxt_conf_validation.c Tue May 18 05:41:06 2021 +0000 | |
@@ -671,6 +671,9 @@ static nxt_conf_vldt_object_t nxt_conf_ | |
.name = nxt_string("threads"), | |
.type = NXT_CONF_VLDT_INTEGER, | |
.validator = nxt_conf_vldt_threads, | |
+ }, { | |
+ .name = nxt_string("hooks"), | |
+ .type = NXT_CONF_VLDT_STRING | |
}, | |
NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members) | |
diff -r 03648307ff8c -r dbe215b6bda2 src/nxt_main_process.c | |
--- a/src/nxt_main_process.c Mon May 17 14:28:38 2021 -0700 | |
+++ b/src/nxt_main_process.c Tue May 18 05:41:06 2021 +0000 | |
@@ -265,6 +265,11 @@ static nxt_conf_map_t nxt_ruby_app_conf | |
NXT_CONF_MAP_INT32, | |
offsetof(nxt_common_app_conf_t, u.ruby.threads), | |
}, | |
+ { | |
+ nxt_string("hooks"), | |
+ NXT_CONF_MAP_STR, | |
+ offsetof(nxt_common_app_conf_t, u.ruby.hooks), | |
+ } | |
}; | |
diff -r 03648307ff8c -r dbe215b6bda2 src/ruby/nxt_ruby.c | |
--- a/src/ruby/nxt_ruby.c Mon May 17 14:28:38 2021 -0700 | |
+++ b/src/ruby/nxt_ruby.c Tue May 18 05:41:06 2021 +0000 | |
@@ -29,6 +29,11 @@ typedef struct { | |
static nxt_int_t nxt_ruby_start(nxt_task_t *task, | |
nxt_process_data_t *data); | |
static VALUE nxt_ruby_init_basic(VALUE arg); | |
+ | |
+static VALUE nxt_ruby_hook_procs_load(VALUE path); | |
+static VALUE nxt_ruby_hook_register(void); | |
+static VALUE nxt_ruby_hook_call_if_present(VALUE name); | |
+ | |
static VALUE nxt_ruby_rack_init(nxt_ruby_rack_init_t *rack_init); | |
static VALUE nxt_ruby_require_rubygems(VALUE arg); | |
@@ -78,6 +83,8 @@ static uint32_t compat[] = { | |
NXT_VERNUM, NXT_DEBUG, | |
}; | |
+static VALUE nxt_ruby_module_unit; | |
+static VALUE nxt_ruby_hook_procs; | |
static VALUE nxt_ruby_rackup; | |
static VALUE nxt_ruby_call; | |
@@ -115,6 +122,10 @@ static VALUE nxt_rb_server_addr_str; | |
static VALUE nxt_rb_server_name_str; | |
static VALUE nxt_rb_server_port_str; | |
static VALUE nxt_rb_server_protocol_str; | |
+static VALUE nxt_rb_on_worker_boot; | |
+static VALUE nxt_rb_on_worker_shutdown; | |
+static VALUE nxt_rb_on_thread_boot; | |
+static VALUE nxt_rb_on_thread_shutdown; | |
static nxt_ruby_string_t nxt_rb_strings[] = { | |
{ nxt_string("80"), &nxt_rb_80_str }, | |
@@ -132,6 +143,10 @@ static nxt_ruby_string_t nxt_rb_strings[ | |
{ nxt_string("SERVER_NAME"), &nxt_rb_server_name_str }, | |
{ nxt_string("SERVER_PORT"), &nxt_rb_server_port_str }, | |
{ nxt_string("SERVER_PROTOCOL"), &nxt_rb_server_protocol_str }, | |
+ { nxt_string("on_worker_boot"), &nxt_rb_on_worker_boot }, | |
+ { nxt_string("on_worker_shutdown"), &nxt_rb_on_worker_shutdown }, | |
+ { nxt_string("on_thread_boot"), &nxt_rb_on_thread_boot }, | |
+ { nxt_string("on_thread_shutdown"), &nxt_rb_on_thread_shutdown }, | |
{ nxt_null_string, NULL }, | |
}; | |
@@ -183,11 +198,65 @@ nxt_ruby_done_strings(void) | |
} | |
+static | |
+VALUE nxt_ruby_hook_procs_load(VALUE path) | |
+{ | |
+ VALUE file, file_obj; | |
+ | |
+ rb_define_module_function(nxt_ruby_module_unit, "on_worker_boot", | |
+ &nxt_ruby_hook_register, 0); | |
+ rb_define_module_function(nxt_ruby_module_unit, "on_worker_shutdown", | |
+ &nxt_ruby_hook_register, 0); | |
+ rb_define_module_function(nxt_ruby_module_unit, "on_thread_boot", | |
+ &nxt_ruby_hook_register, 0); | |
+ rb_define_module_function(nxt_ruby_module_unit, "on_thread_shutdown", | |
+ &nxt_ruby_hook_register, 0); | |
+ | |
+ file = rb_const_get(rb_cObject, rb_intern("File")); | |
+ file_obj = rb_funcall(file, rb_intern("read"), 1, path); | |
+ | |
+ return rb_funcall(nxt_ruby_module_unit, rb_intern("module_eval"), 3, | |
+ file_obj, path, INT2NUM(1)); | |
+} | |
+ | |
+ | |
+static VALUE | |
+nxt_ruby_hook_register() | |
+{ | |
+ VALUE kernel, callee, callee_str; | |
+ | |
+ rb_need_block(); | |
+ | |
+ kernel = rb_const_get(rb_cObject, rb_intern("Kernel")); | |
+ callee = rb_funcall(kernel, rb_intern("__callee__"), 0); | |
+ callee_str = rb_funcall(callee, rb_intern("to_s"), 0); | |
+ | |
+ rb_hash_aset(nxt_ruby_hook_procs, callee_str, rb_block_proc()); | |
+ | |
+ return Qnil; | |
+} | |
+ | |
+ | |
+static VALUE | |
+nxt_ruby_hook_call_if_present(VALUE name) | |
+{ | |
+ VALUE proc; | |
+ | |
+ proc = rb_hash_lookup(nxt_ruby_hook_procs, name); | |
+ | |
+ if (proc == Qnil) { | |
+ return Qnil; | |
+ } | |
+ | |
+ return rb_funcall(proc, rb_intern("call"), 0); | |
+} | |
+ | |
+ | |
static nxt_int_t | |
nxt_ruby_start(nxt_task_t *task, nxt_process_data_t *data) | |
{ | |
int state, rc; | |
- VALUE res; | |
+ VALUE res, hooks; | |
nxt_ruby_ctx_t ruby_ctx; | |
nxt_unit_ctx_t *unit_ctx; | |
nxt_unit_init_t ruby_unit_init; | |
@@ -232,6 +301,33 @@ nxt_ruby_start(nxt_task_t *task, nxt_pro | |
nxt_ruby_call = Qnil; | |
+ nxt_ruby_module_unit = rb_define_module("Unit"); | |
+ | |
+ nxt_ruby_hook_procs = rb_hash_new(); | |
+ | |
+ rb_gc_register_address(&nxt_ruby_hook_procs); | |
+ | |
+ if (c->hooks.start != NULL) { | |
+ hooks = rb_str_new((const char *) c->hooks.start, | |
+ (long) c->hooks.length); | |
+ | |
+ rb_protect(nxt_ruby_hook_procs_load, hooks, &state); | |
+ rb_str_free(hooks); | |
+ if (nxt_slow_path(state != 0)) { | |
+ nxt_ruby_exception_log(NULL, NXT_LOG_ALERT, | |
+ "Failed to setup hooks"); | |
+ return NXT_ERROR; | |
+ } | |
+ } | |
+ | |
+ rb_protect(nxt_ruby_hook_call_if_present, | |
+ nxt_rb_on_worker_boot, &state); | |
+ if (nxt_slow_path(state != 0)) { | |
+ nxt_ruby_exception_log(NULL, NXT_LOG_ERR, | |
+ "Failed to call hook on_worker_boot"); | |
+ return NXT_ERROR; | |
+ } | |
+ | |
nxt_ruby_rackup = nxt_ruby_rack_init(&rack_init); | |
if (nxt_slow_path(nxt_ruby_rackup == Qnil)) { | |
return NXT_ERROR; | |
@@ -274,11 +370,32 @@ nxt_ruby_start(nxt_task_t *task, nxt_pro | |
goto fail; | |
} | |
+ rb_protect(nxt_ruby_hook_call_if_present, | |
+ nxt_rb_on_thread_boot, &state); | |
+ if (nxt_slow_path(state != 0)) { | |
+ nxt_ruby_exception_log(NULL, NXT_LOG_ERR, | |
+ "Failed to call on_thread_boot"); | |
+ } | |
+ | |
rc = (intptr_t) rb_thread_call_without_gvl(nxt_ruby_unit_run, unit_ctx, | |
nxt_ruby_ubf, unit_ctx); | |
+ rb_protect(nxt_ruby_hook_call_if_present, | |
+ nxt_rb_on_thread_shutdown, &state); | |
+ if (nxt_slow_path(state != 0)) { | |
+ nxt_ruby_exception_log(NULL, NXT_LOG_ERR, | |
+ "Failed to call on_thread_shutdown"); | |
+ } | |
+ | |
nxt_ruby_join_threads(unit_ctx, c); | |
+ rb_protect(nxt_ruby_hook_call_if_present, | |
+ nxt_rb_on_worker_shutdown, &state); | |
+ if (nxt_slow_path(state != 0)) { | |
+ nxt_ruby_exception_log(NULL, NXT_LOG_ERR, | |
+ "Failed to call hook on_worker_shutdown"); | |
+ } | |
+ | |
nxt_unit_done(unit_ctx); | |
nxt_ruby_ctx_done(&ruby_ctx); | |
@@ -1069,14 +1186,17 @@ nxt_ruby_exception_log(nxt_unit_request_ | |
return; | |
} | |
+ eclass = rb_class_name(rb_class_of(err)); | |
+ msg = rb_funcall(err, rb_intern("message"), 0); | |
+ | |
ary = rb_funcall(err, rb_intern("backtrace"), 0); | |
if (nxt_slow_path(RARRAY_LEN(ary) == 0)) { | |
+ nxt_unit_req_log(req, level, "Ruby: %s (%s)", RSTRING_PTR(msg), | |
+ RSTRING_PTR(eclass)); | |
+ | |
return; | |
} | |
- eclass = rb_class_name(rb_class_of(err)); | |
- msg = rb_funcall(err, rb_intern("message"), 0); | |
- | |
nxt_unit_req_log(req, level, "Ruby: %s: %s (%s)", | |
RSTRING_PTR(RARRAY_PTR(ary)[0]), | |
RSTRING_PTR(msg), RSTRING_PTR(eclass)); | |
@@ -1116,6 +1236,10 @@ nxt_ruby_atexit(void) | |
rb_gc_unregister_address(&nxt_ruby_call); | |
} | |
+ if (nxt_ruby_hook_procs != Qnil) { | |
+ rb_gc_unregister_address(&nxt_ruby_hook_procs); | |
+ } | |
+ | |
nxt_ruby_done_strings(); | |
ruby_cleanup(0); | |
@@ -1178,6 +1302,7 @@ nxt_ruby_thread_create_gvl(void *rctx) | |
static VALUE | |
nxt_ruby_thread_func(VALUE arg) | |
{ | |
+ int state; | |
nxt_unit_ctx_t *ctx; | |
nxt_ruby_ctx_t *rctx; | |
@@ -1190,9 +1315,23 @@ nxt_ruby_thread_func(VALUE arg) | |
goto fail; | |
} | |
+ rb_protect(nxt_ruby_hook_call_if_present, | |
+ nxt_rb_on_thread_boot, &state); | |
+ if (nxt_slow_path(state != 0)) { | |
+ nxt_ruby_exception_log(NULL, NXT_LOG_ERR, | |
+ "Failed to call on_thread_boot"); | |
+ } | |
+ | |
(void) rb_thread_call_without_gvl(nxt_ruby_unit_run, ctx, | |
nxt_ruby_ubf, ctx); | |
+ rb_protect(nxt_ruby_hook_call_if_present, | |
+ nxt_rb_on_thread_shutdown, &state); | |
+ if (nxt_slow_path(state != 0)) { | |
+ nxt_ruby_exception_log(NULL, NXT_LOG_ERR, | |
+ "Failed to call on_thread_shutdown"); | |
+ } | |
+ | |
nxt_unit_done(ctx); | |
fail: |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment