Poll() in Ruby

poll() in Ruby?

Select cannot safely be used with programs that have more than 1024 file descriptors on a Linux system. This is because the underlying fd_set that the select system call uses is a fixed sized buffer i.e. its size is allocated at compile time, not run time.

From man 2 select:

int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);

An fd_set is a fixed size buffer. Executing FD_CLR() or
FD_SET() with a value of fd that is negative or is equal to or
larger than FD_SETSIZE will result in undefined behavior.
Moreover, POSIX requires fd to be a valid file descriptor.

This means that if you have more than 1024 file descriptors in your program, and you use the select system call, you will end up with memory corruption.

If you want to use more than 1024 file descriptors in your program, you must use poll or epoll, and ensure that you never use select, or you will get random memory corruption. Changing the size of the file descriptor table through ulimit is very dangerous if you are using select. Don't do it.

Ruby's select does seem to be actually implemented with the select system call, so while it may look like increasing ulimit works, under the hood corruption is happening:
https://github.com/ruby/ruby/blob/trunk/thread.c

Furthermore, some unrelated API's in ruby seem to use select (see thread_pthread.c) so it's probably also unsafe to use those, or any code that uses those API's within a ruby program running with a file descriptor table larger than 1024.

Rails 4: How to implement a frequent poll task (every 10 seconds)

Check out Resque, DelayedJob, or Sidekiq. You want to have a separate process doing background task management, so your Rails application is primarily concerned with handling web requests, and not with background work.

React-Rails API Polling

How about this approach?

@Records = React.createClass
getInitialState: ->
# `this.state.records` is empty now, but will be loaded by AJAX
{
records: []
}

componentDidMount: ->
# Ping every 2s
@_recordsInterval = setInterval =>
@_loadRecords()
, 2000
# Load initial data:
@_loadRecords()

componentWillUnmount: ->
# clean up loose ends:
clearInterval(@_recordsInterval)
@_recordsRequest?.abort()

# ...

_loadRecords: ->
# Fetch records from the server and store it as `this.state.records`
@_recordsRequest = $.get "/records", (data) =>
@setState(records: data)

Avoid polling in Rails

You need Action Cable. Action Cable seamlessly integrates WebSockets with the rest of your Rails application. It allows for real-time features to be written in Ruby in the same style and form as the rest of your Rails application, while still being performant and scalable. It's a full-stack offering that provides both a client-side JavaScript framework and a server-side Ruby framework. You have access to your full domain model written with Active Record or your ORM of choice.

Here is great example which shows usage of action cable

https://blog.heroku.com/real_time_rails_implementing_websockets_in_rails_5_with_action_cable

Hope it helps.

How to test polling an external api with Minitest?

Turns out, I was over thinking it and yields method was the solution:

test 'status is done' do
response = {
'type' => 'trackable_jobs',
'id' => '0b6ffad9177aeb594ad54af0',
'status' => 'done',
'errors' => nil
}

BaseApi.expects(:authenticate).with(1).yields
BaseApi::TrackableJob.stubs(:find).returns([response])

assert_equal(true, BaseApis::PollTrackableJobWorker.new.perform('xxx', 123))
end


Related Topics



Leave a reply



Submit