summaryrefslogtreecommitdiffstats
path: root/iredis/data/commands/blpop.md
diff options
context:
space:
mode:
Diffstat (limited to 'iredis/data/commands/blpop.md')
-rw-r--r--iredis/data/commands/blpop.md182
1 files changed, 182 insertions, 0 deletions
diff --git a/iredis/data/commands/blpop.md b/iredis/data/commands/blpop.md
new file mode 100644
index 0000000..b48ace7
--- /dev/null
+++ b/iredis/data/commands/blpop.md
@@ -0,0 +1,182 @@
+`BLPOP` is a blocking list pop primitive. It is the blocking version of `LPOP`
+because it blocks the connection when there are no elements to pop from any of
+the given lists. An element is popped from the head of the first list that is
+non-empty, with the given keys being checked in the order that they are given.
+
+## Non-blocking behavior
+
+When `BLPOP` is called, if at least one of the specified keys contains a
+non-empty list, an element is popped from the head of the list and returned to
+the caller together with the `key` it was popped from.
+
+Keys are checked in the order that they are given. Let's say that the key
+`list1` doesn't exist and `list2` and `list3` hold non-empty lists. Consider the
+following command:
+
+```
+BLPOP list1 list2 list3 0
+```
+
+`BLPOP` guarantees to return an element from the list stored at `list2` (since
+it is the first non empty list when checking `list1`, `list2` and `list3` in
+that order).
+
+## Blocking behavior
+
+If none of the specified keys exist, `BLPOP` blocks the connection until another
+client performs an `LPUSH` or `RPUSH` operation against one of the keys.
+
+Once new data is present on one of the lists, the client returns with the name
+of the key unblocking it and the popped value.
+
+When `BLPOP` causes a client to block and a non-zero timeout is specified, the
+client will unblock returning a `nil` multi-bulk value when the specified
+timeout has expired without a push operation against at least one of the
+specified keys.
+
+**The timeout argument is interpreted as an integer value specifying the maximum
+number of seconds to block**. A timeout of zero can be used to block
+indefinitely.
+
+## What key is served first? What client? What element? Priority ordering details.
+
+- If the client tries to blocks for multiple keys, but at least one key contains
+ elements, the returned key / element pair is the first key from left to right
+ that has one or more elements. In this case the client is not blocked. So for
+ instance `BLPOP key1 key2 key3 key4 0`, assuming that both `key2` and `key4`
+ are non-empty, will always return an element from `key2`.
+- If multiple clients are blocked for the same key, the first client to be
+ served is the one that was waiting for more time (the first that blocked for
+ the key). Once a client is unblocked it does not retain any priority, when it
+ blocks again with the next call to `BLPOP` it will be served accordingly to
+ the number of clients already blocked for the same key, that will all be
+ served before it (from the first to the last that blocked).
+- When a client is blocking for multiple keys at the same time, and elements are
+ available at the same time in multiple keys (because of a transaction or a Lua
+ script added elements to multiple lists), the client will be unblocked using
+ the first key that received a push operation (assuming it has enough elements
+ to serve our client, as there may be other clients as well waiting for this
+ key). Basically after the execution of every command Redis will run a list of
+ all the keys that received data AND that have at least a client blocked. The
+ list is ordered by new element arrival time, from the first key that received
+ data to the last. For every key processed, Redis will serve all the clients
+ waiting for that key in a FIFO fashion, as long as there are elements in this
+ key. When the key is empty or there are no longer clients waiting for this
+ key, the next key that received new data in the previous command / transaction
+ / script is processed, and so forth.
+
+## Behavior of `!BLPOP` when multiple elements are pushed inside a list.
+
+There are times when a list can receive multiple elements in the context of the
+same conceptual command:
+
+- Variadic push operations such as `LPUSH mylist a b c`.
+- After an `EXEC` of a `MULTI` block with multiple push operations against the
+ same list.
+- Executing a Lua Script with Redis 2.6 or newer.
+
+When multiple elements are pushed inside a list where there are clients
+blocking, the behavior is different for Redis 2.4 and Redis 2.6 or newer.
+
+For Redis 2.6 what happens is that the command performing multiple pushes is
+executed, and _only after_ the execution of the command the blocked clients are
+served. Consider this sequence of commands.
+
+ Client A: BLPOP foo 0
+ Client B: LPUSH foo a b c
+
+If the above condition happens using a Redis 2.6 server or greater, Client **A**
+will be served with the `c` element, because after the `LPUSH` command the list
+contains `c,b,a`, so taking an element from the left means to return `c`.
+
+Instead Redis 2.4 works in a different way: clients are served _in the context_
+of the push operation, so as long as `LPUSH foo a b c` starts pushing the first
+element to the list, it will be delivered to the Client **A**, that will receive
+`a` (the first element pushed).
+
+The behavior of Redis 2.4 creates a lot of problems when replicating or
+persisting data into the AOF file, so the much more generic and semantically
+simpler behavior was introduced into Redis 2.6 to prevent problems.
+
+Note that for the same reason a Lua script or a `MULTI/EXEC` block may push
+elements into a list and afterward **delete the list**. In this case the blocked
+clients will not be served at all and will continue to be blocked as long as no
+data is present on the list after the execution of a single command,
+transaction, or script.
+
+## `!BLPOP` inside a `!MULTI` / `!EXEC` transaction
+
+`BLPOP` can be used with pipelining (sending multiple commands and reading the
+replies in batch), however this setup makes sense almost solely when it is the
+last command of the pipeline.
+
+Using `BLPOP` inside a `MULTI` / `EXEC` block does not make a lot of sense as it
+would require blocking the entire server in order to execute the block
+atomically, which in turn does not allow other clients to perform a push
+operation. For this reason the behavior of `BLPOP` inside `MULTI` / `EXEC` when
+the list is empty is to return a `nil` multi-bulk reply, which is the same thing
+that happens when the timeout is reached.
+
+If you like science fiction, think of time flowing at infinite speed inside a
+`MULTI` / `EXEC` block...
+
+@return
+
+@array-reply: specifically:
+
+- A `nil` multi-bulk when no element could be popped and the timeout expired.
+- A two-element multi-bulk with the first element being the name of the key
+ where an element was popped and the second element being the value of the
+ popped element.
+
+@examples
+
+```
+redis> DEL list1 list2
+(integer) 0
+redis> RPUSH list1 a b c
+(integer) 3
+redis> BLPOP list1 list2 0
+1) "list1"
+2) "a"
+```
+
+## Reliable queues
+
+When `BLPOP` returns an element to the client, it also removes the element from
+the list. This means that the element only exists in the context of the client:
+if the client crashes while processing the returned element, it is lost forever.
+
+This can be a problem with some application where we want a more reliable
+messaging system. When this is the case, please check the `BRPOPLPUSH` command,
+that is a variant of `BLPOP` that adds the returned element to a target list
+before returning it to the client.
+
+## Pattern: Event notification
+
+Using blocking list operations it is possible to mount different blocking
+primitives. For instance for some application you may need to block waiting for
+elements into a Redis Set, so that as far as a new element is added to the Set,
+it is possible to retrieve it without resort to polling. This would require a
+blocking version of `SPOP` that is not available, but using blocking list
+operations we can easily accomplish this task.
+
+The consumer will do:
+
+```
+LOOP forever
+ WHILE SPOP(key) returns elements
+ ... process elements ...
+ END
+ BRPOP helper_key
+END
+```
+
+While in the producer side we'll use simply:
+
+```
+MULTI
+SADD key element
+LPUSH helper_key x
+EXEC
+```