Database Reference
In-Depth Information
query = selector.merge(:state => opts[:from])
physical_item = @inventory.find_and_modify(:query => query,
:update => {'$set' => {:state => opts[:to], :ts => Time.now.utc}})
if physical_item.nil?
raise InventoryFetchFailure
end
items_transitioned << physical_item['_id']
@orders.update({:_id => order_id},
{"$push" => {:item_ids => physical_item['_id']}})
end
rescue Mongo::OperationFailure, InventoryFetchFailure
rollback(order_id, items_transitioned, opts[:from], opts[:to])
raise InventoryFetchFailure, "Failed to add #{selector[:sku]}"
end
items_transitioned.size
end
To t r a n s i t io n s t a t e , e a c h s e l e c t o r g e t s a n e xt r a c o n d i t i o n ,
{:state
=>
AVAILABLE}
, and
then the selector is passed to
findAndModify
which, if matched, sets a timestamp and
the item's new state. The method then saves the list of items transitioned and updates
the order with the
ID
of the item just added.
If the
findAndModify
command fails and returns
nil
, then you raise an
Inventory-
FetchFailure
exception. If the command fails because of networking errors, you res-
cue the inevitable
Mongo::OperationFailure
exception. In both cases, you rescue by
rolling back all the items transitioned thus far and then raise an
InventoryFetch-
Failure
, which includes the
SKU
of the item that couldn't be added. You can then res-
cue this exception on the application layer to fail gracefully for the user.
All that now remains is to examine the rollback code:
def rollback(order_id, item_ids, old_state, new_state)
@orders.update({"_id" => order_id},
{"$pullAll" => {:item_ids => item_ids}})
item_ids.each do |id|
@inventory.find_and_modify(
:query => {"_id" => id, :state => new_state},
:update => {"$set" => {:state => old_state, :ts => Time.now.utc}}
)
end
end
You use the
$pullAll
operator to remove all of the
ID
s just added to the order's
item_ids
array. You then iterate over the list of item
ID
s and transition each one back
to its old state.
The
transition_state
method can be used as the basis for other methods that
move items through their successive states. It wouldn't be difficult to integrate this
into the order transition system that you built in the previous subsection. But that
must be left as an exercise for the reader.