Безопасно ли использовать переменные экземпляра для хранения временных свойств объектов ActiveRecord? - PullRequest
2 голосов
/ 22 января 2012

Мне нужно сохранить значение состояния кодирования в видео, пока оно закодировано

У меня есть видеообъект.Во время кодирования видео оно должно блокировать редактирование своих комментариев.

Поэтому видео должно сохранять свое текущее состояние кодирования (происходит ли это да / нет?) И разрешать дочерним комментариям запрашивать это свойство.

Обратите внимание

Я знаю, что есть более эффективные способы решения этой конкретной проблемы.На самом деле мне нужно решить немного иную проблему, однако я чувствовал, что нюансы ее могут спутать с вопросом, поэтому я выбрал эту.Мой вопрос касается именно нюансов переменных isntance, а не того, как лучше решить эту проблему кодирования (которая, очевидно, нуждается в очереди).

class Video

  has_many :comments

  after_initialize do
    @encoding_in_process = false
  end

  def encode
    @encoding_in_process = true
    ...
    @encoding_in_process = false
  end

  def encoding_in_process? 
    @encoding_in_process
  end
end

class Comment
  belongs_to :video

  before_update
    raise "locked" if video.encoding_in_process?
  end

  ...
end

Как видите, каждый экземпляр видео хранитсяпеременная экземпляра @encoding_in_process, которая используется для определения возможности обновления комментария.

Проблема

Существует опасность, что в памяти будет несколько экземпляровиз того же видео каждое с разными значениями для @encoding_in_process.

например

bieber_video = Video.find_all_by_artist('Bieber').last
bieber_video.encode 
# assume this takes a while...
bieber_video.encoding_in_process?
# => true

bieber_copy = Video.find_by_id bieber_video.id
bieber_copy.encoding_in_process?
# => false


# Each ActiveRecord objects refer to the same Bieber video
bieber_copy.id == bieber_video.id
# => true

# ...however they refer to different objects in memory:
puts bieber_video
#<Video:0x00000105a9e948>
puts bieber_copy
#<Video:0x00000105a11111>

# and hence each instance has a different version of commenting_locked?
# bieber_video.encoding_in_process? != bieber_copy.encoding_in_process?

Вопрос

Даночто одна и та же строка базы данных может генерировать два разных экземпляра в памяти, каков безопасный способ хранения временной информации, не поддерживаемой базой данных, об этих экземплярах?

EDIT

Фактическая проблема, которую я пытаюсь решить, - это установка флага для объекта при инициализации destroy, чтобы его дочерние объекты могли определить, могут ли они быть уничтожены сами.

Поэтому это очень мгновенная проблема, и она не подходит для резервного копирования в базу данных.Я использовал этот видео-пример, потому что мне показалось, что он немного яснее, но, возможно, я просто замутил воду.

РЕШЕНИЕ (любезно предоставленный один из ответов ниже

Предложение @Alex D действительно решило проблему, но для большей ясности для тех, кто хочет повторить, действительный код был следующим:

class Video
  # set a class variable containing an array of all videos
  # which are currently being encoded
  @@ids_of_videos_being_encoded = []
  ...

  def encode
    store_encoding_state true
    begin
      encode()
    ensure
      # make sure we switch this off after 
      # encoding finishes or fails
      store_encoding_state false
    end
  end

  private  
    def store_encoding_state encoding_in_progress
      if encoding_in_progress
        @@ids_of_videos_being_encoded.push(id)
      else
        @@ids_of_videos_being_encoded.delete(id)
      end
    end

    def encoding_initiated?
      @@ids_of_videos_being_encoded.include? id
    end
end

Ответы [ 2 ]

1 голос
/ 22 января 2012

Ответ на ваш вопрос зависит от того, можете ли вы использовать несколько серверных процессов или нет.Если вы хотите запустить несколько серверных процессов (что является хорошим предположением), проблема заключается не только в нескольких объектах ActiveRecord в памяти, представляющих одну и ту же строку БД, но и в нескольких объектах в разных пространствах памяти .

Если у вас есть несколько процессов, которые каким-то образом совместно работают с одними и теми же данными, вы должны хранить эти данные в общем хранилище (то есть в базе данных), и вы должны сбрасывать изменения в хранилищеи обновите данные в памяти по мере необходимости.В этом случае вы не можете полагаться на то, что временные данные в памяти хранятся в синхронизации (потому что это невозможно).

Если вы постоянно записываете / читаете ваши переходные данные вБД звучит дорого, потому что это так.В целом, когда у вас есть несколько процессов (на одном и том же или разных серверах), работающих вместе, вы хотите спроектировать вещи так, чтобы каждый процесс мог собирать кусок данных и работать с ним некоторое время, не связываясь с другими.Мелкозернистый обмен данными в распределенной системе = плохая производительность.

Если вы уверены, что когда-либо будете использовать только один серверный процесс, и вы хотите смоделировать влияние переменных экземпляра, которые совместно используются несколькими ActiveRecordобъекты, представляющие одну и ту же строку БД, хранят данные в хэше, снабженные ключом идентификатором записи, и используют методы получения / установки, которые читают / записывают хэш.Если вы делаете много этого, вы можете сделать некоторую метапрограммирующую «магию», чтобы автоматически генерировать геттеры / сеттеры (как «attr_accessor»).Если вам нужна помощь в написании этого кода метапрограммирования, опубликуйте вопрос, и я на него отвечу.

1 голос
/ 22 января 2012

Поэтому видео должно сохранять свое текущее состояние кодирования (происходит ли оно да / нет?) И разрешать дочерним комментариям запрашивать это свойство.

IMO, это не очень хороший способсделать это из-за всех возникающих проблем с синхронизацией.

Гораздо лучшая стратегия - запускать все видео в состоянии unencoded, которое вы сохраняете вместе с метаданными видеозаписи.Когда поток видеоданных создан, поставьте задачу кодирования на усмотрение работника.Рабочий поток будет кодировать видео, и когда это будет сделано, он должен обновить состояние видео до encoded.

Теперь нет проблем с переходным состоянием;в следующий раз, когда кто-то попытается прокомментировать, когда кодирование закончено, это будет сделано.

Учитывая, что одна и та же строка базы данных может генерировать два разных экземпляра в памяти, что является безопасным способом хранениявременная информация об этих экземплярах без поддержки базы данных?

Если их не нужно синхронизировать, проблема не возникает.Если их do нужно синхронизировать, вы рискуете забегом.Вы также можете вызвать .reload, чтобы обновить состояние объекта из базы данных.

И если данные должны быть синхронизированы таким образом, то вам, вероятно, do необходимо их сохранить.В примере кодирования видео вы должны либо сохранить закодированное / незашифрованное состояние каждого видео, либо предоставить неявный, авторитетный способ узнать, закодировано видео или нет.


Обновление с исходного вопроса:

Фактическая проблема, которую я пытаюсь решить, - это установить флаг для объекта, когда уничтожение инициировано, так, чтобы его дочерние объекты могли определить, имеют ли они право на уничтожениесами.

Просто используйте after_destroy callback , чтобы вызвать соответствующий метод для каждого дочернего объекта и позволить им определить, должны ли они быть уничтожены илине.Это будет выглядеть примерно так:

class Video < ActiveRecord::Base
  after_destroy :purge_pending_comments!

  def purge_pending_comments!
    comments.map &:destroy_if_pending
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...