module JamRuby class QuickMixObserver < ActiveRecord::Observer # if you change the this class, tests really should accompany. having alot of logic in observers is really tricky, as we do here observe JamRuby::QuickMix def before_validation(quick_mix) # if we see that a part was just uploaded entirely, validate that we can find the part that was just uploaded if quick_mix.is_part_uploading_was && !quick_mix.is_part_uploading begin aws_part = quick_mix.s3_manager.multiple_upload_find_part(quick_mix[:ogg_url], quick_mix.upload_id, quick_mix.next_part_to_upload - 1) # calling size on a part that does not exist will throw an exception... that's what we want aws_part.size rescue SocketError => e raise # this should cause a 500 error, which is what we want. The client will retry later on 500. rescue Exception => e quick_mix.errors.add(:next_part_to_upload, ValidationMessages::PART_NOT_FOUND_IN_AWS) rescue RuntimeError => e quick_mix.errors.add(:next_part_to_upload, ValidationMessages::PART_NOT_FOUND_IN_AWS) rescue quick_mix.errors.add(:next_part_to_upload, ValidationMessages::PART_NOT_FOUND_IN_AWS) end end # if we detect that this just became fully uploaded -- if so, tell s3 to put the parts together if quick_mix.marking_complete && !quick_mix.fully_uploaded_was && quick_mix.fully_uploaded multipart_success = false begin quick_mix.s3_manager.multipart_upload_complete(quick_mix[:ogg_url], quick_mix.upload_id) multipart_success = true rescue SocketError => e raise # this should cause a 500 error, which is what we want. The client will retry later. rescue Exception => e #quick_mix.reload quick_mix.reset_upload quick_mix.errors.add(:upload_id, ValidationMessages::BAD_UPLOAD) end end end def after_commit(quick_mix) end # here we tick upload failure counts, or revert the state of the model, as needed def after_rollback(quick_mix) # if fully uploaded, don't increment failures if quick_mix.fully_uploaded return end # increment part failures if there is a part currently being uploaded if quick_mix.is_part_uploading_was #quick_mix.reload # we don't want anything else that the user set to get applied quick_mix.increment_part_failures(quick_mix.part_failures_was) if quick_mix.part_failures >= APP_CONFIG.max_track_part_upload_failures # save upload id before we abort this bad boy upload_id = quick_mix.upload_id begin quick_mix.s3_manager.multipart_upload_abort(quick_mix[:ogg_url], upload_id) rescue => e puts e.inspect end quick_mix.reset_upload if quick_mix.upload_failures >= APP_CONFIG.max_track_upload_failures # do anything? end end end end def before_save(quick_mix) # if we are on the 1st part, then we need to make sure we can save the upload_id if quick_mix.next_part_to_upload == 1 quick_mix.upload_id = quick_mix.s3_manager.multipart_upload_start(quick_mix[:ogg_url]) end end end end