Ruby 使用Rails应用程序覆盖应用程序依赖的文件时的最佳做法

Ruby 使用Rails应用程序覆盖应用程序依赖的文件时的最佳做法,ruby,ruby-on-rails-3,Ruby,Ruby On Rails 3,我有一个Rails应用程序,每次执行搜索时都会读取.yml文件。(这是一个全文搜索应用程序。).yml文件告诉应用程序它应该向哪个url发出搜索请求,因为不同版本的搜索索引驻留在不同的服务器上,我偶尔会在索引之间切换 我有一个应用程序的管理部分,允许我重写前面提到的.yml文件,以便我可以添加新的搜索URL或删除不需要的URL。虽然我可以在服务器上手动编辑该文件,但我更希望能够在我的站点管理部分对其进行编辑,这样当我无法访问服务器时,我仍然可以进行任何必要的更改 对我的应用程序实际使用的文件进行

我有一个Rails应用程序,每次执行搜索时都会读取.yml文件。(这是一个全文搜索应用程序。).yml文件告诉应用程序它应该向哪个url发出搜索请求,因为不同版本的搜索索引驻留在不同的服务器上,我偶尔会在索引之间切换

我有一个应用程序的管理部分,允许我重写前面提到的.yml文件,以便我可以添加新的搜索URL或删除不需要的URL。虽然我可以在服务器上手动编辑该文件,但我更希望能够在我的站点管理部分对其进行编辑,这样当我无法访问服务器时,我仍然可以进行任何必要的更改

对我的应用程序实际使用的文件进行编辑的最佳做法是什么?(我想这也适用于,比方说,一个能够重写自己的助手文件(部署后)的应用程序。)

当另一个连接到我的站点的用户想要执行搜索时,我可能正在重写此文件,这是一个问题吗?如果我在写操作的中间,他们的搜索会失败吗?我应该先将新的.yml文件写入临时文件,然后再替换原来的.yml文件吗?我知道写操作非常快,但我只是想看看别人怎么想


更新:谢谢大家的回复!虽然我认为最好使用某种缓存,而不是在每次请求时读取文件,但这有助于找出真正执行文件重写的最佳方式,因为我特别希望在这种特定情况下每次都重新读取文件。

如果您真的想通过重写文件来执行此操作,在编写配置文件时,使用文件系统的锁定功能阻止其他线程访问配置文件。也许看看类似的东西

不过,我强烈建议不要在不重新部署应用程序的情况下使用需要更改的配置文件。首先,您现在要求每次有人进行搜索时都读取一个文件。其次,出于安全原因,允许web应用程序对自己的代码进行写访问通常是个坏主意。我会将这些搜索索引URL存储在数据库或memcached键中


编辑:正如@bioneuralnet所指出的,决定是需要实时配置更新还是最终同步是很重要的。

如果您真的想通过覆盖文件来实现这一点,请使用文件系统的锁定功能,在写入配置文件时阻止其他线程访问配置文件。也许看看类似的东西

不过,我强烈建议不要在不重新部署应用程序的情况下使用需要更改的配置文件。首先,您现在要求每次有人进行搜索时都读取一个文件。其次,出于安全原因,允许web应用程序对自己的代码进行写访问通常是个坏主意。我会将这些搜索索引URL存储在数据库或memcached键中


编辑:正如@bioneuralnet指出的,决定是否需要实时配置更新或只是最终同步是很重要的。

首先,我要说的是,在每次请求时读取该文件是性能杀手。别这样!如果确实需要将该数据保存在.yml文件中,则需要缓存该数据并仅在其更改后重新加载(基于文件的时间戳)


但是不要在每个请求上都检查时间戳——这几乎同样糟糕。如果自上次检查已过n分钟,请在请求中检查它。可能在过滤器之前的某个地方。如果您是在线程模式下运行的(大多数人不是这样),请小心使用互斥锁或其他东西。

首先,让我说,在每次请求时读取该文件是性能杀手。别这样!如果确实需要将该数据保存在.yml文件中,则需要缓存该数据并仅在其更改后重新加载(基于文件的时间戳)


但是不要在每个请求上都检查时间戳——这几乎同样糟糕。如果自上次检查已过n分钟,请在请求中检查它。可能在过滤器之前的某个地方。如果您在线程模式下运行(大多数人不是这样),请注意使用互斥锁或其他东西。

如果必须为此使用文件,则安全过程如下所示:

begin
  # Write your new stuff to /some/path/f.yml.tmp here
  File.rename('/some/path/f.yml.tmp', '/some/path/f.yml')
rescue SystemCallError => e
  # Log an error, complain loudly, fall over and cry, ...
end
  • 将新内容写入某种临时文件
  • 用于以原子方式将旧文件替换为新文件
  • 如果不使用单独的文件,当不可避免的问题发生时,很容易会得到一个写了一半的坏文件。
    File.rename
    类方法只是系统调用的包装器,它保证是原子的(即,它要么完全成功,要么完全失败,不会让您处于不一致的中间状态)

    如果您想替换
    /some/path/f.yml
    ,您可以执行以下操作:

    begin
      # Write your new stuff to /some/path/f.yml.tmp here
      File.rename('/some/path/f.yml.tmp', '/some/path/f.yml')
    rescue SystemCallError => e
      # Log an error, complain loudly, fall over and cry, ...
    end
    
    正如其他人所说,文件并不是处理此问题的最佳方式,如果您有多台服务器,当服务器不同步时,使用文件将失败。您最好使用多个服务器可以访问的数据库,然后您可以:

  • 在每个web服务器进程中缓存该值
  • 盲目地每10分钟刷新一次(或者任何有效的方法)
  • 如果连接到远程服务器失败,请刷新缓存值(进行额外的错误检查以避免刷新/连接/失败循环)

  • 如果必须为此使用文件,则安全过程如下所示:

    begin
      # Write your new stuff to /some/path/f.yml.tmp here
      File.rename('/some/path/f.yml.tmp', '/some/path/f.yml')
    rescue SystemCallError => e
      # Log an error, complain loudly, fall over and cry, ...
    end
    
  • 将新内容写入某种临时文件
  • 用于以原子方式将旧文件替换为新文件
  • 如果不使用单独的文件,当不可避免的问题发生时,很容易会得到一个写了一半的坏文件。
    File.rename
    class方法只是一个包装器