diff --git a/poolboy.cabal b/poolboy.cabal
--- a/poolboy.cabal
+++ b/poolboy.cabal
@@ -1,6 +1,6 @@
 cabal-version:       3.0
 name:                poolboy
-version:             0.1.0.1
+version:             0.2.0.0
 author:              Gautier DI FOLCO
 maintainer:          gautier.difolco@gmail.com
 category:            Data
@@ -18,6 +18,7 @@
       base == 4.*
     , safe-exceptions == 0.1.*
     , stm == 2.*
+    , async == 2.*
   hs-source-dirs: src
   exposed-modules:
       Data.Poolboy
diff --git a/src/Data/Poolboy.hs b/src/Data/Poolboy.hs
--- a/src/Data/Poolboy.hs
+++ b/src/Data/Poolboy.hs
@@ -10,13 +10,18 @@
     WorkQueue,
     withPoolboy,
     newPoolboy,
-    stopWorkQueue,
-    isStopWorkQueue,
 
     -- * Driving
     changeDesiredWorkersCount,
     waitReadyQueue,
 
+    -- * Stopping
+    stopWorkQueue,
+    isStopedWorkQueue,
+    WaitingStopStrategy,
+    waitingStopTimeout,
+    waitingStopFinishWorkers,
+
     -- * Enqueueing
     enqueue,
     enqueueAfter,
@@ -24,11 +29,13 @@
 where
 
 import Control.Concurrent
+import Control.Concurrent.Async
 import Control.Concurrent.STM.TQueue
 import Control.Exception.Safe (bracket, tryAny)
 import Control.Monad
 import Control.Monad.STM
-import Data.IORef
+import Data.Maybe (isNothing)
+import System.Timeout (timeout)
 
 -- | Initial settings
 data PoolboySettings = PoolboySettings
@@ -65,8 +72,8 @@
       return ()
 
 -- | 'backet'-based usage (recommended)
-withPoolboy :: PoolboySettings -> (WorkQueue -> IO a) -> IO a
-withPoolboy settings = bracket (newPoolboy settings) (\wq -> stopWorkQueue wq >> waitStopWorkQueue wq)
+withPoolboy :: PoolboySettings -> WaitingStopStrategy -> (WorkQueue -> IO a) -> IO a
+withPoolboy settings waitStopWorkQueue = bracket (newPoolboy settings) (\wq -> stopWorkQueue wq >> waitStopWorkQueue wq)
 
 -- | Standalone/manual usage
 newPoolboy :: PoolboySettings -> IO WorkQueue
@@ -75,7 +82,6 @@
     WorkQueue
       <$> newTQueueIO
       <*> newTQueueIO
-      <*> newIORef 0
       <*> newEmptyMVar
       <*> return settings.log
 
@@ -85,7 +91,7 @@
       FixedWCS x -> return x
 
   changeDesiredWorkersCount wq count
-  void $ forkIO $ controller wq
+  void $ forkIO $ controller wq []
 
   return wq
 
@@ -100,15 +106,21 @@
   atomically $ writeTQueue wq.commands Stop
 
 -- | Non-blocking check of the work queue's running status
-isStopWorkQueue :: WorkQueue -> IO Bool
-isStopWorkQueue wq =
+isStopedWorkQueue :: WorkQueue -> IO Bool
+isStopedWorkQueue wq =
   not <$> isEmptyMVar wq.stopped
 
+type WaitingStopStrategy = WorkQueue -> IO ()
+
 -- | Block until the queue is totally stopped (no more running worker)
-waitStopWorkQueue :: WorkQueue -> IO ()
-waitStopWorkQueue wq =
+waitingStopFinishWorkers :: WaitingStopStrategy
+waitingStopFinishWorkers wq =
   void $ tryAny $ readMVar wq.stopped
 
+-- | Block until the queue is totally stopped or deadline (in micro seconds) is reached
+waitingStopTimeout :: Int -> WaitingStopStrategy
+waitingStopTimeout delay wq = void $ timeout delay $ waitingStopFinishWorkers wq
+
 -- | Enqueue one action in the work queue (non-blocking)
 enqueue :: WorkQueue -> IO () -> IO ()
 enqueue wq =
@@ -132,7 +144,6 @@
 data WorkQueue = WorkQueue
   { commands :: TQueue Commands,
     queue :: TQueue (Either () (IO ())),
-    currentWorkersCount :: IORef Int,
     stopped :: MVar (),
     log :: String -> IO ()
   }
@@ -142,42 +153,40 @@
   | Stop
   deriving stock (Show)
 
-controller :: WorkQueue -> IO ()
-controller wq = do
+controller :: WorkQueue -> [Async ()]  -> IO ()
+controller wq workers = do
   command <- atomically $ readTQueue wq.commands
   let stopOneWorker = atomically $ writeTQueue wq.queue $ Left ()
+      getLiveWorkers = filterM (fmap isNothing . poll) workers
   wq.log $ "Command: " <> show command
   case command of
     ChangeDesiredWorkersCount n -> do
-      currentCount <- readIORef wq.currentWorkersCount
-      let diff = currentCount - n
-      if diff > 0
-        then replicateM_ diff stopOneWorker
-        else replicateM_ (abs diff) $ do
-          wq.log "Pre-fork"
-          forkIO $ worker wq
-      controller wq
+      liveWorkers <- getLiveWorkers
+      let diff = length liveWorkers - n
+      newWorkers <-
+        if diff > 0
+          then do
+            replicateM_ diff stopOneWorker
+            return []
+          else replicateM (abs diff) $ do
+            wq.log "Pre-fork"
+            async $ worker wq
+      controller wq $ newWorkers <> liveWorkers
     Stop -> do
-      currentCount <- readIORef wq.currentWorkersCount
+      liveWorkers <- getLiveWorkers
+      let currentCount = length liveWorkers
       wq.log $ "Stopping " <> show currentCount <> " workers"
       replicateM_ currentCount stopOneWorker
+      forM_ liveWorkers waitCatch
+      void $ tryPutMVar wq.stopped ()
 
 worker :: WorkQueue -> IO ()
 worker wq = do
   wq.log "New worker"
-  newCount <- atomicModifyIORef' wq.currentWorkersCount $ \n -> (n + 1, n + 1)
-  wq.log $ "New worker count " <> show newCount
   let loop = do
         command <- atomically $ readTQueue wq.queue
         case command of
           Left () -> do
             wq.log "Stopping"
-            remaining <-
-              atomicModifyIORef' wq.currentWorkersCount $ \n ->
-                let count = max 0 (n - 1) in (count, count)
-            wq.log $ "Remaining: " <> show remaining
-            when (remaining == 0) $
-              void $
-                tryPutMVar wq.stopped ()
           Right act -> wq.log "pop" >> void (tryAny act) >> wq.log "poped" >> loop
   loop
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -18,20 +18,16 @@
     it "threadDelay should be absorbed in mulitple threads" $ do
       computations <-
         timeout 2500 $
-          withPoolboy (poolboySettingsWith 100) $ \wq -> do
+          withPoolboy (poolboySettingsWith 100) waitingStopFinishWorkers $ \wq -> do
             replicateM_ 100 $ enqueue wq $ threadDelay 1000
-            waitReadyQueue wq
-            threadDelay 1000
       computations `shouldSatisfy` isJust
     replicateM_ 1 $
       it "should be resilient to errors and Exceptions" $ do
         witness <- newIORef False
         computations <-
           timeout 10000 $
-            withPoolboy (poolboySettingsWith 5) $ \wq -> do
+            withPoolboy (poolboySettingsWith 5) waitingStopFinishWorkers $ \wq -> do
               mapM_ (enqueue wq) [error "an error", throw RandomException, writeIORef witness True]
-              waitReadyQueue wq
-              threadDelay 100
         computations `shouldSatisfy` isJust
         readIORef witness `shouldReturn` True
 
