1

I have a stupid problem with scotty web app and mongodb service starting in the right order. I use systemd to start mongodb first and then the scotty web app. It does not work for some reason. The app errors out with connect: does not exist (Connection refused) from the mongodb driver meaning that the connection is not ready.

So my question. How can I test the connection availability say three times with 0.5s interval and only then error out?

This is the application main function

main :: IO ()
main = do
  pool <- createPool (runIOE $ connect $ host "127.0.0.1") close 1 300 5
  clearSessions pool
  let r = \x -> runReaderT x pool
  scottyT 3000 r r basal

basal :: ScottyD ()
basal = do
  middleware $ staticPolicy (noDots >-> addBase "static")
  notFound $ runSession
  routes

Although the app service is ordered after mongodb service the connection to mongodb is still unavailable during the app start up. So I get the above mentioned error. This is the systemd service file to avoid questions regarding the correct service ordering.

[Unit]
Description=Basal Web Application
Requires=mongodb.service
After=mongodb.service iptables.service network-online.target

[Service]
User=http
Group=http
WorkingDirectory=/srv/http/basal/
ExecStart=/srv/http/basal/bin/basal
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

I don't know why connection to mongodb is not available given the correct service order. So I want to probe connection availability withing haskell code three times with 0.5s delay and then error out. How can I do it?

Thanks.

r.sendecky
  • 9,933
  • 9
  • 34
  • 62
  • Hey, mongodb should really be ready to accept connections if you have After=mongodb.service in your systemd service file. Would you mind telling me your distro (if that is where you got the service file for mongo) or pastebinning your mongodb service file (as well as telling me if you wrote it yourself or got it from somewhere). Thanks a ton. – CameronNemo Jul 26 '14 at 20:15
  • @CameronNemo Sorry for the late reply - long holiday. My distro is Arch. The above service file is obveously my own. The mongodb service file came with the package. I stopped trying to fix the actual systemd priorities. I solved it on the application level trying the connection several times till mongodb is ready. – r.sendecky Sep 15 '14 at 03:38

1 Answers1

3

I guess from the functions you're using that you're using something like mongoDB 1.5.0.

Here, connect returns something in the IOE monad, which is an alias for ErrorTIOErrorIO.

So the best approach is to use the retrying mechanisms ErrorT offers. As it's an instance of MonadPlus, we can just use mplus if we don't care about checking for the specific error:

retryConnect :: Int -> Int -> Host -> IOE Pipe
retryConnect retries delayInMicroseconds host
    | retries > 0 =
            connect host `mplus`
                (liftIO (threadDelay delayInMicroseconds) >>
                   retryConnect (retries - 1) delayInMicroseconds host)
    | otherwise = connect host

(threadDelay comes from Control.Concurrent).

Then replace connect with retryConnect 2 500000 and it'll retry twice after the first failure with a 500,000 microsecond gap (i.e. 0.5s).

If you do want to check for a specific error, then use catchError instead and inspect the error to decide whether to swallow it or rethrow it.

Ganesh Sittampalam
  • 28,821
  • 4
  • 79
  • 98
  • Thank you for the example. It does not compile for now, gives me a type error in `threadDelay delayInMicroseconds` Expected type: Control.Monad.Trans.Error.ErrorT IOError IO () Actual type: IO () I'll have a look at it closer during the day... – r.sendecky Jul 11 '14 at 02:08
  • OK. I just had to `liftIO`the `threadDelay delayInMicroseconds` part. It compiles now. Thank you. Let me just check if it fixed my issue and everything works... – r.sendecky Jul 11 '14 at 05:22
  • All works as expected. I am very happy. )) To completely get rid of the error I had to encrease the number of retries to 4 and the delay to 1 second. Aftyer that it worked fine. Thanks once again. – r.sendecky Jul 11 '14 at 05:38
  • Apologies for the mistake, I was too lazy to try to compile it myself first - I've edited in the fix now :-) – Ganesh Sittampalam Jul 11 '14 at 06:34