
Hello there Yifan,
exception handling should be done on a per-context basis, where the
developer establishes the notion of context. Most of the time this
boils down to releasing resources:
forkIO (doStuffWith h `finally` hClose h)
In more complicated scenarios, where you actually need to /handle/ the
exception you should probably wrap some control concept around it.
There are many options. You could just catch and handle the exception.
Other options include a resumable monad (like monad-coroutine) that
brings everything back into a consistent state.
Exception handling is convenient in Haskell. You should probably just
try to enforce some of the exception cases by using the server in a
wrong way. Close the connection prematurely or send Unix signals. Note
that you need to handle signals separately. In particular by default a
SIGPIPE, which can in fact be thrown by the networking system, needs to
be ignored:
import System.Posix.Signal
main :: IO ()
main =
withSocketsDo $ do
installHandler sigPIPE Ignore Nothing
Finally for both efficiency and safety make use of a stream processing
abstraction like conduit, enumerator or pipes.
Greets,
Ertugrul
Yifan Yu
First of all, apologise if the question is too broad. The background goes like this: I've implemented a server program in Haskell for my company intended to replace the previous one written in C which crashes a lot (and btw the technology of the company is exclusively C-based). When I chose Haskell I promised my manager (arrogantly - I actually made a bet with him), "it won't crash". Now it has been finished (with just a few hundred LOC), and my test shows that it is indeed very stable. But by looking at the code again I'm a little worried, since I'm rather new to exception handling and there're many networking-related functions in the program. I was tempted to catch (SomeException e) at the very top-level of the program and try to recursively call main to restart the server in case of any exception being thrown, but I highly doubt that is the correct and idiomatic way. There are also a number of long-running threads launched from the main thread, and exceptions thrown from these threads can't be caught by the top-level `catch' in the main thread. My main function looks like this:
main :: IO () main = withSocketsDo $ do sCameraU <- socketNewPassive False 6000 sStunU <- socketNewPassive False 3478 sCmdT <- socketNewPassive True 7000 mvarCam <- newMVar M.empty mvarLog <- newMVar []
forkIO $ regCamera sCameraU mvarCam mvarLog forkIO $ updCamera mvarCam mvarLog forkIO $ stun sCameraU sStunU mvarCam mvarLog
listen sCmdT 128 processCmd sCmdT mvarCam mvarLog
sClose sCameraU sClose sStunU sClose sCmdT
I find that I can't tell whether a function will throw any exception at all, or what exceptions will be thrown, by looking at their documentation. I can only tell if I browse the source code. So the question is, how can I determine all the exceptions that can be thrown by a given function? And what is the best way to handle situations like this, with both the long-running threads and main thread need to be restarted whenever exceptions happen.
-- Not to be or to be and (not to be or to be and (not to be or to be and (not to be or to be and ... that is the list monad.