incubator-couchdb-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Warren Gallagher <wgallag...@gridironsoftware.com>
Subject Re: FIFO/LIFO accountancy
Date Wed, 03 Feb 2010 18:30:50 GMT
I don't have a specific couchDB solution to offer, however, I have found a particular chapter
in "RESTful Web Services" by Leonard Richardson & Sam Ruby quite useful in thinking about
such problems.
In chapter 8,  "REST and ROA Best Practices" a way of modelling transactions as resources
is explained. Sometimes thinking about resource models leads to understanding underlying document
models that may be useful.

Warren Gallagher
wgallagher@gridironsoftware.com
Chief Technology Officer
GridIron Software



On 2010-02-03, at 1:13 PM, Andrew Melo wrote:

> On Wed, Feb 3, 2010 at 12:07 PM, Metin Akat <akat.metin@gmail.com> wrote:
>> Hmm, one solution I hadn't thought about at all.
>> Thanks, Chris. I'll think about it.
>> So far the only difference is that I would probably choose the leading
>> event to be the document of purchase.
>> Then in a situation of race condition usually there won't be the need
>> to "raise an exception". Instead the   "FIFO process" will continue
>> with the next "batch". An exception will be risen only if we are out
>> of apples, and then we will issue a "cancellation of purchase"
>> document, or even better, will put the purchase order on queue (in a
>> case it makes sense) and order new apples from our supplier.
>> Yeah, I'm starting to like such an approach. Thanks again.
> 
> What happens to the customer then? You've shown me a page saying
> "order complete" and then at some point down the line (whenever
> couchDB notices the probem or your state machine catches up on
> _changes), it realizes it can't fulfill the order. Even worse, all of
> the cheaper apples are actually gone, and all that's left are the more
> expensive ones.
> 
> I think your better bet would be to use something that was aware of
> atomic commits handle the inventory-ing, and then export that data
> couch to run map/reduce over, rather than hoping to enforce atomic
> semantics on what is an unatomic subsystem.
> 
> Best,
> Andrew
> 
> 
>> 
>> 
>> 
>> On Wed, Feb 3, 2010 at 7:27 PM, Chris Anderson <jchris@apache.org> wrote:
>>> On Wed, Feb 3, 2010 at 8:37 AM, Brian Candler <B.Candler@pobox.com> wrote:
>>>> On Wed, Feb 03, 2010 at 05:29:26PM +0200, Metin Akat wrote:
>>>>> So, we need some way to figure out which apples we sell first. (how
>>>>> much value to remove from the warehouse account). In order to do this
>>>>> we need to know how much have we sold till the moment. And this needs
>>>>> to be fault tolerant.
>>>>> For example, if somebody (at some other cash register in the store)
>>>>> sold 3 apples before our deal, our transactions would be quite a bit
>>>>> different. What if this happened one milisecond before we sell our
>>>>> apples?
>>>> 
>>>> It sounds to me like this is a locking problem. You have an inventory of
>>>> (5 apples @ $2), (5 apples @ $3) and you want to remove from these pools
>>>> atomically, *without any chance of going negative*
>>>> 
>>> 
>>> You can do a state machine approach where you have 1 update "pull the
>>> apples off the shelf" and another one for the cash register.
>>> 
>>> The register in this case would be an asynchronous background process.
>>> 
>>> If you have a crash between pulling the apples of the shelf and the
>>> cash register, but the register is driven by _changes, it'll just pick
>>> right up after a crash.
>>> 
>>> If you have a race condition and 2 users add the apples to their
>>> carts, whoever the cash register services first wins. The other user
>>> can get a "delayed shipping option" error message.
>>> 
>>>> So your first thought might be to keep your stock of apples as a single
>>>> document, and use couchdb's 'optimistic locking' to prevent two concurrent
>>>> changes:
>>>> 
>>>> {
>>>>  "id":"apples",
>>>>  "stock":{2.0=>5, 3.0=>5},  // cost price => quantity
>>>> }
>>>> 
>>>> That's fine (on a single couchdb node anyway). But then you want to record
>>>> the sale as another part of the same 'transaction', and post it to your
>>>> sales ledger and the customer's account receivable at the same time.  That
>>>> might work if the details of the sale were stored in the same document as
>>>> the apples (a view can pull them out). e.g.
>>>> 
>>>> {
>>>>  "id":"apples",
>>>>  "stock":{3.0=>4},
>>>>  "purchases":[
>>>>   {"supplier":888, "orderno":123, "line":1, "qty":5, "cost":10.0},
>>>>   {"supplier":888, "orderno":124, "line":1, "qty":5, "cost":15.0}
>>>>  ],
>>>>  "sales":[
>>>>  {"cust":1234, "orderno":9999, "line":1, "qty":6, "price":30.0, "cost":13.0}
>>>>  ]
>>>> }
>>>> 
>>>> But what if one customer decides to purchase apples and pears in the same
>>>> order?  In the event of a power loss, would it be acceptable for half of
the
>>>> order to be recorded?
>>>> 
>>>> I think it might. If the order is a separate doc, and the order ID is posted
>>>> against each line item as shown above, you can identify orders which haven't
>>>> been fully processed and hence complete the processing of them when the app
>>>> restarts.
>>>> 
>>>> This gives a very stock-centric view of your business processes. What if
>>>> your business takes apples out of the apples stock and manufactures it into
>>>> cartons of apple juice, which it then sells?
>>>> 
>>>> Maybe an RDBMS would be a better fit :-(
>>>> 
>>>> B.
>>>> 
>>> 
>>> 
>>> 
>>> --
>>> Chris Anderson
>>> http://jchrisa.net
>>> http://couch.io
>>> 
>> 
> 
> 
> 
> -- 
> --
> Andrew Melo


Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message