webapp: Now allows restarting any threads that crash.
This commit is contained in:
parent
07717a9b2b
commit
76ddf9b6d3
30 changed files with 124 additions and 61 deletions
|
@ -154,6 +154,7 @@ import Assistant.Threads.XMPPClient
|
||||||
import Assistant.Environment
|
import Assistant.Environment
|
||||||
import qualified Utility.Daemon
|
import qualified Utility.Daemon
|
||||||
import Utility.LogFile
|
import Utility.LogFile
|
||||||
|
import Utility.ThreadScheduler
|
||||||
|
|
||||||
stopDaemon :: Annex ()
|
stopDaemon :: Annex ()
|
||||||
stopDaemon = liftIO . Utility.Daemon.stopDaemon =<< fromRepo gitAnnexPidFile
|
stopDaemon = liftIO . Utility.Daemon.stopDaemon =<< fromRepo gitAnnexPidFile
|
||||||
|
@ -196,7 +197,7 @@ startDaemon assistant foreground startbrowser = do
|
||||||
d <- getAssistant id
|
d <- getAssistant id
|
||||||
urlrenderer <- liftIO newUrlRenderer
|
urlrenderer <- liftIO newUrlRenderer
|
||||||
#endif
|
#endif
|
||||||
mapM_ startthread
|
mapM_ (startthread urlrenderer)
|
||||||
[ watch $ commitThread
|
[ watch $ commitThread
|
||||||
#ifdef WITH_WEBAPP
|
#ifdef WITH_WEBAPP
|
||||||
, assist $ webAppThread d urlrenderer False Nothing webappwaiter
|
, assist $ webAppThread d urlrenderer False Nothing webappwaiter
|
||||||
|
@ -224,10 +225,10 @@ startDaemon assistant foreground startbrowser = do
|
||||||
, watch $ watchThread
|
, watch $ watchThread
|
||||||
]
|
]
|
||||||
|
|
||||||
waitNamedThreads
|
liftIO waitForTermination
|
||||||
|
|
||||||
watch a = (True, a)
|
watch a = (True, a)
|
||||||
assist a = (False, a)
|
assist a = (False, a)
|
||||||
startthread (watcher, t)
|
startthread urlrenderer (watcher, t)
|
||||||
| watcher || assistant = startNamedThread t
|
| watcher || assistant = startNamedThread (Just urlrenderer) t
|
||||||
| otherwise = noop
|
| otherwise = noop
|
||||||
|
|
|
@ -10,3 +10,4 @@ module Assistant.Common (module X) where
|
||||||
import Common.Annex as X
|
import Common.Annex as X
|
||||||
import Assistant.Monad as X
|
import Assistant.Monad as X
|
||||||
import Assistant.Types.DaemonStatus as X
|
import Assistant.Types.DaemonStatus as X
|
||||||
|
import Assistant.Types.NamedThread as X
|
||||||
|
|
|
@ -19,7 +19,6 @@ module Assistant.Monad (
|
||||||
asIO,
|
asIO,
|
||||||
asIO1,
|
asIO1,
|
||||||
asIO2,
|
asIO2,
|
||||||
NamedThread(..),
|
|
||||||
ThreadName,
|
ThreadName,
|
||||||
debug,
|
debug,
|
||||||
notice
|
notice
|
||||||
|
@ -41,10 +40,7 @@ import Assistant.Types.Commits
|
||||||
import Assistant.Types.Changes
|
import Assistant.Types.Changes
|
||||||
import Assistant.Types.Buddies
|
import Assistant.Types.Buddies
|
||||||
import Assistant.Types.NetMessager
|
import Assistant.Types.NetMessager
|
||||||
|
import Assistant.Types.ThreadName
|
||||||
{- Information about a named thread that can be run. -}
|
|
||||||
data NamedThread = NamedThread ThreadName (Assistant ())
|
|
||||||
type ThreadName = String
|
|
||||||
|
|
||||||
newtype Assistant a = Assistant { mkAssistant :: ReaderT AssistantData IO a }
|
newtype Assistant a = Assistant { mkAssistant :: ReaderT AssistantData IO a }
|
||||||
deriving (
|
deriving (
|
||||||
|
@ -59,7 +55,7 @@ instance MonadBase IO Assistant where
|
||||||
liftBase = Assistant . liftBase
|
liftBase = Assistant . liftBase
|
||||||
|
|
||||||
data AssistantData = AssistantData
|
data AssistantData = AssistantData
|
||||||
{ threadName :: String
|
{ threadName :: ThreadName
|
||||||
, threadState :: ThreadState
|
, threadState :: ThreadState
|
||||||
, daemonStatusHandle :: DaemonStatusHandle
|
, daemonStatusHandle :: DaemonStatusHandle
|
||||||
, scanRemoteMap :: ScanRemoteMap
|
, scanRemoteMap :: ScanRemoteMap
|
||||||
|
@ -75,7 +71,7 @@ data AssistantData = AssistantData
|
||||||
|
|
||||||
newAssistantData :: ThreadState -> DaemonStatusHandle -> IO AssistantData
|
newAssistantData :: ThreadState -> DaemonStatusHandle -> IO AssistantData
|
||||||
newAssistantData st dstatus = AssistantData
|
newAssistantData st dstatus = AssistantData
|
||||||
<$> pure "main"
|
<$> pure (ThreadName "main")
|
||||||
<*> pure st
|
<*> pure st
|
||||||
<*> pure dstatus
|
<*> pure dstatus
|
||||||
<*> newScanRemoteMap
|
<*> newScanRemoteMap
|
||||||
|
@ -136,5 +132,5 @@ notice = logaction noticeM
|
||||||
|
|
||||||
logaction :: (String -> String -> IO ()) -> [String] -> Assistant ()
|
logaction :: (String -> String -> IO ()) -> [String] -> Assistant ()
|
||||||
logaction a ws = do
|
logaction a ws = do
|
||||||
name <- getAssistant threadName
|
ThreadName name <- getAssistant threadName
|
||||||
liftIO $ a name $ unwords $ (name ++ ":") : ws
|
liftIO $ a name $ unwords $ (name ++ ":") : ws
|
||||||
|
|
|
@ -8,50 +8,78 @@
|
||||||
module Assistant.NamedThread where
|
module Assistant.NamedThread where
|
||||||
|
|
||||||
import Common.Annex
|
import Common.Annex
|
||||||
|
import Assistant.Types.NamedThread
|
||||||
|
import Assistant.Types.ThreadName
|
||||||
import Assistant.Types.DaemonStatus
|
import Assistant.Types.DaemonStatus
|
||||||
import Assistant.DaemonStatus
|
import Assistant.DaemonStatus
|
||||||
import Assistant.Alert
|
import Assistant.Alert
|
||||||
import Assistant.Monad
|
import Assistant.Monad
|
||||||
|
import Assistant.WebApp
|
||||||
|
import Assistant.WebApp.Types
|
||||||
|
|
||||||
import Control.Concurrent
|
import Control.Concurrent
|
||||||
import Control.Concurrent.Async
|
import Control.Concurrent.Async
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
|
import qualified Data.Text as T
|
||||||
|
import qualified Control.Exception as E
|
||||||
|
|
||||||
{- Starts a named thread, if it's not already running.
|
{- Starts a named thread, if it's not already running.
|
||||||
-
|
-
|
||||||
- Named threads are run by a management thread, so if they crash
|
- Named threads are run by a management thread, so if they crash
|
||||||
- an alert is displayed, allowing the thread to be restarted. -}
|
- an alert is displayed, allowing the thread to be restarted. -}
|
||||||
startNamedThread :: NamedThread -> Assistant ()
|
startNamedThread :: Maybe UrlRenderer -> NamedThread -> Assistant ()
|
||||||
startNamedThread namedthread@(NamedThread name a) = do
|
startNamedThread urlrenderer namedthread@(NamedThread name a) = do
|
||||||
m <- startedThreads <$> getDaemonStatus
|
m <- startedThreads <$> getDaemonStatus
|
||||||
case M.lookup name m of
|
case M.lookup name m of
|
||||||
Nothing -> start
|
Nothing -> start
|
||||||
Just aid ->
|
Just (aid, _) -> do
|
||||||
maybe noop (const start) =<< liftIO (poll aid)
|
r <- liftIO (E.try (poll aid) :: IO (Either E.SomeException (Maybe (Either E.SomeException ()))))
|
||||||
|
case r of
|
||||||
|
Right Nothing -> noop
|
||||||
|
_ -> start
|
||||||
where
|
where
|
||||||
start = do
|
start = do
|
||||||
d <- getAssistant id
|
d <- getAssistant id
|
||||||
aid <- liftIO $ runmanaged $ d { threadName = name }
|
aid <- liftIO $ runmanaged $ d { threadName = name }
|
||||||
|
restart <- asIO $ startNamedThread urlrenderer namedthread
|
||||||
modifyDaemonStatus_ $ \s -> s
|
modifyDaemonStatus_ $ \s -> s
|
||||||
{ startedThreads = M.insertWith' const name aid (startedThreads s) }
|
{ startedThreads = M.insertWith' const name (aid, restart) (startedThreads s) }
|
||||||
runmanaged d = do
|
runmanaged d = do
|
||||||
aid <- async $ runAssistant d a
|
aid <- async $ runAssistant d a
|
||||||
void $ forkIO $ manager d aid
|
void $ forkIO $ manager d aid
|
||||||
return aid
|
return aid
|
||||||
manager d aid = do
|
manager d aid = do
|
||||||
r <- waitCatch aid
|
r <- E.try (wait aid) :: IO (Either E.SomeException ())
|
||||||
case r of
|
case r of
|
||||||
Right _ -> noop
|
Right _ -> noop
|
||||||
Left e -> do
|
Left e -> do
|
||||||
let msg = unwords [name, "crashed:", show e]
|
let msg = unwords
|
||||||
|
[ fromThreadName name
|
||||||
|
, "crashed:", show e
|
||||||
|
]
|
||||||
hPutStrLn stderr msg
|
hPutStrLn stderr msg
|
||||||
-- TODO click to restart
|
button <- runAssistant d mkbutton
|
||||||
runAssistant d $ void $
|
runAssistant d $ void $
|
||||||
addAlert $ warningAlert name msg
|
addAlert $ (warningAlert (fromThreadName name) msg)
|
||||||
|
{ alertButton = button }
|
||||||
|
mkbutton = case urlrenderer of
|
||||||
|
Nothing -> return Nothing
|
||||||
|
Just renderer -> do
|
||||||
|
close <- asIO1 removeAlert
|
||||||
|
url <- liftIO $ renderUrl renderer (RestartThreadR name) []
|
||||||
|
return $ Just $ AlertButton
|
||||||
|
{ buttonLabel = T.pack "Restart Thread"
|
||||||
|
, buttonUrl = url
|
||||||
|
, buttonAction = Just close
|
||||||
|
}
|
||||||
|
|
||||||
{- Waits for all named threads that have been started to finish. -}
|
{- Waits for all named threads that have been started to finish.
|
||||||
|
-
|
||||||
|
- Note that if a named thread crashes, it will probably
|
||||||
|
- cause this to crash as well. Also, named threads that are started
|
||||||
|
- after this is called will not be waited on. -}
|
||||||
waitNamedThreads :: Assistant ()
|
waitNamedThreads :: Assistant ()
|
||||||
waitNamedThreads = do
|
waitNamedThreads = do
|
||||||
m <- startedThreads <$> getDaemonStatus
|
m <- startedThreads <$> getDaemonStatus
|
||||||
liftIO $ mapM_ wait $ M.elems m
|
liftIO $ mapM_ (wait . fst) $ M.elems m
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ import Data.Either
|
||||||
|
|
||||||
{- This thread makes git commits at appropriate times. -}
|
{- This thread makes git commits at appropriate times. -}
|
||||||
commitThread :: NamedThread
|
commitThread :: NamedThread
|
||||||
commitThread = NamedThread "Committer" $ do
|
commitThread = namedThread "Committer" $ do
|
||||||
delayadd <- liftAnnex $
|
delayadd <- liftAnnex $
|
||||||
maybe delayaddDefault (return . Just . Seconds)
|
maybe delayaddDefault (return . Just . Seconds)
|
||||||
=<< annexDelayAdd <$> Annex.getGitConfig
|
=<< annexDelayAdd <$> Annex.getGitConfig
|
||||||
|
|
|
@ -32,7 +32,7 @@ import qualified Data.Set as S
|
||||||
- be detected immediately.
|
- be detected immediately.
|
||||||
-}
|
-}
|
||||||
configMonitorThread :: NamedThread
|
configMonitorThread :: NamedThread
|
||||||
configMonitorThread = NamedThread "ConfigMonitor" $ loop =<< getConfigs
|
configMonitorThread = namedThread "ConfigMonitor" $ loop =<< getConfigs
|
||||||
where
|
where
|
||||||
loop old = do
|
loop old = do
|
||||||
waitBranchChange
|
waitBranchChange
|
||||||
|
|
|
@ -16,7 +16,7 @@ import Utility.NotificationBroadcaster
|
||||||
- frequently than once every ten minutes.
|
- frequently than once every ten minutes.
|
||||||
-}
|
-}
|
||||||
daemonStatusThread :: NamedThread
|
daemonStatusThread :: NamedThread
|
||||||
daemonStatusThread = NamedThread "DaemonStatus" $ do
|
daemonStatusThread = namedThread "DaemonStatus" $ do
|
||||||
notifier <- liftIO . newNotificationHandle
|
notifier <- liftIO . newNotificationHandle
|
||||||
=<< changeNotifier <$> getDaemonStatus
|
=<< changeNotifier <$> getDaemonStatus
|
||||||
checkpoint
|
checkpoint
|
||||||
|
|
|
@ -24,7 +24,7 @@ import qualified Data.Set as S
|
||||||
- downloads. If so, runs glacier-cli to check if the files are now
|
- downloads. If so, runs glacier-cli to check if the files are now
|
||||||
- available, and queues the downloads. -}
|
- available, and queues the downloads. -}
|
||||||
glacierThread :: NamedThread
|
glacierThread :: NamedThread
|
||||||
glacierThread = NamedThread "Glacier" $ runEvery (Seconds 3600) <~> go
|
glacierThread = namedThread "Glacier" $ runEvery (Seconds 3600) <~> go
|
||||||
where
|
where
|
||||||
isglacier r = Remote.remotetype r == Glacier.remote
|
isglacier r = Remote.remotetype r == Glacier.remote
|
||||||
go = do
|
go = do
|
||||||
|
|
|
@ -17,13 +17,10 @@ import qualified Git
|
||||||
import qualified Git.Branch
|
import qualified Git.Branch
|
||||||
import qualified Command.Sync
|
import qualified Command.Sync
|
||||||
|
|
||||||
thisThread :: ThreadName
|
|
||||||
thisThread = "Merger"
|
|
||||||
|
|
||||||
{- This thread watches for changes to .git/refs/, and handles incoming
|
{- This thread watches for changes to .git/refs/, and handles incoming
|
||||||
- pushes. -}
|
- pushes. -}
|
||||||
mergeThread :: NamedThread
|
mergeThread :: NamedThread
|
||||||
mergeThread = NamedThread "Merger" $ do
|
mergeThread = namedThread "Merger" $ do
|
||||||
g <- liftAnnex gitRepo
|
g <- liftAnnex gitRepo
|
||||||
let dir = Git.localGitDir g </> "refs"
|
let dir = Git.localGitDir g </> "refs"
|
||||||
liftIO $ createDirectoryIfMissing True dir
|
liftIO $ createDirectoryIfMissing True dir
|
||||||
|
|
|
@ -33,11 +33,8 @@ import qualified Control.Exception as E
|
||||||
#warning Building without dbus support; will use mtab polling
|
#warning Building without dbus support; will use mtab polling
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
thisThread :: ThreadName
|
|
||||||
thisThread = "MountWatcher"
|
|
||||||
|
|
||||||
mountWatcherThread :: NamedThread
|
mountWatcherThread :: NamedThread
|
||||||
mountWatcherThread = NamedThread "MountWatcher" $
|
mountWatcherThread = namedThread "MountWatcher" $
|
||||||
#if WITH_DBUS
|
#if WITH_DBUS
|
||||||
dbusThread
|
dbusThread
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -33,7 +33,7 @@ netWatcherThread = thread dbusThread
|
||||||
netWatcherThread = thread noop
|
netWatcherThread = thread noop
|
||||||
#endif
|
#endif
|
||||||
where
|
where
|
||||||
thread = NamedThread "NetWatcher"
|
thread = namedThread "NetWatcher"
|
||||||
|
|
||||||
{- This is a fallback for when dbus cannot be used to detect
|
{- This is a fallback for when dbus cannot be used to detect
|
||||||
- network connection changes, but it also ensures that
|
- network connection changes, but it also ensures that
|
||||||
|
@ -41,7 +41,7 @@ netWatcherThread = thread noop
|
||||||
- while (despite the local network staying up), are synced with
|
- while (despite the local network staying up), are synced with
|
||||||
- periodically. -}
|
- periodically. -}
|
||||||
netWatcherFallbackThread :: NamedThread
|
netWatcherFallbackThread :: NamedThread
|
||||||
netWatcherFallbackThread = NamedThread "NetWatcherFallback" $
|
netWatcherFallbackThread = namedThread "NetWatcherFallback" $
|
||||||
runEvery (Seconds 3600) <~> handleConnection
|
runEvery (Seconds 3600) <~> handleConnection
|
||||||
|
|
||||||
#if WITH_DBUS
|
#if WITH_DBUS
|
||||||
|
|
|
@ -23,11 +23,8 @@ import Network.Socket
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import Data.Char
|
import Data.Char
|
||||||
|
|
||||||
thisThread :: ThreadName
|
|
||||||
thisThread = "PairListener"
|
|
||||||
|
|
||||||
pairListenerThread :: UrlRenderer -> NamedThread
|
pairListenerThread :: UrlRenderer -> NamedThread
|
||||||
pairListenerThread urlrenderer = NamedThread "PairListener" $ do
|
pairListenerThread urlrenderer = namedThread "PairListener" $ do
|
||||||
listener <- asIO1 $ go [] []
|
listener <- asIO1 $ go [] []
|
||||||
liftIO $ withSocketsDo $
|
liftIO $ withSocketsDo $
|
||||||
runEvery (Seconds 1) $ void $ tryIO $
|
runEvery (Seconds 1) $ void $ tryIO $
|
||||||
|
|
|
@ -19,12 +19,9 @@ import qualified Types.Remote as Remote
|
||||||
|
|
||||||
import Data.Time.Clock
|
import Data.Time.Clock
|
||||||
|
|
||||||
thisThread :: ThreadName
|
|
||||||
thisThread = "Pusher"
|
|
||||||
|
|
||||||
{- This thread retries pushes that failed before. -}
|
{- This thread retries pushes that failed before. -}
|
||||||
pushRetryThread :: NamedThread
|
pushRetryThread :: NamedThread
|
||||||
pushRetryThread = NamedThread "PushRetrier" $ runEvery (Seconds halfhour) <~> do
|
pushRetryThread = namedThread "PushRetrier" $ runEvery (Seconds halfhour) <~> do
|
||||||
-- We already waited half an hour, now wait until there are failed
|
-- We already waited half an hour, now wait until there are failed
|
||||||
-- pushes to retry.
|
-- pushes to retry.
|
||||||
topush <- getFailedPushesBefore (fromIntegral halfhour)
|
topush <- getFailedPushesBefore (fromIntegral halfhour)
|
||||||
|
@ -38,7 +35,7 @@ pushRetryThread = NamedThread "PushRetrier" $ runEvery (Seconds halfhour) <~> do
|
||||||
|
|
||||||
{- This thread pushes git commits out to remotes soon after they are made. -}
|
{- This thread pushes git commits out to remotes soon after they are made. -}
|
||||||
pushThread :: NamedThread
|
pushThread :: NamedThread
|
||||||
pushThread = NamedThread "Pusher" $ runEvery (Seconds 2) <~> do
|
pushThread = namedThread "Pusher" $ runEvery (Seconds 2) <~> do
|
||||||
-- We already waited two seconds as a simple rate limiter.
|
-- We already waited two seconds as a simple rate limiter.
|
||||||
-- Next, wait until at least one commit has been made
|
-- Next, wait until at least one commit has been made
|
||||||
commits <- getCommits
|
commits <- getCommits
|
||||||
|
|
|
@ -20,7 +20,7 @@ import Data.Time.Clock.POSIX
|
||||||
|
|
||||||
{- This thread wakes up occasionally to make sure the tree is in good shape. -}
|
{- This thread wakes up occasionally to make sure the tree is in good shape. -}
|
||||||
sanityCheckerThread :: NamedThread
|
sanityCheckerThread :: NamedThread
|
||||||
sanityCheckerThread = NamedThread "SanityChecker" $ forever $ do
|
sanityCheckerThread = namedThread "SanityChecker" $ forever $ do
|
||||||
waitForNextCheck
|
waitForNextCheck
|
||||||
|
|
||||||
debug ["starting sanity check"]
|
debug ["starting sanity check"]
|
||||||
|
|
|
@ -19,7 +19,7 @@ import qualified Data.Map as M
|
||||||
{- This thread polls the status of ongoing transfers, determining how much
|
{- This thread polls the status of ongoing transfers, determining how much
|
||||||
- of each transfer is complete. -}
|
- of each transfer is complete. -}
|
||||||
transferPollerThread :: NamedThread
|
transferPollerThread :: NamedThread
|
||||||
transferPollerThread = NamedThread "TransferPoller" $ do
|
transferPollerThread = namedThread "TransferPoller" $ do
|
||||||
g <- liftAnnex gitRepo
|
g <- liftAnnex gitRepo
|
||||||
tn <- liftIO . newNotificationHandle =<<
|
tn <- liftIO . newNotificationHandle =<<
|
||||||
transferNotifier <$> getDaemonStatus
|
transferNotifier <$> getDaemonStatus
|
||||||
|
|
|
@ -31,7 +31,7 @@ import qualified Data.Set as S
|
||||||
- that need to be made, to keep data in sync.
|
- that need to be made, to keep data in sync.
|
||||||
-}
|
-}
|
||||||
transferScannerThread :: NamedThread
|
transferScannerThread :: NamedThread
|
||||||
transferScannerThread = NamedThread "TransferScanner" $ do
|
transferScannerThread = namedThread "TransferScanner" $ do
|
||||||
startupScan
|
startupScan
|
||||||
go S.empty
|
go S.empty
|
||||||
where
|
where
|
||||||
|
|
|
@ -22,7 +22,7 @@ import Control.Concurrent
|
||||||
{- This thread watches for changes to the gitAnnexTransferDir,
|
{- This thread watches for changes to the gitAnnexTransferDir,
|
||||||
- and updates the DaemonStatus's map of ongoing transfers. -}
|
- and updates the DaemonStatus's map of ongoing transfers. -}
|
||||||
transferWatcherThread :: NamedThread
|
transferWatcherThread :: NamedThread
|
||||||
transferWatcherThread = NamedThread "TransferWatcher" $ do
|
transferWatcherThread = namedThread "TransferWatcher" $ do
|
||||||
dir <- liftAnnex $ gitAnnexTransferDir <$> gitRepo
|
dir <- liftAnnex $ gitAnnexTransferDir <$> gitRepo
|
||||||
liftIO $ createDirectoryIfMissing True dir
|
liftIO $ createDirectoryIfMissing True dir
|
||||||
let hook a = Just <$> asIO2 (runHandler a)
|
let hook a = Just <$> asIO2 (runHandler a)
|
||||||
|
|
|
@ -25,7 +25,7 @@ import System.Process (create_group)
|
||||||
|
|
||||||
{- Dispatches transfers from the queue. -}
|
{- Dispatches transfers from the queue. -}
|
||||||
transfererThread :: NamedThread
|
transfererThread :: NamedThread
|
||||||
transfererThread = NamedThread "Transferr" $ do
|
transfererThread = namedThread "Transferrer" $ do
|
||||||
program <- liftIO readProgramFile
|
program <- liftIO readProgramFile
|
||||||
forever $ inTransferSlot $
|
forever $ inTransferSlot $
|
||||||
maybe (return Nothing) (uncurry $ startTransfer program)
|
maybe (return Nothing) (uncurry $ startTransfer program)
|
||||||
|
|
|
@ -59,7 +59,7 @@ needLsof = error $ unlines
|
||||||
]
|
]
|
||||||
|
|
||||||
watchThread :: NamedThread
|
watchThread :: NamedThread
|
||||||
watchThread = NamedThread "Watcher" $ do
|
watchThread = namedThread "Watcher" $ do
|
||||||
startup <- asIO1 startupScan
|
startup <- asIO1 startupScan
|
||||||
direct <- liftAnnex isDirect
|
direct <- liftAnnex isDirect
|
||||||
addhook <- hook $ if direct then onAddDirect else onAdd
|
addhook <- hook $ if direct then onAddDirect else onAdd
|
||||||
|
|
|
@ -38,9 +38,6 @@ import Yesod.Static
|
||||||
import Network.Socket (SockAddr)
|
import Network.Socket (SockAddr)
|
||||||
import Data.Text (pack, unpack)
|
import Data.Text (pack, unpack)
|
||||||
|
|
||||||
thisThread :: String
|
|
||||||
thisThread = "WebApp"
|
|
||||||
|
|
||||||
mkYesodDispatch "WebApp" $(parseRoutesFile "Assistant/WebApp/routes")
|
mkYesodDispatch "WebApp" $(parseRoutesFile "Assistant/WebApp/routes")
|
||||||
|
|
||||||
type Url = String
|
type Url = String
|
||||||
|
@ -76,7 +73,7 @@ webAppThread assistantdata urlrenderer noannex postfirstrun onstartup = thread $
|
||||||
urlfile <- runThreadState st $ fromRepo gitAnnexUrlFile
|
urlfile <- runThreadState st $ fromRepo gitAnnexUrlFile
|
||||||
go addr webapp htmlshim (Just urlfile)
|
go addr webapp htmlshim (Just urlfile)
|
||||||
where
|
where
|
||||||
thread = NamedThread thisThread
|
thread = namedThread "WebApp"
|
||||||
getreldir
|
getreldir
|
||||||
| noannex = return Nothing
|
| noannex = return Nothing
|
||||||
| otherwise = Just <$>
|
| otherwise = Just <$>
|
||||||
|
|
|
@ -34,7 +34,7 @@ import qualified Git.Branch
|
||||||
import Data.Time.Clock
|
import Data.Time.Clock
|
||||||
|
|
||||||
xmppClientThread :: UrlRenderer -> NamedThread
|
xmppClientThread :: UrlRenderer -> NamedThread
|
||||||
xmppClientThread urlrenderer = NamedThread "XMPPClient" $
|
xmppClientThread urlrenderer = namedThread "XMPPClient" $
|
||||||
restartableClient . xmppClient urlrenderer =<< getAssistant id
|
restartableClient . xmppClient urlrenderer =<< getAssistant id
|
||||||
|
|
||||||
{- Runs the client, handing restart events. -}
|
{- Runs the client, handing restart events. -}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import Assistant.Alert
|
||||||
import Assistant.Pairing
|
import Assistant.Pairing
|
||||||
import Utility.NotificationBroadcaster
|
import Utility.NotificationBroadcaster
|
||||||
import Logs.Transfer
|
import Logs.Transfer
|
||||||
|
import Assistant.Types.ThreadName
|
||||||
|
|
||||||
import Control.Concurrent.STM
|
import Control.Concurrent.STM
|
||||||
import Control.Concurrent.Async
|
import Control.Concurrent.Async
|
||||||
|
@ -21,8 +22,9 @@ import Data.Time.Clock.POSIX
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
|
|
||||||
data DaemonStatus = DaemonStatus
|
data DaemonStatus = DaemonStatus
|
||||||
-- All the named threads that comprise the daemon.
|
-- All the named threads that comprise the daemon,
|
||||||
{ startedThreads :: M.Map String (Async ())
|
-- and actions to run to restart them.
|
||||||
|
{ startedThreads :: M.Map ThreadName (Async (), IO ())
|
||||||
-- False when the daemon is performing its startup scan
|
-- False when the daemon is performing its startup scan
|
||||||
, scanComplete :: Bool
|
, scanComplete :: Bool
|
||||||
-- Time when a previous process of the daemon was running ok
|
-- Time when a previous process of the daemon was running ok
|
||||||
|
|
17
Assistant/Types/NamedThread.hs
Normal file
17
Assistant/Types/NamedThread.hs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{- named threads
|
||||||
|
-
|
||||||
|
- Copyright 2012 Joey Hess <joey@kitenet.net>
|
||||||
|
-
|
||||||
|
- Licensed under the GNU GPL version 3 or higher.
|
||||||
|
-}
|
||||||
|
|
||||||
|
module Assistant.Types.NamedThread where
|
||||||
|
|
||||||
|
import Assistant.Monad
|
||||||
|
import Assistant.Types.ThreadName
|
||||||
|
|
||||||
|
{- Information about a named thread that can be run. -}
|
||||||
|
data NamedThread = NamedThread ThreadName (Assistant ())
|
||||||
|
|
||||||
|
namedThread :: String -> Assistant () -> NamedThread
|
||||||
|
namedThread name a = NamedThread (ThreadName name) a
|
14
Assistant/Types/ThreadName.hs
Normal file
14
Assistant/Types/ThreadName.hs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{- name of a thread
|
||||||
|
-
|
||||||
|
- Copyright 2012 Joey Hess <joey@kitenet.net>
|
||||||
|
-
|
||||||
|
- Licensed under the GNU GPL version 3 or higher.
|
||||||
|
-}
|
||||||
|
|
||||||
|
module Assistant.Types.ThreadName where
|
||||||
|
|
||||||
|
newtype ThreadName = ThreadName String
|
||||||
|
deriving (Eq, Read, Show, Ord)
|
||||||
|
|
||||||
|
fromThreadName :: ThreadName -> String
|
||||||
|
fromThreadName (ThreadName n) = n
|
|
@ -12,9 +12,11 @@ module Assistant.WebApp.Control where
|
||||||
import Assistant.WebApp.Common
|
import Assistant.WebApp.Common
|
||||||
import Locations.UserConfig
|
import Locations.UserConfig
|
||||||
import Utility.LogFile
|
import Utility.LogFile
|
||||||
|
import Assistant.DaemonStatus
|
||||||
|
|
||||||
import Control.Concurrent
|
import Control.Concurrent
|
||||||
import System.Posix (getProcessID, signalProcess, sigTERM)
|
import System.Posix (getProcessID, signalProcess, sigTERM)
|
||||||
|
import qualified Data.Map as M
|
||||||
|
|
||||||
getShutdownR :: Handler RepHtml
|
getShutdownR :: Handler RepHtml
|
||||||
getShutdownR = page "Shutdown" Nothing $
|
getShutdownR = page "Shutdown" Nothing $
|
||||||
|
@ -42,6 +44,12 @@ getRestartR = page "Restarting" Nothing $ do
|
||||||
restartcommand program = program ++ " assistant --stop; " ++
|
restartcommand program = program ++ " assistant --stop; " ++
|
||||||
program ++ " webapp"
|
program ++ " webapp"
|
||||||
|
|
||||||
|
getRestartThreadR :: ThreadName -> Handler ()
|
||||||
|
getRestartThreadR name = do
|
||||||
|
m <- liftAssistant $ startedThreads <$> getDaemonStatus
|
||||||
|
liftIO $ maybe noop snd $ M.lookup name m
|
||||||
|
redirectBack
|
||||||
|
|
||||||
getLogR :: Handler RepHtml
|
getLogR :: Handler RepHtml
|
||||||
getLogR = page "Logs" Nothing $ do
|
getLogR = page "Logs" Nothing $ do
|
||||||
logfile <- lift $ runAnnex undefined $ fromRepo gitAnnexLogFile
|
logfile <- lift $ runAnnex undefined $ fromRepo gitAnnexLogFile
|
||||||
|
|
|
@ -131,3 +131,7 @@ instance PathPiece RepoListNotificationId where
|
||||||
instance PathPiece RepoSelector where
|
instance PathPiece RepoSelector where
|
||||||
toPathPiece = pack . show
|
toPathPiece = pack . show
|
||||||
fromPathPiece = readish . unpack
|
fromPathPiece = readish . unpack
|
||||||
|
|
||||||
|
instance PathPiece ThreadName where
|
||||||
|
toPathPiece = pack . show
|
||||||
|
fromPathPiece = readish . unpack
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
/shutdown ShutdownR GET
|
/shutdown ShutdownR GET
|
||||||
/shutdown/confirm ShutdownConfirmedR GET
|
/shutdown/confirm ShutdownConfirmedR GET
|
||||||
/restart RestartR GET
|
/restart RestartR GET
|
||||||
|
/restart/thread/#ThreadName RestartThreadR GET
|
||||||
/log LogR GET
|
/log LogR GET
|
||||||
|
|
||||||
/config ConfigurationR GET
|
/config ConfigurationR GET
|
||||||
|
|
|
@ -110,7 +110,7 @@ firstRun = do
|
||||||
v <- newEmptyMVar
|
v <- newEmptyMVar
|
||||||
let callback a = Just $ a v
|
let callback a = Just $ a v
|
||||||
runAssistant d $ do
|
runAssistant d $ do
|
||||||
startNamedThread $
|
startNamedThread (Just urlrenderer) $
|
||||||
webAppThread d urlrenderer True
|
webAppThread d urlrenderer True
|
||||||
(callback signaler)
|
(callback signaler)
|
||||||
(callback mainthread)
|
(callback mainthread)
|
||||||
|
|
6
debian/changelog
vendored
6
debian/changelog
vendored
|
@ -1,3 +1,9 @@
|
||||||
|
git-annex (3.20130125) UNRELEASED; urgency=low
|
||||||
|
|
||||||
|
* webapp: Now allows restarting any threads that crash.
|
||||||
|
|
||||||
|
-- Joey Hess <joeyh@debian.org> Sat, 26 Jan 2013 15:48:40 +1100
|
||||||
|
|
||||||
git-annex (3.20130124) unstable; urgency=low
|
git-annex (3.20130124) unstable; urgency=low
|
||||||
|
|
||||||
* Added source repository group, that only retains files until they've
|
* Added source repository group, that only retains files until they've
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
Name: git-annex
|
Name: git-annex
|
||||||
Version: 3.20130124
|
Version: 3.20130125
|
||||||
Cabal-Version: >= 1.8
|
Cabal-Version: >= 1.8
|
||||||
License: GPL
|
License: GPL
|
||||||
Maintainer: Joey Hess <joey@kitenet.net>
|
Maintainer: Joey Hess <joey@kitenet.net>
|
||||||
|
|
Loading…
Reference in a new issue