Rails 最佳实践:后台进程/线程?

发布于 2024-11-05 10:01:49 字数 1089 浏览 0 评论 0原文

我来自 PHP 环境(至少在 Web 开发方面)并进入了 Ruby 的美丽世界,所以我可能有一些愚蠢的问题。我想,当不使用 PHP 时,有一些根本不同的选项可用。

在 PHP 中,我们使用 memcache 来存储要在页面顶部的栏中显示的警报。当发生生成警报的事件(例如发布新的博客文章)时,每 5 分钟左右运行一次的 cron 脚本会将该信息放入内存缓存中。

现在,当用户访问该网站时,我们会在内存缓存中查找所有尚未消除的警报并显示它们。

我猜想我可以在 Rails 中做不同的事情,就是绕过 cron 脚本的需要,以及在每个请求上查看 memcache 的需要,通过使用 Singleton 和在单独线程中运行的轮询进程来从内存缓存复制到此单例。从理论上讲,这比每次请求检查一次 memcache 更优化,并且还将轮询逻辑封装到一个地方,而不是在 cron 任务和查找逻辑之间拆分。

我的问题是:Rails 应用程序运行时在后台运行某种运行循环是否有任何警告?我了解 Objective-C/Java 中多线程的含义,但我具体询问的是 Rails (3) 环境。

基本上是这样的:

class SiteAlertsMap < Hash
  include Singleton

  def initialize
    super
    begin_polling
  end

  # ... SNIP, any specific methods etc ...

  private

    def begin_polling
      # Create some other Thread here, which polls at set intervals
    end
end

这让我想到了一个类似的问题。我们将(加密的)任务推送到 SQS 队列上,用于与电子商务相关的任务和长时间运行的后台任务。为此,我们不使用 cron,而是有一个用 PHP 编写的工作守护进程,它在后台运行。现在,当我们部署时,我们必须关闭该工作程序并从新的代码库重新启动它。在 Rails 中,我可以通过 Rails 服务器(独角兽)本身来启动和停止这个过程吗?我不认为这是我在单独线程中的主进程上运行的东西,因为我们经常希望将它作为一个进程单独控制,但如果它能在 Web 应用程序运行时方便地运行,那就太好了。

I'm coming from a PHP environment (at least in terms of web dev) and into the beautiful world of Ruby, so I may have some dumb questions. I imagine there are some fundamentally different options available when not using PHP.

In PHP, we use memcache to store alerts we want to display in a bar along the top of the page. When something happens that generates an alert (such as a new blog post being made), a cron script that runs once every 5 minutes or so puts that information into memcache.

Now when a user visits the site, we look in memcache to find any alerts that they haven't already dismissed and we display them.

What I'm guessing I can do differently in Rails, is to by-pass the need for a cron script, and also the need to look in memcache on every request, by using a Singleton and a polling process running in a separate thread to copy from memcache to this singleton. This would, in theory, be more optimized than checking memcache once-per-request and also encapsulate the polling logic into one place, rather than being split between a cron task and the lookup logic.

My question is: are there any caveats to having some sort of runloop in the background while a Rails app is running? I understand the implications of multithreading, from Objective-C/Java, but I'm asking specifically about the Rails (3) environment.

Basically something like:

class SiteAlertsMap < Hash
  include Singleton

  def initialize
    super
    begin_polling
  end

  # ... SNIP, any specific methods etc ...

  private

    def begin_polling
      # Create some other Thread here, which polls at set intervals
    end
end

This leads me into a similar question. We push (encrypted) tasks onto an SQS queue, for things related to e-commerce and for long-running background tasks. We don't use cron for this, but rather we have a worker daemon written in PHP, which runs in the background. Right now when we deploy, we have to shut down this worker and start it again from the new code-base. In Rails, could I somehow have this process start and stop with the rails server (unicorn) itself? I don't think that's something I'd running on the main process in a separate thread, since we often want to control it as a process by itself, but it would be nice if it just conveniently ran when the web application was running.

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

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

发布评论

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

评论(1

好听的两个字的网名 2024-11-12 10:01:49

ruby 中的后台进程线程化将是一个可怕的错误,特别是因为您使用的是多进程服务器。使用带有 4 个工作进程的 unicorn 意味着您将从每个进程进行轮询,这不是您想要的。 Ruby 并没有真正的线程,它在 1.8 中具有绿色线程,在 1.9 IIRC 中具有全局解释器锁。许多 gem 和库也是令人讨厌的非线程安全的。

使用 memcache 仍然是您的最佳选择,如果您正确设置它,您应该只会看到它使请求时间增加一两毫秒。另一种选择是将这些警报存储在 Redis 中,这种选择可以让您在保留这些警报的同时产生最小的额外开销。这可以更好地保护您免受内存缓存崩溃或服务器重新启动等问题的影响。

对于后台作业,您应该使用与现在类似的方法,但是有几个现成的处理程序可以用于此操作,例如 resquedelayed_job 以及其他一些。如果您绝对必须使用SQS作为后端队列,您也许可以找到一些代码来帮助您,但否则您可以自己编写。每当代码发生更改时,这仍然需要重新启动其他守护程序。实际上,这并不是一个大问题,因为最佳实践要求使用像 capistrano 这样的部署系统,可以轻松添加规则以在部署时反弹守护进程。我使用 monit 来监视守护进程,因此重新启动它就像告诉 monit 重新启动它一样简单。

一般来说,Ruby 在线程方面与 Java/Objective-C 不同。它遵循更类似于 Unix 的基于进程的隔离模型,但社区已经提出了最佳实践和方法,使这一过程比其他语言更轻松。 Ruby 确实需要更多地关注设置其堆栈,因为它并不像启用 mod_php 并复制一些文件那么简单,但是一旦理解了选择和架构,就更容易推断出如何进行你的应用程序有效。在我看来,流程模型对于 Web 应用程序来说要好得多,因为它将代码和状态与其他正在运行的操作的影响隔离开来。这种隔离还使应用程序更容易在分布式系统中使用。

Threading for background processes in ruby would be a terrible mistake, especially since you're using a multi-process server. Using unicorn with say 4 worker processes would mean that you'd be polling from each of them, which is not what you want. Ruby doesn't really have real threads, it has green threads in 1.8 and a global interpreter lock in 1.9 IIRC. Many gems and libraries are also obnoxiously unthreadsafe.

Using memcache is still your best option and, if you have it set up correctly, you should only see it adding a millisecond or two to the request time. Another option which would give you the benefit of persisting these alerts while incurring minimal additional overhead would be to store these alerts in redis. This would better protect you against things like memcache crashing or server reboots.

For the background jobs you should use a similar approach to what you have now, but there are several off the shelf handlers for this like resque, delayed_job, and a few others. If you absolutely have to use SQS as the backend queue, you might be able to find some code to help you, but otherwise you could write it yourself. This still requires the other daemon to be rebooted whenever there is a code change. In practice this isn't a huge concern as best practices dictate using a deployment system like capistrano where a rule can easily be added to bounce the daemon on deploy. I use monit to watch the daemon process, so restarting it is as easy as telling monit to restart it.

In general, Ruby is not like Java/Objective-C when it comes to threads. It follows the more Unix-like model of process based isolation, but the community has come up with best practices and ways to make this less painful than in other languages. Ruby does require a bit more attention to setting up its stack as it is not as simple as enabling mod_php and copying some files around, but once the choices and architecture is understood, it is easier to reason about how your application works. The process model, in my opinion, is much better for web apps as it isolates code and state from the effects of other running operations. The isolation also makes the app easier to work with in a distributed system.

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