New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Address dangling threads in Timeout module #6127
Conversation
This is a good find, and I agree it should be patched something like you did here. Unfortunately this is not quite the right logic. The finalizer logic puts the In this case you do not hold a reference to the finalizer, so it is immediately dereferenced and likely to trigger shutdown of the Unfortunately it seems like we don't have an easy way to register a snippit of code to be run at exit from Java in the same way we have I think this change would work, but I do wonder if we should add something to diff --git a/core/src/main/java/org/jruby/ext/timeout/Timeout.java b/core/src/main/java/org/jruby/ext/timeout/Timeout.java
index 35afa6517f..4712030203 100644
--- a/core/src/main/java/org/jruby/ext/timeout/Timeout.java
+++ b/core/src/main/java/org/jruby/ext/timeout/Timeout.java
@@ -45,6 +45,7 @@ import org.jruby.RubyThread;
import org.jruby.RubyTime;
import org.jruby.anno.JRubyMethod;
import org.jruby.exceptions.RaiseException;
+import org.jruby.javasupport.JavaUtil;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.Block;
import org.jruby.runtime.ThreadContext;
@@ -68,6 +69,9 @@ public class Timeout {
new ScheduledThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), new DaemonThreadFactory());
executor.setRemoveOnCancelPolicy(true);
timeout.setInternalVariable(EXECUTOR_VARIABLE, executor);
+
+ // for at_exit shutdown from the Ruby code
+ timeout.setInstanceVariable("@" + EXECUTOR_VARIABLE, JavaUtil.convertJavaToUsableRubyObject(timeout.getRuntime(), executor));
}
diff --git a/lib/ruby/stdlib/timeout.rb b/lib/ruby/stdlib/timeout.rb
index 2c0a0e69d0..d4fed865b1 100644
--- a/lib/ruby/stdlib/timeout.rb
+++ b/lib/ruby/stdlib/timeout.rb
@@ -56,6 +56,12 @@ end
# Load executor-based timeout logic into Timeout mod
JRuby::Util.load_ext('org.jruby.ext.timeout.Timeout')
+# Register an at_exit hook to shut down the Timeout executor
+at_exit do
+ executor = Timeout.instance_variable_get(:@__executor__)
+ executor.shutdown
+end
+
def timeout(*args, &block)
warn "Object##{__method__} is deprecated, use Timeout.timeout instead.", uplevel: 1
Timeout.timeout(*args, &block) |
That change looks good to me. 👍 |
👍 on being able to achieve the same (register an |
See jruby#6127 for a case that needed to be able to add exit hooks from Java, to shut down the executor associated with the Timeout library.
Replaces Ruby-based internals tweaking from jruby#6127.
@ProfessorEugene @kares See #6133 for an improved API. |
JRuby executors are not shutting down, causing a build-up of JRuby worker threads. A patch for JRuby has been submitted <jruby/jruby#6127> but until merged and puppetserver updated to use the new version this change will explicitly shut down the worker threads.
JRuby executors are not shutting down, causing a build-up of JRuby worker threads. A patch for JRuby has been submitted <jruby/jruby#6127> but until merged and puppetserver updated to use the new version this change will explicitly shut down the worker threads.
Some JVM-based projects (e.g. puppetlabs/puppetserver) that embed JRuby using
ScriptingContainer
and use thetimeout
module suffer thread leaks when recyclingScriptingContainer
s. Such users appear to expectScriptingContainer#terminate
to clean up all allocated resources (within reason) including threads.This PR is an attempt to do so by shutting down the
ScheduledThreadPoolExecutor
created during the initialization of theTimeout
module on Ruby teardown.