How do I use thrift_client library hook feature? - ruby-on-rails

I'm using thrift_client 0.8.1 library. And it supports some hook interfaces.
client = ThriftClient.new(FooService, host)
client.add_callback :before_method do |*args|
ActionController::Base.logger.info instance_eval("#current_server")
logger.info args.inspect
end
client.add_callback :post_connect do |client|
logger.info "A thrift server connection has been made<#{client.current_server}>"
end
Everytime calling a method, I would like to write log the information of thrift server.
So I installed a :before method hook but I think instance_eval("#current_server") doesn't work as I expected. The #current_server is an instance variable in the ThriftClient class. What is the problem?

I don't believe that the :before_method callback is invoked within the ThriftClient instance context. This is the invocation of :before_method:
def do_callbacks(callback_type_sym, *args)
return unless #callbacks[callback_type_sym]
#callbacks[callback_type_sym].each do |callback|
callback.call(*args)
end
end
The :before_method CB is invoked with the method name. For :post_connect it is the client instance.

Related

Clock Schedule Once Error in class functions/methods

I have a class with two functions in a Kivy app. One function calls the second with Clock.schedule_once(function_name).
class SivaCEFBrowser(Screen):
def back_to_login(self):
App.get_running_app().root.current='login_screen'
App.get_running_app().root.transition.direction='right'
def go_to_verify(self):
App.get_running_app().root.current='verify_screen'
App.get_running_app().root.transition.direction='left'
def launch_cef_browser(self):
sys.excepthook = cef.ExceptHook # To shutdown all CEF processes on error.
cef.Initialize()
cef.CreateBrowserSync(url="https://www.google.com/", window_title="Hello World!")
cef.MessageLoop()
cef.Shutdown()
def trigger_browser(self):
Clock.schedule_once(self.launch_cef_browser)
When my code runs, the trigger_browser() function is called which, in turn, invokes launch_cef_browser(). This is the error that I get:
What am I missing here?
You need to define launch_cef_browser function like def launch_cef_browser(self, *args).
The *args argument is being used by kivy for internal processing of the function.

How to create and keep serialport connection in Ruby on Rails, handle infinity loop to create model with new messages?

I want to listening SerialPort and when message occurs then get or create Log model with id received from my device.
How to load once automatically SerialPort and keep established connection and if key_detected? in listener deal with Log model?
This is my autoloaded module in lib:
module Serialport
class Connection
def initialize(port = "/dev/tty0")
port_str = port
baud_rate = 9600
data_bits = 8
stop_bits = 1
parity = SerialPort::NONE
#sp = SerialPort.new(port_str, baud_rate, data_bits, stop_bits, parity)
#key_parts = []
#key_limit = 16 # number of slots in the RFID card.
while true do
listener
end
#sp.close
end
def key_detected?
#key_parts << #sp.getc
if #key_parts.size >= #key_limit
self.key = #key_parts.join()
#key_parts = []
true
else
false
end
end
def listener
if key_detected?
puts self.key
# log = Log.find(rfid: self.key).first_or_create(rfid: self.key)
end
end
end
end
Model:
class Log < ActiveRecord::Base
end
I would have written this in a comment, but it's a bit long... But I wonder if you could clarify your question, and I will update my answer as we go:
With all due respect to the Rails ability to "autoload", why not initialize a connection in an initialization file or while setting up the environment?
i.e., within a file in you_app/config/initializers called serial_port.rb:
SERIAL_PORT_CONNECTION = Serialport::Connection.new
Implementing an infinite loop within your Rails application will, in all probability, hang the Rails app and prevent it from being used as a web service.
What are you trying to accomplish?
If you just want to use active_record or active_support, why not just include these two gems in a separate script?
Alternatively, consider creating a separate thread for the infinite loop (or better yet, use a reactor (They are not that difficult to write, but there are plenty pre-written in the wild, such as Iodine which I wrote for implementing web services)...
Here's an example for an updated listener method, using a separate thread so you call it only once:
def listener
Thread.new do
loop { self.key while key_detected? }
# this will never be called - same as in your code.
#sp.close
end
end

How to implement RPC with RabbitMQ in Rails?

I want to implement an action that calls remote service with RabbitMQ and presents returned data. I implemented this (more as a proof of concept so far) in similar way to example taken from here: https://github.com/baowen/RailsRabbit and it looks like this:
controller:
def rpc
text = params[:text]
c = RpcClient.new('RPC server route key')
response = c.call text
render text: response
end
RabbitMQ RPC client:
class RpcClient < MQ
attr_reader :reply_queue
attr_accessor :response, :call_id
attr_reader :lock, :condition
def initialize()
# initialize exchange:
conn = Bunny.new(:automatically_recover => false)
conn.start
ch = conn.create_channel
#x = ch.default_exchange
#reply_queue = ch.queue("", :exclusive => true)
#server_queue = 'rpc_queue'
#lock = Mutex.new
#condition = ConditionVariable.new
that = self
#reply_queue.subscribe do |_delivery_info, properties, payload|
if properties[:correlation_id] == that.call_id
that.response = payload.to_s
that.lock.synchronize { that.condition.signal }
end
end
end
def call(message)
self.call_id = generate_uuid
#x.publish(message.to_s,
routing_key: #server_queue,
correlation_id: call_id,
reply_to: #reply_queue.name)
lock.synchronize { condition.wait(lock) }
response
end
private
def generate_uuid
# very naive but good enough for code
# examples
"#{rand}#{rand}#{rand}"
end
end
A few tests indicate that this approach works. On the other hand, this approach assumes creating a client (and subscribing to the queue) for every request on this action, which is inefficient according to the RabbitMQ tutorial. So I've got two questions:
Is it possible to avoid creating a queue for every Rails request?
How will this approach (with threads and mutex) interfere with my whole Rails environment? Is it safe to implement things this way in Rails? I'm using Puma as my web server, if it's relevant.
Is it possible to avoid creating a queue for every Rails request?
Yes - there is no need for every single request to have it's own reply queue.
You can use the built-in direct-reply queue. See the documentation here.
If you don't want to use the direct-reply feature, you can create a single reply queue per rails instance. You can use a single reply queue, and have the correlation id help you figure out where the reply needs to go within that rails instance.
How will this approach (with threads and mutex) interfere with my whole Rails environment? Is it safe to implement things this way in Rails?
what's the purpose of the lock / mutex in this code? doesn't seem necessary to me, but i'm probably missing something since i haven't done ruby in about 5 years :)

Timeout in a delayed job

I have some code that potentially can run for a longer period of time. However if it does I want to kill it, here is what I'm doing at the moment :
def perform
Timeout.timeout(ENV['JOB_TIMEOUT'].to_i, Exceptions::WorkerTimeout) { do_perform }
end
private
def do_perform
...some code...
end
Where JOB_TIMEOUT is an environment variable with value such as 10.seconds. I've got reports that this still doesn't prevent my job from running longer that it should.
Is there a better way to do this?
I believe delayed_job does some exception handling voodoo with multiple retries etc, not to mention that I think do_perform will return immediately and the job will continue as usual in another thread. I would imagine a better approach is doing flow control inside the worker
def perform
# A nil timeout will continue with no timeout, protect against unset ENV
timeout = (ENV['JOB_TIMEOUT'] || 10).to_i
do_stuff
begin
Timeout.timeout(timeout) { do_long_running_stuff }
rescue Timeout::Error
clean_up_after_self
notify_business_logic_of_failure
end
end
This will work. Added benefits are not coupling delayed_job so tightly with your business logic - this code can be ported to any other job queueing system unmodified.

Resolv::DNS - How to handle timeouts, errors

I'm using the following function in Ruby on Rails:
def isGoogleEmailAddress?(email_domain)
Resolv::DNS.open({:nameserver=>["8.8.8.8"]}) do |r|
mx = r.getresources(email_domain,Resolv::DNS::Resource::IN::MX)
if mx.any? {|server| server.exchange.to_s.downcase.include? "google"} then
return true
end
return false
end
end
Is there a way to handle the issue where Resolv fails, timeouts, errors etc?
Look through the documentation for the Resolv class and add exception handlers for the various errors/exceptions the class can raise.
They're easy to pick out. Look for classes ending in error and timeout.

Resources