Skip to content

Instantly share code, notes, and snippets.

@ocanty
Created May 20, 2021 10:16
Show Gist options
  • Save ocanty/66a820989d98568b73201a2fc4565b76 to your computer and use it in GitHub Desktop.
Save ocanty/66a820989d98568b73201a2fc4565b76 to your computer and use it in GitHub Desktop.
rbhooks.patch
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