加载 Ruby on Rails 模型而不加载整个框架
我正在创建一个自定义守护程序,它将运行各种数据库任务,例如延迟邮件和用户通知(每个通知都是通知表中的单独行)。我不想使用 script/runner 或 rake 来执行这些任务,因为某些任务可能只需要创建一两个数据库行或数千行取决于任务。我不想要为每个操作启动 ruby 进程或加载整个 Rails 框架的开销。我计划将这个守护进程全部保留在内存中。
为了创建这个守护进程,我想使用 ruby on Rails 应用程序中的模型。我有许多 Rails 插件,例如 acts_as_tree
和 AASM
,如果我在哪里使用模型,我需要加载它们。我需要加载的一些插件是我创建的 ActiveRecord::Base 上的自定义 hack。 (如果某些插件需要来自 Rails 其他部分的组件,我愿意接受删除或重新编码。)
我的问题是
- 这是一个好主意吗?
- 并且 - 这是否可以通过不需要我手动将每个文件包含在我的模型和插件中的方式来实现?
如果这不是一个好主意
- ,那么什么是好的替代方案?
(我不反对编写自己的 SQL 查询,但我必须为守护进程添加数据库约束和单独的用户,以防止任何愚蠢的事故。鉴于我对配置数据库不熟悉,我想使用活动记录作为拐杖。)
I'm looking to create a custom daemon that will run various database tasks such as delaying mailings and user notifications (each notice is a separate row in the notifications table). I don't want to use script/runner
or rake
to do these tasks because it is possible that some of the tasks only require the create of one or two database rows or thousands of rows depending on the task. I don't want the overhead of launching a ruby process or loading the entire rails framework for each operation. I plan to keep this daemon in memory full time.
To create this daemon I would like to use my models from my ruby on rails application. I have a number of rails plugins such as acts_as_tree
and AASM
that I will need loaded if I where to use the models. Some of the plugins I need to load are custom hacks on ActiveRecord::Base that I've created. (I am willing to accept removing or recoding some of the plugins if they need components from other parts of rails.)
My questions are
- Is this a good idea?
- And - Is this possible to do in a way that doesn't have me manually including each file in my models and plugins?
If not a good idea
- What is a good alternative?
(I am not apposed to doing writing my own SQL queries but I would have to add database constraints and a separate user for the daemon to prevent any stupid accidents. Given my lack of familiarity with configuring a database, I would like to use active record as a crutch.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
听起来您担心的是您不想在每次需要运行任务时花费时间或内存成本来启动 Rails 堆栈?如果您计划让守护进程保持全职运行,正如您所说,您可以只对已加载 Rails 堆栈的进程进行守护进程,并且只需为加载堆栈一次而支付与内存或时间相关的惩罚,当守护进程启动。
Async_worker 是这种模式的一个很好的例子:它使用 beanstalk 将消息传递给一个或多个更多工作进程,每个进程只是加载了完整 Rails 堆栈的守护进程。
执行此操作时必须注意的一件事是,您需要在部署时重新启动守护进程,以便它们可以重新加载更新的 Rails 堆栈。我将其用于 url-shortener 应用程序(我运行的单个异步工作进程在访问者重定向后等待保存推荐数据),并且效果很好,我只有一个
after:deploy< /code> 重新启动任何异步工作线程的 capistrano 任务。
It sounds like your concern is that you don't want to pay the time- or memory- cost to spin up the rails stack every time your task needs to be run? If you plan on keeping the daemon running full-time, as you say, you can just daemonize a process that has loaded your rails stack and will only have to pay that memory- or time-related penalty for loading the stack one time, when the daemon starts up.
Async_worker is a good example of this sort of pattern: It uses beanstalk to pass messages to one or more worker processes that are each just daemons that have loaded the full rails stack.
One thing you have to pay attention to when doing this is that you'll need to restart your daemonized processes upon a deploy so they can reload your updated rails stack. I'm using this for a url-shortener app (the single async worker process I have running sits around waiting to save referral data after the visitor gets redirected), and it works well, I just have an
after:deploy
capistrano task that restarts any async worker(s).您可以加载 Rails 的某一方面,例如 ActiveRecord,但是当您认真对待它时,加载整个环境的成本并不比加载 ActiveRecord 本身高多少。您当然可以不包括 ActionMailer 或其他一些方面,但我猜您不会从中看到太多好处。
我建议要么像你说的那样通过运行器/控制台运行,但不要每次都进行引导,而是尝试批处理,以便一次执行 1000 个而不是 1 个。有很多在使用这种风格的项目中,如果您想要示例,您会想到一些批量邮件程序。 DJ (delayed_job) 也做了类似的事情,它在数据库中存储了一些信息,表示该代码需要在将来的某个时刻使用环境堆栈运行,但它会尝试尽可能多地进行批处理,这样您就可以从中获胜。
另一种选择是拥有一个持久的迷你轨道应用程序,尽可能多地剥离,以便内存使用率更低,它可以侦听请求并在您需要时执行您的命令。这将需要更多内存,但引导的延迟基本上会被消除。
最后,作为事后的想法,这对 Postgres 来说是一个很大的用途。
You can load up one aspect of Rails such as ActiveRecord but when you get right down to it the cost of loading the entire environment is not much more than just loading ActiveRecord itself. You could certainly just not include aspects like ActionMailer or some of the side bits but I'm going to guess that you're not going to see much win out of it.
What I would suggest instead is either running through runner/console like you said you didn't want to but rather than bootstrapping each time, try to batch things so that you're doing 1000 at a time instead of 1. There are a lot of projects that use this style, some of the bulk mailers spring to mind if you want examples. DJ (delayed_job) does similar by storing a bit in the database saying that this code needs to be run at some point in the future using the environment stack but it tries to batch together as much as it can so you may get win from that.
The other option is to have a persistent mini-rails app with as much stripped out as possible so that the memory usage is lower which can listen for requests and do your bidding when you want it to. This would be more memory but the latency of bootstrapping would be essentially nullified.
Lastly, as an afterthought, this would be a great use for Postgres.