Ruby check whether program is currently being closed

我只是一个虾纸丫 提交于 2019-12-11 04:25:43

问题


How can I check whether current script in Ruby is being closed? Particularly, in case program is closing, I want to set @reconnect to false, not to allow web-socket reconnect any more. I tried Signal.trap("TERM"), but it doesn't seem to work.

@reconnect is an instance variable inside WebsocketClient class, i can't directly change it in my script outside class.

class WebsocketClient
    def ws_closed(event)
      $logger.warn "WS CLOSED"
      Signal.trap("TERM") { 
        @stop = true
        @reconnect = false
      }

      unless $reauth
        if @stop
          EM.stop
        elsif @reconnect
          $logger.warn "Reconnecting..."
          EM.add_timer(@reconnect_after){ connect! }
        end
      end
    end
end

at_exit {
  $logger.fatal "Application terminated. Shutting down gracefully..."
  # ...
  # Do some exit work...
  # ...
  exit!
}

Output on CTRL-C

01-02-2018 12:00:54.59  WARN    > WS CLOSED
01-02-2018 12:00:54.595 WARN    > Reconnecting...
01-02-2018 12:00:54.596 FATAL   > Application terminated. Shutting down gracefully..

回答1:


See Below taken from my answer Here but seems more pertinent to your question than the one it is currently attached to:

Your best bet is probably a bit easier than signal trapping. The Kernel Module actually offers you an #at_exit method that will be executed just prior to the program actually exiting.

Usage: (from Kernel#at_exit Docs)

def do_at_exit(str1)
  at_exit { print str1 }
end
at_exit { puts "cruel world" }
do_at_exit("goodbye ")
exit

"produces:"

goodbye cruel world

as you can see you can define multiple handlers which will be executed in reverse order when the program exits.

Since Kernel is included in Object you can handle Object specifics as well like

class People
  at_exit {puts "The #{self.name} have left"}
end
exit
# The People have left

or even on instances

p = People.new
p.send(:at_exit, &->{puts "We are leaving"})
# We are leaving
# The People have left

Additionally for more specific Object based implementations you can take a look at ObjectSpace.define_finalizer.

example of usage:

class Person
  def self.finalize(name)
    proc {puts "Goodbye Cruel World -#{name}"}
  end 
  def initialize(name)
    @name = name
    ObjectSpace.define_finalizer(self, self.class.finalize(@name))
  end
end

Usage:

p = Person.new("engineersmnky")
exit
# Goodbye Cruel World -engineersmnky

This may not be specifically what you want as this will fire when an Object is garbage collected as well (not great for ephemeral objects) but if you have objects that should exist throughout the entire application this could still be used similar to an at_exit . Example

# requiring WeakRef to allow garbage collection 
# See: https://ruby-doc.org/stdlib-2.3.3/libdoc/weakref/rdoc/WeakRef.html
require 'weakref' # 
p1 = Person.new("Engineer")
p2 = Person.new("Engineer's Monkey")
p2 = WeakRef.new(p2)
GC.start # just for this example
# Goodbye Cruel World -Engineer's Monkey
#=> nil
p2
#=> WeakRef::RefError: Invalid Reference - probably recycled
exit
# Goodbye Cruel World -Engineer

As you can see the defined finalizer for p2 fired because the Person was gc'd but the program has not exited yet. p1's finalizer waited until exit to fire because it retained its reference throughout the application.



来源:https://stackoverflow.com/questions/48558953/ruby-check-whether-program-is-currently-being-closed

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!