diff --git a/Happstack/Server/Helpers.hs b/Happstack/Server/Helpers.hs
--- a/Happstack/Server/Helpers.hs
+++ b/Happstack/Server/Helpers.hs
@@ -1,7 +1,16 @@
 {-# LANGUAGE ScopedTypeVariables #-}
 module Happstack.Server.Helpers
-    ( smartserver, exactdir, smartserver',getData',vhosts,vhost
+    ( smartserver, exactdir, smartserver',getData',vhosts,vhost, cleanUpLockFile, scrapeUrl, cleanUpLockFile
     ) where
+import Network.Stream
+import qualified Network.HTTP as HTTP
+import Data.Char (toLower)
+import Data.List (isInfixOf)
+import Network.URI (parseURI)
+import System.FilePath ((</>))
+import System.Timeout (timeout)
+import Control.Monad.Error
+import System.Directory (getCurrentDirectory, doesFileExist, removeFile)
 import qualified Control.Exception as E
 import Data.IORef
 import Happstack.Server
@@ -95,4 +104,49 @@
   threadDelay $ waitSeconds * (10^6)
   new <- readIORef eIOref
   return (tid,new)
+
+-- This is useful if you have a web server that crashes, but sometimes leaves the lock file hanging around.
+-- But sometimes, due to unknown reasons, has a false restart that should quickly exit because the lock file exists and the app is really running.
+-- What this function does is clean up the lock file, but only if a curl request for the actual web site fails.
+-- This feels like risky business, try to find a better way (unclear on what the race condition, if any, is exactly but uneasy...)
+-- Another danger is, what if the generated lock file doesn't match the actual lock file? (like if the underlying library call changes?)
+cleanUpLockFile thisprog checkurl teststring waitSecs = do 
+  progName <- getProgName
+  -- prevents inadvertent running from inside ghci.
+  unless (thisprog == progName) $ error $ "prog name isn't " ++ progName ++  " exiting: " ++ progName
+
+  lockFile <- liftM (</> "_local" </> progName ++ "_state.lock") getCurrentDirectory 
+  putStrLn $ "cleanUpLockFile, lock file: " ++ lockFile
+  lock_fileExists <- doesFileExist lockFile
+  when lock_fileExists $ do
+      up <- websiteUp waitSecs checkurl teststring 
+      if up 
+        then do
+          threadDelay $ 2 * 10^6
+          error $ " cleanUpLockFile: " ++ progName ++ " is already running. That's odd. Exiting now."
+        else removeFile lockFile
+
+websiteUp secsWaitRequest url teststring = do
+  let timeoutSecs n = timeout $ (10^6) * n
+  mbEtR <- timeoutSecs secsWaitRequest $ runErrorT $ scrapeUrl url
+  case mbEtR of 
+    Nothing -> do putStrLn $ "scrapeUrl returned nothing after " ++ (show secsWaitRequest) ++ "seconds, so we conclude it's donwn"
+                  return False
+    Just etR -> case etR of 
+      Left e -> return False
+      Right s -> return $ isInfixOf (lc teststring) (lc s)
+
+scrapeUrl :: String -> ErrorT String IO String
+scrapeUrl url = do 
+     rq <- ErrorT $ case Network.URI.parseURI url of
+                Nothing -> return . Left $ "bad url: " ++ url
+                Just uri -> return . Right $ HTTP.Request uri HTTP.GET [] ""
+                
+     ErrorT $ do r <- catch ( HTTP.simpleHTTP rq )
+                            ( \e -> return . Left . Network.Stream.ErrorMisc . show $ e)
+                 case r of 
+                   Right x -> return . Right . HTTP.rspBody $ x
+                   Left y -> return . Left $ "web fetch failed: " ++ (show rq)
+
+lc = map toLower
 
diff --git a/happstack-helpers.cabal b/happstack-helpers.cabal
--- a/happstack-helpers.cabal
+++ b/happstack-helpers.cabal
@@ -1,5 +1,5 @@
 Name: happstack-helpers
-Version: 0.46
+Version: 0.47
 License: BSD3
 License-file: bsd3.txt
 Description: Functions I found I was using repeatedly when programming Happstack based web-apps. 
@@ -53,4 +53,6 @@
                , pureMD5 >= 1.0.0.0 && < 1.1.0.0
                , PBKDF2 >= 0.3 && < 0.4
                , DebugTraceHelpers
+               , network >= 2.2
+               , HTTP >= 4000
   ghc-options: -Wall
