如何在“内部”生成一个 EventMachine? Rails 应用程序?

发布于 2024-11-03 16:31:45 字数 461 浏览 1 评论 0原文

我有一个 Rails 应用程序,并且希望为其添加某种 WebSocket 支持。从各种谷歌搜索来看,最好的基于 Ruby 的 WebSocket 解决方案似乎是在 EventMachine 上运行的 em-websocket

我想知道是否有一种方法可以将 EventMachine 反应器“集成”到 Rails 中?初始化代码放在哪里?这是实现这一目标的正确方法吗?

我见过 this 示例,它依靠 Sinatra 来执行 EventMachine GET request,但这并不完全是我想要的。

任何帮助表示赞赏。

I've got a Rails application, and am looking to add some sort of WebSocket support to it. From various googling, it appears that the best Ruby based WebSocket solution is em-websocket running on EventMachine.

I was wondering if there was a way to "integrate" an EventMachine reactor into Rails? Where do I put the initialization code? Is this the proper way to accomplish this?

I've seen this example that falls back on Sinatra to do an EventMachine GET request, but that isn't quite what I'm looking for.

Any help is appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

揪着可爱 2024-11-10 16:31:45

您无法在 Rails 本身内部运行 Eventmachine 引擎,因为它是一个持久运行循环,会永久阻塞您的 Rails 进程之一。通常所做的是有一个使用 Eventmachine 的副进程,Rails 通过套接字与其通信以发送通知。

Juggernaut 就是这种情况的一个例子,它实现了一个 Websocket 客户端和一个 Rails 钩子来向其发送通知它。此后,该项目已弃用 Ruby 版本,转而使用 JavaScript Node.js 版本,但这仍然是如何使用 Eventmachine 的一个非常全面的示例。

You cannot run the Eventmachine engine inside of Rails itself as it is a persistent run loop that would block one of your Rails processes permanently. What is usually done is there's a side-process that uses Eventmachine and Rails communicates with it through sockets to send notifications.

Juggernaut serves as an example of this kind of thing where it implements a Websocket client and a Rails hook to send notifications to it. The project has since deprecated the Ruby version in favor of a JavaScript Node.js version but this still serves as a very thorough example of how Eventmachine can be used.

带刺的爱情 2024-11-10 16:31:45

如果您在瘦服务器中运行 Rails 应用程序(bundle exec Thin Start),瘦服务器会为您运行 EventMachine,然后您的 Rails 应用程序可以在您需要的任何地方执行 EM 代码。

例如:

具有该代码的库初始化程序:

EM.next_tick do
  EM.add_periodic_timer(20) do
    puts 'from Event Machine in rails code'
  end
end

不会阻止 Rails 进程应用程序。

If you run rails application in a thin server (bundle exec thin start) thin server run EventMachine for you and then your rails application can execute EM code wherever you need.

By example:

A library o initializer with that code:

EM.next_tick do
  EM.add_periodic_timer(20) do
    puts 'from Event Machine in rails code'
  end
end

not blocks rails processes application.

您的好友蓝忘机已上羡 2024-11-10 16:31:45

不知道这是否是你所追求的。但是如果您想提供某种套接字消息系统。

看看 Faye。它为 Node.js 和 Rack 提供消息服务器。 Ryan Bates 还为此提供了 railscast ,这应该可以简化实现。

希望有帮助。

Don't know if this is what you are after. But if you would like to do provide some kind of socket-messaging system.

Have a look at Faye. It provides message servers for Node.js and Rack. There is also a rails cast for this by Ryan Bates which should simplify the implementation.

Hope that helps.

烟花易冷人易散 2024-11-10 16:31:45

我花了相当多的时间来研究这个问题。 EventMachine 需要在 Rails 安装中作为线程运行(除非您使用 Thin),并且对于 Passenger 有一些特殊的注意事项。我在这里编写了我们的实现:http://www.hiringthing。 com/2011/11/04/eventmachine-with-rails.html

更新

我们将此配置提取到名为 Momentarily 的 gem 中。来源在这里 https://github.com/eatenbyagrue/momentarily

I spent a considerable amount of time looking into this. EventMachine need to run as a thread in your rails install (unless you are using Thin,) and there are some special considerations for Passenger. I wrote our implementation up here: http://www.hiringthing.com/2011/11/04/eventmachine-with-rails.html

UPDATE

We pulled this configuration out into a gem called Momentarily. Source is here https://github.com/eatenbyagrue/momentarily

豆芽 2024-11-10 16:31:45

我尝试使用 em-synchrony 在光纤中启动反应器。在 Rails 应用程序中,您可能可以在初始化程序中启动它,因为听起来您只想让反应器运行以响应 Websocket 请求。正如其他答案所建议的,我认为您想要与您的反应器建立套接字通信,或者使用异步客户端之一来连接您的反应器和 Rails 代码都可以读取和写入以交换数据的数据存储。

我的一些同事整理了一些在 ruby​​ 代码中按需启动 EM 反应器的示例,以便在 EventMachine 中运行测试。我会尝试用它作为一个可能的例子; 使用 eventmachine 进行抓取和测试

I'd try using em-synchrony to start a reactor in a fiber. In a rails app you can probably start it in an initializer since it sounds like you just want to leave the reactor running to respond to websocket requests. As suggested by the other answers I think you want to either setup socket communication with your reactor or use one of the asynchronous clients to a data store which both your reactor and rails code can read from and write to to exchange data.

Some of my coworkers put together some examples of starting EM reactors on demand in ruby code to run their tests within EventMachine. I'd try using that as a possible example; raking and testing with eventmachine

浅浅淡淡 2024-11-10 16:31:45

我会考虑研究抽筋。它是一个构建在 EventMachine 之上的异步框架,并且支持瘦服务器:

机架中间件支持+彩虹!和瘦网络服务器

I'd consider looking into Cramp. It's an async framework built on top of EventMachine, and it supports Thin server:

Rack Middlewares support + Rainbows! and Thin web servers

不可一世的女人 2024-11-10 16:31:45

如果你可以帮助的话,你可能不应该再使用 EM,它似乎不再被维护 - 如果你遇到错误 - 你就得靠自己了。

上面的大多数答案在 JRuby 中不起作用,因为 https://github.com/eventmachine /eventmachine/issues/479 - 即 EM::Synchrony 使用的模式

Thread.new{ EM.run }

以及在互联网上找到的各种答案(例如 EventMachine 和 Ruby 线程 - 这里到底发生了什么?)在 JRuby eventmachine 实现下被破坏了(纤程是 jruby 中的线程,目前没有关于何时改变的路线图)。

JRuby 消息传递选项将

  1. 与 TorqueBox(与 HornetQ 捆绑在一起)一起部署,http://torquebox.org/news/2011/08/15/websockets-stomp-and-torquebox/,令人印象深刻且富有进取心,但并不真正优雅,除非您有 Java 背景
  2. 较新版本的 Faye 应该可以与 JRuby 配合使用,Faye in jruby on Rails
  3. 注意未来,请关注赛璐珞社区,一些有趣的分布式解决方案来自那里https://github.com/celluloid/reel/wiki/WebSockets, https://github.com/celluloid/dcell

You probably shouldn't use EM any more if you can help it, it seems to no longer be maintained - if you encounter a bug - you're on your own.

Most of the answers above don't work in JRuby due to https://github.com/eventmachine/eventmachine/issues/479 - namely the pattern:

Thread.new{ EM.run }

used by EM::Synchrony and various answers found around the internet (such as EventMachine and Ruby Threads - what's really going on here?) are broken under JRuby eventmachine implementation (fibers are threads in jruby and there's currently no roadmap on when this will change).

JRuby messaging options would be

  1. deploy with TorqueBox (which comes bundled with HornetQ), http://torquebox.org/news/2011/08/15/websockets-stomp-and-torquebox/, impressive and enterprisey but not really elegant unless you're coming from a Java background
  2. newer versions of Faye should work with JRuby, Faye in jruby on rails
  3. note for the future, keep an eye on the celluloid community, some interesting distributed solutions are coming from there https://github.com/celluloid/reel/wiki/WebSockets, https://github.com/celluloid/dcell
  4. ?
孤寂小茶 2024-11-10 16:31:45

我有同样的问题并找到了解决方案。首先,将代码放入 lib 目录(例如 /lib/listener/init.rb)并创建一个运行 EM 的类方法,例如 Listener。运行

#!/usr/bin/env ruby

require File.expand_path('../../config/environment', File.dirname(__FILE__))

class Listener
  def self.run
  # your code here
  # you can access your models too
  end
end

之后我使用了 dante gem。创建 /init/listener 文件。代码可能是这样的:

#!/usr/bin/env ruby

require File.expand_path('../../lib/listener/init.rb', __FILE__)

log_file = File.expand_path('../../log/listener.stdout.log', __FILE__)
pid_file = File.expand_path('../../tmp/listener.pid', __FILE__)

listener = Dante::Runner.new('listener')

if ARGV[0] === 'start'
  listener.execute(daemonize: true,
                   pid_path: pid_file,
                   log_path: log_file) { Listener.run }
elsif ARGV[0] === 'restart'
  listener.execute(daemonize: true,
                   restart: true,
                   pid_path: pid_file,
                   log_path: log_file) { Listener.run }
elsif ARGV[0] === 'stop'
  listener.execute(kill: true, pid_path: pid_file)
end

现在您可以运行这样的代码: ./bin/listener start, ./bin/listener restart, ./bin /listener stop

您可以使用 god 来监控监听器的运行情况。但请确保您使用相同的 pid 文件 (/tmp/listener.pid)。

I had same problem and found solution. First, put your code in lib dir (for example /lib/listener/init.rb) and create one class method that run EM, for example Listener.run.

#!/usr/bin/env ruby

require File.expand_path('../../config/environment', File.dirname(__FILE__))

class Listener
  def self.run
  # your code here
  # you can access your models too
  end
end

After that I used dante gem. Create /init/listener file. The code may be like that:

#!/usr/bin/env ruby

require File.expand_path('../../lib/listener/init.rb', __FILE__)

log_file = File.expand_path('../../log/listener.stdout.log', __FILE__)
pid_file = File.expand_path('../../tmp/listener.pid', __FILE__)

listener = Dante::Runner.new('listener')

if ARGV[0] === 'start'
  listener.execute(daemonize: true,
                   pid_path: pid_file,
                   log_path: log_file) { Listener.run }
elsif ARGV[0] === 'restart'
  listener.execute(daemonize: true,
                   restart: true,
                   pid_path: pid_file,
                   log_path: log_file) { Listener.run }
elsif ARGV[0] === 'stop'
  listener.execute(kill: true, pid_path: pid_file)
end

Now you can run you code like that: ./bin/listener start, ./bin/listener restart, ./bin/listener stop

You can use god for monitoring your listener is running. But make sure you're using same pid file (/tmp/listener.pid).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文