thanks for raising this issue, I think it is an interesting topic to
discuss and one where guidelines are a good idea as it's not a matter
of API or language, but about semantics.
I would always raise an exception on parse-time errors, because
clearly there is no point into executing a transaction that will have
missing commands because they are misspelled or alike. So unless the
user traps the exception in some language-specific way, the error will
stop the execution of the program and the transaction will not be
executed at all.
Unfortunately once you add pipelining into the mix things are not as
simple as they should be, because:
1) If you send MULTI / commands / EXEC in the same pipeline you can't
prevent the EXEC even if you detected errors.
2) If you split the pipeline sending "MULTI / commands" before, read
the reply, and than EXEC, you can handle it correctly, but this means
to pay two times the round trip time, that's not cool.
So since parse-time errors should only happen on *syntax errors*, I think that:
1) If the library does not use pipelining for MULTI/EXEC the
parse-time error should raised ASAP, if reply is not "QUEUED".
2) If the library uses pipelining it's ok to raise the error after
sending the EXEC, but the error raised should be the first parse-time
error encountered if any.
After all, even in an ACID SQL system, if there is a syntax error in
the query, no body can save the user from a disaster, but this should
only happen in development environments.
About exec-time errors, I think this category of errors should also
raise an exception that should stop the execution of the program by
default, because in this stage errors can happen only for severe
conditions like wrong type (problem in the application logic), or out
of memory in Redis if it's configured with maxmemory, and other
similar things that are not expected usually.
However I think it's a good idea if, optionally, libraries have an API
that allows to just call EXEC without raising errors but just
returning the array of replies, that may include errors elements
inside, with a way to test for errors. Like:
result = redis.exec(trap_errors = true)
if result.is_error() ...
in this way the default behaviour is the safest, but the library still
delivers all the power to handle everything by hand if needed (think
about writing a shell that returns an array of replies including
errors for MULTI/EXEC blocks).
Salvatore 'antirez' Sanfilippo
open source developer - VMware
Beauty is more important in computing than anywhere else in technology
because software is so complicated. Beauty is the ultimate defence
— David Gelernter