A fairly straightforward algorithm for this can be established, if you can assume some fixed 2D grid of cells, each of which contains a value for the level of the water in them. Imagine an infinitely tall grid of perspex dividers, at the bottom of which are holes/tubes to facilitate flow between adjacent cells. What's key is to not think about the cells themselves, but the connections between cells. E.g. in the simplest grid:
there are 4 connections between individual cells (between A and B, between B and D, between C and D, and between A and C). You can make diagonal connections as well if you like, it doesn't make a difference to the core algorithm. You can also add solid cells, connections into which are blocked, which in your case would form the banks of your imaginary river.
Imagine that you start with some initial state. It won't necessarily be 'level' or in equilibrium, and if it isn't, you expect that the first few updates will cause flow between the cells until equilibrium is reached.
For each connection, look at the cells on either side, and calculate the difference in water level between them. Say, for example, that A has a level of 3 and B has a level of 1. Then the connection from A to B has a 'pressure' of 2 (3-1) in the direction of B. If the cell on the other side of the connection is not empty (say because it's ground), then the pressure will be 0. If the cell on the other side has more water than this cell, the pressure will be some negative number.
The end result of this phase will be a numeric value for each connection as to how quickly water will flow through that connection, and in which direction. This is an 'instantaneous' value, in that it describes potential for flow when you next update. It is not trying to describe how much water will flow, just how much water wants to flow.
For each cell, look at the pressure of all of the connections that touch that cell. Use the information on those pressures to decide how much fluid to transfer from this cell to the cells on the other side of the connections. For example, say A (with its level of 3) has an outward pressure of 2 towards B (with level 1), and an outward pressure of 1 towards C (which has level 2). So in the next update, you'd transfer twice as much fluid to cell B as you do towards C.
Exactly how much fluid to transfer between cells is something you decide is sensible. Limiting that rate of transfer will cause your fluid to flow more slowly (like treacle instead of water), and you want to have a damping value of some sort to stop oscillation (e.g. water flowing from A to B, then B to A, then A to B, but never settling). It's also crucial to distribute the outwards flow between all connections (e.g. not just send all water out along the first connection you process)
What's key is that you only transfer in one direction. Because when you come to process cell B, you don't want to 'pull' fluid from A, because you may have already 'pushed' fluid from A to B.
The reason why you do it in two phases is so that you can make the decision on how fast the flows will be between cells, before you start changing the values of the individual cells. Otherwise fluid moving from A to B would affect the decision of how much fluid wants to move from B to D.