Hey all,
Bob did a pretty good job explaining how the changes feed works most
of the time but I did want to call attention to an error condition
that might be of concern to the original question. There is a
situation where you can see old changes in the response depending on
some timing and error conditions.
For a bit of background on the since parameter, when we are looking at
a clustered since sequence like such:
35-g1AAAAG1eJyNz0EKwjAQBdBoC2I3nkEPEGppSLOyV8k0U2pJE9C61pvpzWKaitBNyWYGhs9_jCaEpF2iyFFBY29YK-B0sNbcu6tB2mj7UNKM1OCofXQrCVycc32XyP3gDztExlkpYwqWTLHGQO0nPH_SJkh5i6IVTUzHUmJrkkn9JC-_PPaetCxoLYe8AhHTM2mnf-q8-tjMfWYuPHcIHIiyqDiPKuq_TDeP1A
What that actually contains is an encoded set of {shard, node,
update_seq} triples kinda like such:
[
{"shards/00000000-3fffffff/davisp/test-db.1384769918", db7, { 9,
<<"ee5754a">>, db7}},
{"shards/40000000-7fffffff/davisp/test-db.1384769918", db2, { 1,
<<"0fe9f9c">>, db2}},
{"shards/80000000-bfffffff/davisp/test-db.1384769918", db5, {10,
<<"f7b08b9">>, db5}},
{"shards/c0000000-ffffffff/davisp/test-db.1384769918", db12, {15,
<<"b942877">>, db12}}
]
What's happening here is that when you specify that parameter, CouchDB
will decode it and then try and read the changes from each of those
shards resuming at the given update seq. As an aside the extra uuid
prefix and node name are extra so that we can try and skip some old
changes, an optimization but not important for this discussion.
Now, the important bit is that if we specify this since seq and one of
the nodes db2, db5, db7, or db12 happens to be down (or just gone if
you stored that since seq for a long time and say the cluster changed
size) then CouchDB has to choose another shard to replace the missing
node. When this happens you will see "old" changes that have already
been processed. Your application should be able to handle this using
the approaches that Bob listed in his email.
However, (there's always a however in distributed systems) there
exists a timing situation where you may be reading the changes feed,
an update comes in to the shard you're reading from, and you see the
change. Then say that node goes down (which would terminate the
changes feed). The client would then reconnect with their latest
update seq and get a different node. This node may (depending on a
whole bunch of timing and optimization things) send a change for the
doc that is technically "before" the change that was already
processed. So you do have to be able to recognize that you already
processed a change for the doc. CouchDB does this internally by
keeping the revision tree and checking revisions against that.
I get the feeling that my description may not be super clear so I'll
try and restate it as a sequence of events:
1. Client requests _changes with since=35-g1AAA...
2. Someone makes an update to doc foo
3. The first shard that handles the update is part of the changes feed from #1
4. Client reading _changes sees update appear in its feed
5. The node containing the shard with an update dies (an operator
rebooted the wrong node perhaps)
6. Client has its changes feed disconnect and reconnects with
since=35-g1AAA.. (or even a newer sequence)
7. The shard that responds as a replacement for the shard on the dead
node does not (yet) have the update
8. The doc exists in the update sequence after where it starts reading
its changes feed
9. Client sees the "old" change and must know that its old
Note that this is all very unlikely and super sensitive to timing. For
instance, one node seeing the update, and then dying, and the other
two copies not receving the update would require some very peculiar
network disconnections in the cluster while still being reachable from
the load balancer. But the possibility remains which means apps will
want to be able to handle it.
Paul