Revised code looks like this now. Weirdly (at least, it seems weird to me), I
had to put has_one on the App, and belongs_to on both the App and the
Disposition models.
Locking-wise, I''m worried about this tiny instant right here, across
these three
statements:
disp.app = stream_app
stream_app.disposition = disp
stream_app.save!
We assign an App record to the Disposition we''ve just created.. We do
the
converse for the App record, so that they reference each other, and then we save
both. Is the oplock code safe enough to guarantee that another process grabbing
the app with the App.find statement won''t be allowed to save it?
Thanks,
--Wilson.
# Current code:
# App model
has_one :disposition, :dependent => true
belongs_to :disposition
# ..and numerous others
# Disposition model
belongs_to :app
validates_presence_of :status_code
validates_presence_of :app_id
validates_uniqueness_of :app_id
# Controller code
def stream
disp = Disposition.new
stream_app = App.find(:first, :conditions => "status_code =
''A'' and
disposition_id is null")
if stream_app.nil? then
render(:text => "STOP")
return
end
App.transaction(stream_app, disp) do
disp.status_code = ''S'' # For
''Streaming''
disp.app = stream_app
stream_app.disposition = disp
begin
stream_app.save!
rescue ActiveRecord::StaleObjectError
puts "internal/stream: Our worst nightmare has been
realized."
render(:text => "STOP")
return
end
end # transaction
render(:text => "#{disp.app_id}")
end # stream
Wilson wrote:> So, I have the following relationship between ''App'' and
the disposition
> of said app. The "apps" table has a DISPOSITION_ID column, and
the
> "dispositions" table has an APP_ID column. It seems to me that
each
> model should have a "has_one" relationship to the other, but when
I do
> that, it starts looking for a disposition_id column in the dispositions
> table. Still working on that quirk.. but luckily, it doesn''t
really
> matter for the question I''m going to pose here..
>
> class App < ActiveRecord::Base
> belongs_to :disposition
> # snip a jillion lines of stuff here
> end
>
> class Disposition < ActiveRecord::Base
> has_one :app
> validates_presence_of :status_code
> validates_uniqueness_of :app_id
> end
>
> Both the "apps" and "dispositions" tables use the
lock_version magic
> column.
>
> This application interfaces to a legacy mainframe back-end via
> distributed "streaming tools" written in VB6. The app needs to
> implement a poor-man''s message queue by returning an
"apps.id" column
> value when the VB6 tools hit an action URL. When there are no more apps
> to process, the page should contain the string "STOP".
>
> However, since there will be up to 80 or 100 of these things hitting the
> server once every 30 to 60 seconds, I''m extremely paranoid about
> locking. Having two requests ever return the same "app id"
number would
> be catastrophic, and would lead to public humiliation and/or extra work
> for everybody.
>
> Here''s the rough draft I have so far:
>
> def stream
> disp = Disposition.new
> stream_app = App.find(:first,
> :conditions => "status_code = ''A'' and
disposition_id is null")
>
> App.transaction(stream_app, disp) do
> disp.status_code = ''S'' # For
''Streaming''
> stream_app.disposition = disp
> begin
> disp.save!
> rescue ActiveRecord::StaleObjectError
> puts "stream: Our worst nightmare has been realized."
> render(:text => "STOP")
> return
> end
> end # transaction
> render(:text => "#{disp.app.id}")
> end # stream
>
> Am I on the right track? Is there a better way to do this? Is there a
> cool message-queueing system for Ruby out there?
>
> Thanks,
> --Wilson.