Skip to content

projectivetech/dont-stall-my-process

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 

Repository files navigation

DontStallMyProcess

This little gem helps you in case one of your native extensions goes crazy and stalls your entire Ruby process.

It takes a Ruby class, instantiates it in a forked subprocess and communicates with it over DRb. You can define timeouts for function execution times. If the timeout is exceeded, the subprocess is terminated (and killed if necessary).

Usage

obj = DontStallMyProcess.create <klass> [, <configuration>]

where klass is a class name and configuration looks like this:

{
  timeout: 120      # Seconds for a method of the SomeClass instance to execute.
  methods: {        # Hash of methods that should get nested DRb services.
    somemethodname: {
      <description of nested remote object; same way but without :klass...>
    },
    ...
  }
}

The :timeout specifies how long a remote DRb method is allowed to take. When :timeout seconds have passed, the child process along with all of its DRb providers will be killed (TERM-5sec-KILL) and a TimeoutExceeded exception will be thrown. If not given, :timeout will default to 300 seconds.

Methods not listed in the :methods hash will have usual DRb marshall/unmarshall behaviour. Methods listed in there will return a DRb proxy as well, and you can pass in another nested :methods hash there. You may also overwrite the :timeout option, if you don't the value of the parent configuration will be used.

Nested DRb services will run in the same child process.

Only one instance of nested classes will be created, i.e., the remote method will only be called once! However, if an instance is garbage-collected, or you have manually called the stop_service! method, the remote method will be called again.

Subprocess will be ended automatically after all proxy objects have been garbage-collected or manually disconnected by calling stop_service!. If you pass a true parameter, nested proxies will be terminated, too. Make sure to not use these objects afterwards. Ypu can also provide a block to the create method in which case the service will be automatically stopped when the block execution ends.

Global configuration

DontStallMyProcess.configure do |config|
  config.sigkill_only = false
  config.close_stdio = true
  config.restore_all_traps = false
  config.skip_at_exit_handlers = false
  config.process_pool_size = 10
  config.subprocess_name = 'DontStallMyProcess'
  config.after_fork do |pid|
    <...>
  end
end

If the `sigkill_only` flag is set to true, the dead process will be terminated using `SIGKILL` only, so
no `TERM` signal will be sent. This is useful for some parent processes (e.g., Sidekiq) that trap
the `TERM` signal to do some shutdown logic on their own. `sigkill_only` defaults to `false`.

The `close_stdio` flag causes the subprocess to close `$stdout` and `$stderr` after the fork. Defaults to `true`.

When the `restore_all_traps` flag is set, all signal handlers will be reset to the Ruby default signal handlers. See documentation on Ruby `Signal` module for more information.

`skip_at_exit_handlers` will define an `at_exit` block after the subprocess has been forked that calls `exit!` and hence skips all previously defined exit procs. Defaults to `false`.

When `process_pool_size` is set to a value > 0, that number of processes will be kept alive and be re-used when all their DRb services have been terminated (i.e. all local proxies have been garbage-collected). Defaults to `nil` (same as zero) which turns off process pooling.

The `subprocess_name` string is the name of the subprocess. The string `%{parent}` will be interpolated to the parent process' name, the string `%{klass}` with the name of the main class to be contained, or `<pool` if the process remains in the pool and does not serve any class. Defaults to `nil` which means the subprocess is not renamed at all, but instead keeps the name of the parent process.

The `after_fork` method of the configuration object may be used to register a `Proc` that is called right
when the subprocess has been spawned. This is useful for overwriting signal traps, or closing file descriptors
or the like.

## Caveats

Kernel methods (e.g., `open`, `format`, etc.) are not supported at the moment. Due to the
double indirection of the DRb service (we need a proxy object on both sides of the communication
and a lot of `public_send`s), these methods are called instead of the intended remote methods
as they are privately included into the proxy class (and thus, `method_missing` is not called when
you `send` one of them).

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages