I am using the eredis erlang client and I am new to Erlang. I was wondering what might be wrong with the following function:
foo(Host, Port) ->
case catch eredis:start_link(Host, Port) of
{connection_error, {connection_error, _}} -> {error, "failed"};
{ok, Connection} -> {"done"};
_ -> {error, "Unknown"}
end.
My understanding is that given the above function and a valid Redis host:port e.g. localhost:6379 then if I do:
mymodule:foo('localhost', 6379).
I should get the answer
{"done"}
while if for example I do:
mymodule:foo('loc', 6379).
I should get:
{error, "failed"}
But in the latter case what I get is:
** exception exit: {connection_error,{connection_error,nxdomain}}
Could somebody kindly explain what am I doing wrong here?
Thanks
The problem is probably that your exception is stemming from the eredis_client gen_server you start up with your start link. It is supposed to return {error, Term} back to you and never throw an exception there. You are also linked to the process, so you may die due to this.
It is very rare that you need to do exception handling in Erlang. Here you can just handle errors directly
case eredis:start_link(Host, Port) of
{ok, Pid} -> {ok, Pid};
{error, Reason} -> {error, Reason}
end.
should be enough. In fact, you can just do
{ok, Pid} = eredis:start_link(Host, Port)
and utilize a crash if something goes wrong for the time being. The error you see due to nxdomain is because you don't have the name 'loc'.
Related
I am learning Clojure, and I would like to create a macro that works like Javas try-catch.
If an exception is thrown, the exception should be returned. Otherwise, the result should be returned.
Any resource that is open should also be closed in the finally section (Without the use of with-open). However, I do have one problem except not being caught that I don't know how to solve. Any help or suggestion would be appreciated!
Here is my code:
(defmacro my-try
([expression]
`(try
~expression
(catch Exception e# e#)
)
)
([[value variable] expression]
`(let [~value ~variable]
(try
~expression
(catch Exception e# e#)
(finally (if (instance? java.io.Closeable ~value) (.close ~value)))
)
)
)
)
When I try to open and read from a file that does not exist:
(def v (my-try [s (FileReader. (File. "missing-file"))] (. s read)))
(println v)
I get the following error:
Execution error (FileNotFoundException) at java.io.FileInputStream/open0 (FileInputStream.java:-2).
missing-file (Det går inte att hitta filen)
I suspect that this error message is an uncaught exception because (1) it does not follow the structure of other exceptions, and (2) if I change the format of the exception return, such as adding a specific message, the error message still does not change.
Any help in finding out what is at fault is highly appreciated!
Many thanks for considering my request.
In (let [~value ~variable], ~variable is evaluating to (FileReader. (File. "missing-file")), but that's outside of the try. It would become something like this:
(let [s (FileReader. (File. "missing-file"))]
(try
(. s read)
. . .
))
Move the let into the try, then expression into the let body.
Also, like in all languages, (catch Exception e# e#) is pretty much universally a bad idea. Throwing away errors becomes a nightmare once anything remotely non-trivial happens, since you've thrown out your only evidence of the problem.
I know we can get the full stacktrace using __STACKTRACE__ in a catch/rescue block in elixir, but what's the correct way of printing it? In my case, I rescue from an error but I still want to log it to console. This is what I'm doing right now:
def unreliable_method(item) do
# Do something with `item`
:ok
rescue
_err ->
Logger.error("Failed for item: #{inspect(item)}")
Logger.error(inspect(__STACKTRACE__))
{:error, :processing_failed}
end
Just the Stacktrace
This was answered by Michał Muskała on the official elixir github issue:
The canonical way would be to use Exception.format_stacktrace/1
From the docs, it's clear that we don't need to explicitly pass __STACKTRACE__ as an argument to the method when still inside the rescue block. It's automatically retrieved using Process.info:
Logger.error(Exception.format_stacktrace())
Full Error and Stacktrace
Michal's comment helped me find Exception.format/3, that formats the error itself and its complete stacktrace, and that seemed more appropriate for my usecase:
def unreliable_method do
# do something
:ok
rescue
err ->
Logger.error(Exception.format(:error, err, __STACKTRACE__))
{:error, :processing_failed}
end
Say I'm going to open a file and parse its contents, and I want to do that lazily:
parseFile :: FilePath -> IO [SomeData]
parseFile path = openBinaryFile path ReadMode >>= parse' where
parse' handle = hIsEOF handle >>= \eof -> do
if eof then hClose handle >> return []
else do
first <- parseFirst handle
rest <- unsafeInterleaveIO $ parse' handle
return (first : rest)
The above code is fine if no error occurs during the whole reading process. But if an exception is thrown, there would be no chance to execute hClose, and the handle won't be correctly closed.
Usually, if the IO process isn't lazy, exception handling could be easily solved by catch or bracket. However in this case normal exception handling methods will cause the file handle to be closed before the actual reading process starts. That of course not acceptable.
So what is the common way to release some resources that need to be kept out of its scope because of laziness, like what I'm doing, and still ensuring exception safety?
Instead of using openBinaryFile, you could use withBinaryFile:
parseFile :: FilePath -> ([SomeData] -> IO a) -> IO a
parseFile path f = withBinaryFile path ReadMode $ \h -> do
values <- parse' h
f values
where
parse' = ... -- same as now
However, I'd strongly recommend you consider using a streaming data library instead, as they are designed to work with this kind of situation and handle exceptions properly. For example, with conduit, your code would look something like:
parseFile :: MonadResource m => FilePath -> Producer m SomeData
parseFile path = bracketP
(openBinaryFile path ReadMode)
hClose
loop
where
loop handle = do
eof <- hIsEOF handle
if eof
then return ()
else parseFirst handle >>= yield >> loop handle
And if you instead rewrite your parseFirst function to use conduit itself and not drop down to the Handle API, this glue code would be shorter, and you wouldn't be tied directly to Handle, which makes it easier to use other data sources and perform testing.
The conduit tutorial is available on the School of Haskell.
UPDATE One thing I forgot to mention is that, while the question focuses on exceptions preventing the file from being closed, even non-exceptional situations will result in that, if you don't completely consume the input. For example, if you file has more than one record, and you only force evaluation of the first one, the file will not be closed until the garbage collector is able to reclaim the handle. Yet another reason for either withBinaryFile or a streaming data library.
I'm writing a REST service in Erlang and need to verify the received data before passing it to other internal functions for further processing; in order to do that, I'm currently using nested case expressions like this:
case all_args_defined(Args) of
true ->
ActionSuccess = action(Args),
case ActionSuccess of
{ok, _} -> ...;
{fail, reason} -> {fail, reason}
end,
_ ->
{fail, "args not defined"}
end,
...
I realize this is kind of ugly, but this way I can provide detailed error messages. Additionally, I don't think the usual make it crash philosophy is applicable here - I don't want my REST service to crash and be restarted every time somebody throws invalid arguments at it.
However, I'm considering abandoning all those cases in favor of an umbrella try/catch block catching any badmatch errors - would this work?
fun() ->
true = all_args_defined(Args),
{ok, _} = action(Args).
%% somewhere else
catch fun().
Since what you want to achieve is error reporting, you should structure the thing around the execution of actions and reporting of the result. Perhaps something like this:
execute(Action, Args) ->
try
check_args(Args),
Result = action(Action, Args),
send_result(Result)
catch
throw:{fail, Reason} ->
report_error(Reason);
ExceptionClass:Term ->
%% catch-all for all other unexpected exceptions
Trace = erlang:get_stacktrace(),
report_error({crash, ExceptionClass, Term, Trace})
end.
%% all of these throw {fail, Reason} if they detect something fishy
%% and otherwise they return some value as result (or just crash)
action(foo, [X1, X2]) -> ...;
action(foo, Args) -> throw({fail, {bad_arity, foo, 2, Args}});
action(...) -> ...
%% this handles the formatting of all possible errors
report_error({bad_arity, Action, Arity, Args}) ->
send_error(io_lib:format("wrong number of arguments for ~w: "
"expected ~w, but got ~w",
[Action, Arity, length(Args)]));
report_error(...) -> ...;
report_error({crash, Class, Term, Trace}) ->
send_error(io_lib:format("internal error: "
"~w:~w~nstacktrace:~n~p~n",
[Class, Term, Trace])).
I've had this problem while developing an application that create users.
I first come with a solution like this:
insert() ->
try
check_1(), % the check functions throw an exception on error.
check_2(),
check_3(),
do_insert()
catch
throw:Error1 ->
handle_error_1();
throw:Error2 ->
handle_error_2();
_:Error ->
internal_error()
end.
The problem with this solution is that you lose the stack trace with the try...catch block.
Instead of this, a better solution is:
insert() ->
case catch execute() of
ok -> all_ok;
{FuncName, Error} ->
handle_error(FuncName, Error);
{'EXIT', Error} ->
internal_error(Error)
end.
execute() ->
check_1(), % the check functions throw an exception on error.
check_2(),
check_3(),
do_insert().
This way you have the full error stack on Error.
I have faced exactly the same question when writing my own REST services.
Let's start with the philosophy:
I like to think of my applications like a box. On the inside of the box are all of the parts I built and have direct control over. If something breaks here, it's my fault, it should crash, and I should read about it in an error log. On the edge of the box are all of the connection points to the outside world - these are not to be trusted. I avoid exception handling in the inside parts and use it as needed for the outer edge.
On similar projects I have worked on:
I usually have about a dozen checks on the user input. If something looks bad, I log it and return an error to the user. Having a stack trace isn't particularly meaningful to me - if the user forgot a parameter there is nothing in my code to hunt down and fix. I'd rather see a text log that says something like: “at 17:35, user X accessed path Y but was missing parameter Z”.
I organize my checks into functions that return ok or {error, string()}. The main function just iterates over the checks and returns ok if they all pass, otherwise it returns the first error, which is then logged. Inside of my check functions I use exception handling as needed because I can't possibly consider all of the ways users can screw up.
As suggested by my colleagues, you can alternatively have each check throw an exception instead of using a tuple.
As for your implementation, I think your idea of using a single exception handler is a good one if you only have the single check. If you end up needing more checks you may want to implement something like I described so that you can have more specific logging.
One last question for the evening, I'm building the main input function of my Haskell program and I have to check for the args that are brought in
so I use
args <- getArgs
case length args of
0 -> putStrLn "No Arguments, exiting"
otherwise -> { other methods here}
Is there an intelligent way of setting up other methods, or is it in my best interest to write a function that the other case is thrown to within the main?
Or is there an even better solution to the issue of cases. I've just got to take in one name.
args <- getArgs
case length args of
0 -> putStrLn "No Arguments, exiting"
otherwise -> do
other
methods
here
Argument processing should isolated in a separate function.
Beyond that it's hard to generalize, because there are so many different ways of handling arguments.
Here are some type signatures that are worth considering:
exitIfNonempty :: [Arg] -> IO [Arg] -- return args unless empty
processOptions :: [Arg] -> (OptionRecord, [Arg]) -- convert options to record,
-- return remaining args
processOptionsBySideEffect :: [Arg] -> State [Arg] -- update state from options,
-- return remaining args
callFirstArgAsCommand :: [(Name, [Arg] -> IO ())] -> [Arg] -> IO ()
And a couple sketches of implementations (none of this code has been anywhere near a compiler):
exitIfNonempty [] = putStrLen "No arguments; exiting"
exitIfNonempty args = return args
callFirstArgAsCommand commands [] = fail "Missing command name"
callFirstArgAsCommand commands (f:as) =
case lookup f commands in
Just f -> f as
Nothing -> fail (f ++ " is not the name of any command")
I'll leave the others to your imagination.
Is it in my best interest to write a function that the other case is thrown to within the main?
Yes. Moreover, you should build up a library of combinators that you can call on to process command-line argument easily, for a variety of programs. Such libraries undoubtedly already exist on Hackage, but this is one of those cases where it may be easier to roll your own than to learn somebody else's API (and it will definitely be more fun).
View Patterns might be helpful here.