diff --git a/Changelog.md b/Changelog.md
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,3 +1,16 @@
+### 1.0
+
+- Module *NgxExport.Tools.Aggregate* can now be built without support from the
+  *Snap framework* (flag *SnapAggregateServer* replaces flag *Aggregate*). The
+  module now allows building native Nginx-based aggregate services (see updated
+  docs).
+- In module *NgxExport.Tools.Aggregate*, getting current time with *ngxNow* was
+  replaced by *getCurrentTime* because the former is not safe in the async
+  context.
+- Removed upper bound restriction in the Cabal constraint on the version of
+  package *aeson*.
+- Package stability tag was promoted to stable.
+
 ### 0.8.2.0
 
 - In module *NgxExport.Tools.Subrequest*, bridged HTTP subrequests return status
diff --git a/NgxExport/Tools/Aggregate.hs b/NgxExport/Tools/Aggregate.hs
--- a/NgxExport/Tools/Aggregate.hs
+++ b/NgxExport/Tools/Aggregate.hs
@@ -1,13 +1,14 @@
-{-# LANGUAGE TemplateHaskell, OverloadedStrings, BangPatterns #-}
+{-# LANGUAGE CPP, TemplateHaskell, ScopedTypeVariables #-}
+{-# LANGUAGE OverloadedStrings, BangPatterns #-}
 
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  NgxExport.Tools.Aggregate
--- Copyright   :  (c) Alexey Radkov 2019-2020
+-- Copyright   :  (c) Alexey Radkov 2019-2021
 -- License     :  BSD-style
 --
 -- Maintainer  :  alexey.radkov@gmail.com
--- Stability   :  experimental
+-- Stability   :  stable
 -- Portability :  non-portable (requires Template Haskell)
 --
 -- An aggregate service from the more extra tools collection for
@@ -19,8 +20,13 @@
 module NgxExport.Tools.Aggregate (
     -- * The typed service exporter
     -- $aggregateServiceExporter
-                                  AggregateServerConf
-                                 ,ngxExportAggregateService
+#ifdef SNAP_AGGREGATE_SERVER
+                                  AggregateServerConf,
+#endif
+                                  ngxExportAggregateService
+    -- * Nginx-based aggregate service
+    -- $nginxBasedAggregateService
+
     -- * The worker-side reporter
                                  ,reportAggregate
     -- * Re-exported data constructors from /Foreign.C/
@@ -29,6 +35,7 @@
                                  ,Foreign.C.Types.CUInt (..)
                                  ) where
 
+import           NgxExport
 import           NgxExport.Tools
 
 import           Language.Haskell.TH
@@ -42,22 +49,33 @@
 import qualified Data.Map.Strict as M
 import           Data.IORef
 import           Data.Int
-import qualified Data.Text as T
-import qualified Data.Text.Encoding as T
-import           Data.Time.Clock.POSIX
+#if MIN_VERSION_time(1,9,1)
+import           Data.Fixed
+#endif
+import           Data.Time.Clock
+import           Data.Time.Calendar
 import           Data.Aeson
 import           Data.Maybe
 import           Control.Monad
-import           Control.Monad.IO.Class
-import           Control.Arrow
 import           Control.Exception
-import           Control.Exception.Enclosed (handleAny)
 import           System.IO.Unsafe
+import           Safe
+
+#ifdef SNAP_AGGREGATE_SERVER
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as T
+import           Control.Monad.IO.Class
+import           Control.Exception.Enclosed (handleAny)
 import           Snap.Http.Server
 import           Snap.Core
+#endif
 
-type Aggregate a = IORef (CTime, Map Int32 (CTime, Maybe a))
 
+type AggregateValue a = (UTCTime, Map Int32 (UTCTime, Maybe a))
+type Aggregate a = IORef (AggregateValue a)
+
+type ReportValue a = Maybe (Int32, Maybe a)
+
 -- $aggregateServiceExporter
 --
 -- An aggregate service collects custom typed data reported by worker processes
@@ -214,39 +232,39 @@
 -- As far as /reportStats/ is a deferred service, we won't get useful data in 5
 -- seconds after Nginx start.
 --
--- > $ curl 'http://127.0.0.1:8020/' | jq
+-- > $ curl -s 'http://127.0.0.1:8020/' | jq
 -- > [
--- >   "1970-01-01T00:00:00Z",
+-- >   "1858-11-17T00:00:00Z",
 -- >   {}
 -- > ]
 --
 -- However, later we should get some useful data.
 --
--- > $ curl 'http://127.0.0.1:8020/' | jq
+-- > $ curl -s 'http://127.0.0.1:8020/' | jq
 -- > [
--- >   "2019-04-22T14:19:04Z",
+-- >   "2021-12-08T09:56:18.118132083Z",
 -- >   {
--- >     "5910": [
--- >       "2019-04-22T14:19:19Z",
+-- >     "21651": [
+-- >       "2021-12-08T09:56:18.12155413Z",
 -- >       {
--- >         "bytesSent": 0,
+-- >         "meanBytesSent": 0,
 -- >         "requests": 0,
--- >         "meanBytesSent": 0
+-- >         "bytesSent": 0
 -- >       }
 -- >     ],
--- >     "5911": [
--- >       "2019-04-22T14:19:14Z",
+-- >     "21652": [
+-- >       "2021-12-08T09:56:18.118132083Z",
 -- >       {
--- >         "bytesSent": 0,
+-- >         "meanBytesSent": 0,
 -- >         "requests": 0,
--- >         "meanBytesSent": 0
+-- >         "bytesSent": 0
 -- >       }
 -- >     ]
 -- >   }
 -- > ]
 --
 -- Here we have collected stats from the two Nginx worker processes with /PIDs/
--- /5910/ and /5911/. The timestamps show when the stats was updated the last
+-- /21651/ and /21652/. The timestamps show when the stats was updated the last
 -- time. The topmost timestamp shows the time of the latest /purge/ event. The
 -- data itself have only zeros as soon we have made no request to the main
 -- server so far. Let's run 100 simultaneous requests and look at the stats (it
@@ -256,29 +274,89 @@
 --
 -- Wait 5 seconds...
 --
--- > $ curl 'http://127.0.0.1:8020/' | jq
+-- > $ curl -s 'http://127.0.0.1:8020/' | jq
 -- > [
--- >   "2019-04-22T14:29:04Z",
+-- >   "2021-12-08T09:56:18.118132083Z",
 -- >   {
--- >     "5910": [
--- >       "2019-04-22T14:31:34Z",
+-- >     "21651": [
+-- >       "2021-12-08T09:56:48.159263993Z",
 -- >       {
--- >         "bytesSent": 17751,
--- >         "requests": 97,
--- >         "meanBytesSent": 183
+-- >         "meanBytesSent": 183,
+-- >         "requests": 84,
+-- >         "bytesSent": 15372
 -- >       }
 -- >     ],
--- >     "5911": [
--- >       "2019-04-22T14:31:31Z",
+-- >     "21652": [
+-- >       "2021-12-08T09:56:48.136934713Z",
 -- >       {
--- >         "bytesSent": 549,
--- >         "requests": 3,
--- >         "meanBytesSent": 183
+-- >         "meanBytesSent": 183,
+-- >         "requests": 16,
+-- >         "bytesSent": 2928
 -- >       }
 -- >     ]
 -- >   }
 -- > ]
 
+throwUserError :: String -> IO a
+throwUserError = ioError . userError
+
+#if MIN_VERSION_time(1,9,1)
+asIntegerPart :: forall a. HasResolution a => Integer -> Fixed a
+asIntegerPart = MkFixed . (resolution (undefined :: Fixed a) *)
+{-# SPECIALIZE INLINE asIntegerPart :: Integer -> Pico #-}
+#endif
+
+toNominalDiffTime :: TimeInterval -> NominalDiffTime
+toNominalDiffTime =
+#if MIN_VERSION_time(1,9,1)
+    secondsToNominalDiffTime . asIntegerPart
+#else
+    fromRational . toRational . secondsToDiffTime
+#endif
+    . fromIntegral . toSec
+
+updateAggregate :: Aggregate a -> ReportValue a -> NominalDiffTime -> IO ()
+updateAggregate a s int = do
+    let (pid, v) = fromJust s
+    !t <- getCurrentTime
+    atomicModifyIORef' a $
+        \(t', v') ->
+            (let (!tn, f) =
+                     if diffUTCTime t t' >= int
+                         then (t
+                              ,M.filter $
+                                  \(t'', _) -> diffUTCTime t t'' < int
+                              )
+                         else (t', id)
+                 !vn = f $ M.alter
+                           (\old ->
+                               let !new' = if isNothing old || isJust v
+                                               then v
+                                               else snd $ fromJust old
+                               in Just (t, new')
+                           ) pid v'
+             in (tn, vn)
+            ,()
+            )
+
+receiveAggregate :: FromJSON a =>
+    Aggregate a -> L.ByteString -> ByteString -> IO L.ByteString
+receiveAggregate a v sint = do
+    let !s = decode' v
+        !int = toNominalDiffTime $ readDef (Min 5) $ C8.unpack sint
+    when (isNothing s) $ throwUserError "Unreadable aggregate!"
+    updateAggregate a (fromJust s) int
+    return "done"
+
+sendAggregate :: ToJSON a =>
+    Aggregate a -> ByteString -> IO ContentHandlerResult
+sendAggregate a = const $ do
+    s <- readIORef a
+    return (encode s, "text/plain", 200, [])
+
+
+#ifdef SNAP_AGGREGATE_SERVER
+
 -- | Configuration of an aggregate service.
 --
 -- This type is exported because Template Haskell requires that. Though its
@@ -292,8 +370,9 @@
 -- @
 --
 -- The value of /asPort/ corresponds to the TCP port of the internal aggregate
--- server. The /asPurgeInterval/ is the /purge/ interval. An aggregate service
--- should sometimes purge data from worker processes which did not report for a
+-- server (the IP address of the internal server is always /127.0.0.1/). The
+-- /asPurgeInterval/ is the /purge/ interval. An aggregate service should
+-- sometimes purge data from worker processes which have not reported for a
 -- long time. For example, it makes no sense to keep data from workers that
 -- have already been terminated. The inactive PIDs get checked every
 -- /asPurgeInterval/, and data which correspond to PIDs with timestamps older
@@ -308,8 +387,10 @@
 
 aggregateServer :: (FromJSON a, ToJSON a) =>
     Aggregate a -> ByteString -> AggregateServerConf -> Bool -> IO L.ByteString
-aggregateServer a u = ignitionService $ \conf ->
-    simpleHttpServe (asConfig $ asPort conf) (asHandler a u conf) >> return ""
+aggregateServer a u = ignitionService $ \conf -> do
+    let !int = toNominalDiffTime $ asPurgeInterval conf
+    simpleHttpServe (asConfig $ asPort conf) $ asHandler a u int
+    return ""
 
 asConfig :: Int -> Config Snap a
 asConfig p = setPort p
@@ -319,48 +400,30 @@
            $ setVerbose False mempty
 
 asHandler :: (FromJSON a, ToJSON a) =>
-    Aggregate a -> ByteString -> AggregateServerConf -> Snap ()
-asHandler a u conf =
-    route [(B.append "put/" u, Snap.Core.method POST $ receiveAggregate a conf)
-          ,(B.append "get/" u, Snap.Core.method GET $ sendAggregate a)
+    Aggregate a -> ByteString -> NominalDiffTime -> Snap ()
+asHandler a u int =
+    route [(B.append "put/" u
+           ,Snap.Core.method POST $ receiveAggregateSnap a int
+           )
+          ,(B.append "get/" u
+           ,Snap.Core.method GET $ sendAggregateSnap a
+           )
           ]
 
-receiveAggregate :: FromJSON a =>
-    Aggregate a -> AggregateServerConf -> Snap ()
-receiveAggregate a conf =
+receiveAggregateSnap :: FromJSON a => Aggregate a -> NominalDiffTime -> Snap ()
+receiveAggregateSnap a int =
     handleAggregateExceptions "Exception while receiving aggregate" $ do
         !s <- decode' <$> readRequestBody 65536
         when (isNothing s) $ liftIO $ throwUserError "Unreadable aggregate!"
-        liftIO $ do
-            let (pid, v) = fromJust s
-                int = fromIntegral . toSec . asPurgeInterval $ conf
-            !t <- ngxNow
-            atomicModifyIORef' a $
-                \(t', v') ->
-                    (let (!tn, f) =
-                             if t - t' >= int
-                                 then (t, M.filter $ \(t'', _) -> t - t'' < int)
-                                 else (t', id)
-                         !vn = f $ M.alter
-                                   (\old ->
-                                       let !new' =
-                                               if isNothing old || isJust v
-                                                   then v
-                                                   else snd $ fromJust old
-                                       in Just (t, new')
-                                   ) pid v'
-                     in (tn, vn)
-                    ,()
-                    )
+        liftIO $ updateAggregate a (fromJust s) int
         finishWith emptyResponse
 
-sendAggregate :: ToJSON a => Aggregate a -> Snap ()
-sendAggregate a =
+sendAggregateSnap :: ToJSON a => Aggregate a -> Snap ()
+sendAggregateSnap a =
     handleAggregateExceptions "Exception while sending aggregate" $ do
         s <- liftIO $ readIORef a
         modifyResponse $ setContentType "application/json"
-        writeLBS $ encode $ (toUTCTime *** M.map (first toUTCTime)) s
-    where toUTCTime (CTime t) = posixSecondsToUTCTime $ fromIntegral t
+        writeLBS $ encode s
 
 handleAggregateExceptions :: String -> Snap () -> Snap ()
 handleAggregateExceptions cmsg = handleAny $ \e ->
@@ -369,9 +432,9 @@
               modifyResponse $ setResponseStatus c $ T.encodeUtf8 $ T.pack cmsg
               writeBS $ T.encodeUtf8 $ T.pack msg
 
-throwUserError :: String -> IO a
-throwUserError = ioError . userError
+#endif
 
+
 -- | Exports a simple aggregate service with specified name and the aggregate
 --   type.
 --
@@ -393,34 +456,159 @@
                           -> Name         -- ^ Name of the aggregate type
                           -> Q [Dec]
 ngxExportAggregateService f a = do
-    let nameF = 'aggregateServer
+    let sName = mkName $ "aggregate_storage_" ++ f
+        storage = varE sName
+#ifdef SNAP_AGGREGATE_SERVER
+        nameF = 'aggregateServer
         fName = mkName $ "aggregate_" ++ f
-        sName = mkName $ "aggregate_storage_" ++ f
         uName = mkName $ "aggregate_url_" ++ f
+#endif
+        nameRecv = 'receiveAggregate
+        recvName = mkName $ "receiveAggregate_" ++ f
+        nameSend = 'sendAggregate
+        sendName = mkName $ "sendAggregate_" ++ f
     concat <$> sequence
         [sequence
-            [sigD uName [t|ByteString|]
-            ,funD uName [clause [] (normalB [|C8.pack f|]) []]
-            ,sigD sName [t|Aggregate $(conT a)|]
+            [sigD sName [t|Aggregate $(conT a)|]
             ,funD sName
                 [clause []
-                    (normalB [|unsafePerformIO $ newIORef (0, M.empty)|])
+                    (normalB [|unsafePerformIO $
+                                 newIORef (UTCTime (ModifiedJulianDay 0) 0
+                                          ,M.empty
+                                          )
+                             |]
+                    )
                     []
                 ]
             ,pragInlD sName NoInline FunLike AllPhases
+#ifdef SNAP_AGGREGATE_SERVER
+            ,sigD uName [t|ByteString|]
+            ,funD uName [clause [] (normalB [|C8.pack f|]) []]
             ,sigD fName [t|AggregateServerConf -> Bool -> IO L.ByteString|]
             ,funD fName
                 [clause []
-                    (normalB [|$(varE nameF) $(varE sName) $(varE uName)|])
+                    (normalB [|$(varE nameF) $(storage) $(varE uName)|])
                     []
                 ]
+#endif
+            ,sigD recvName [t|L.ByteString -> ByteString -> IO L.ByteString|]
+            ,funD recvName
+                [clause []
+                    (normalB [|$(varE nameRecv) $(storage)|])
+                    []
+                ]
+            ,sigD sendName [t|ByteString -> IO ContentHandlerResult|]
+            ,funD sendName
+                [clause []
+                    (normalB [|$(varE nameSend) $(storage)|])
+                    []
+                ]
             ]
+#ifdef SNAP_AGGREGATE_SERVER
         -- FIXME: name AggregateServerConf must be imported from the user's
         -- module unqualified (see details in NgxExport/Tools.hs, function
         -- ngxExportSimpleService')!
         ,ngxExportSimpleServiceTyped
             fName ''AggregateServerConf SingleShotService
+#endif
+        ,ngxExportAsyncOnReqBody recvName
+        ,ngxExportAsyncHandler sendName
         ]
+
+-- $nginxBasedAggregateService
+--
+-- Service /simpleService_aggregate_stats/ was implemented using
+-- /Snap framework/. Basically, a native Nginx implementation is not easy
+-- because the service must listen on a single (not duplicated) file descriptor
+-- which is not the case when Nginx spawns more than one worker processes.
+-- Running /simpleService_aggregate_stats/ as a shared service is an elegant
+-- solution as shared services guarantee that they occupy only one worker at a
+-- time. However, /nginx-haskell-module/ provides directive /single_listener/
+-- which can be used to apply the required restriction in a custom Nginx virtual
+-- server. This directive requires that the virtual server listens with option
+-- /reuseport/ and is only available on Linux with socket option
+-- /SO_ATTACH_REUSEPORT_CBPF/.
+--
+-- Exporter 'ngxExportAggregateService' exports additional handlers to build a
+-- native Nginx-based aggregate service. Let's replace service
+-- /simpleService_aggregate_stats/ from the previous example with such a native
+-- Nginx-based aggregate service using /single_listener/ and listening on port
+-- /8100/.
+--
+-- ==== File /nginx.conf/
+-- @
+-- user                    nobody;
+-- worker_processes        2;
+--
+-- events {
+--     worker_connections  1024;
+-- }
+--
+-- http {
+--     default_type        application\/octet-stream;
+--     sendfile            on;
+--
+--     haskell load \/var\/lib\/nginx\/test_tools_extra_aggregate.so;
+--
+--     haskell_run_service simpleService_reportStats $hs_reportStats 8100;
+--
+--     haskell_var_empty_on_error $hs_stats;
+--
+--     server {
+--         listen       8010;
+--         server_name  main;
+--         error_log    \/tmp\/nginx-test-haskell-error.log;
+--         access_log   \/tmp\/nginx-test-haskell-access.log;
+--
+--         haskell_run updateStats !$hs_updateStats $bytes_sent;
+--
+--         location \/ {
+--             echo Ok;
+--         }
+--     }
+--
+--     server {
+--         listen       8020;
+--         server_name  stat;
+--
+--         location \/ {
+--             allow 127.0.0.1;
+--             deny all;
+--             proxy_pass http:\/\/127.0.0.1:8100\/get\/stats;
+--         }
+--     }
+--
+--     server {
+--         listen          8100 __/reuseport/__;
+--         server_name     stats;
+--
+--         __/single_listener on/__;
+--
+--         location __/\/put\/stats/__ {
+--             haskell_run_async_on_request_body __/receiveAggregate_stats/__
+--                     $hs_stats \"Min 1\";
+--
+--             if ($hs_stats = \'\') {
+--                 return 400;
+--             }
+--
+--             return 200;
+--         }
+--
+--         location __/\/get\/stats/__ {
+--             haskell_async_content __/sendAggregate_stats/__ noarg;
+--         }
+--     }
+-- }
+-- @
+--
+-- Handler /receiveAggregate_stats/ accepts a time interval corresponding to the
+-- value of /asPurgeInterval/ from service /simpleService_aggregate_stats/. If
+-- the value is not readable (say, /noarg/) then it is defaulted to /Min 5/.
+--
+-- Notice that the stats server must listen on IP address /127.0.0.1/ because
+-- 'reportAggregate' (being the base of service /simpleService_reportStats/)
+-- reports stats to this address.
 
 -- | Reports data to an aggregate service.
 --
diff --git a/NgxExport/Tools/EDE.hs b/NgxExport/Tools/EDE.hs
--- a/NgxExport/Tools/EDE.hs
+++ b/NgxExport/Tools/EDE.hs
@@ -3,11 +3,11 @@
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  NgxExport.Tools.EDE
--- Copyright   :  (c) Alexey Radkov 2020
+-- Copyright   :  (c) Alexey Radkov 2020-2021
 -- License     :  BSD-style
 --
 -- Maintainer  :  alexey.radkov@gmail.com
--- Stability   :  experimental
+-- Stability   :  stable
 -- Portability :  non-portable (requires Template Haskell)
 --
 -- EDE templates for parsing JSON objects from the more extra tools collection
@@ -29,7 +29,7 @@
 
 import           Text.EDE
 import           Text.EDE.Filters
-#if EDE_USE_PRETTYPRINTER
+#ifdef EDE_USE_PRETTYPRINTER
 #if MIN_VERSION_prettyprinter(1,7,0)
 import           Prettyprinter (unAnnotate)
 #else
@@ -275,7 +275,7 @@
                         Failure msg -> throwIO $ EDERenderError $ showPlain msg
                         Success r -> return $ LT.encodeUtf8 r
     where showPlain = show .
-#if EDE_USE_PRETTYPRINTER
+#ifdef EDE_USE_PRETTYPRINTER
               unAnnotate
 #else
               plain
diff --git a/NgxExport/Tools/PCRE.hs b/NgxExport/Tools/PCRE.hs
--- a/NgxExport/Tools/PCRE.hs
+++ b/NgxExport/Tools/PCRE.hs
@@ -10,7 +10,7 @@
 -- License     :  BSD-style
 --
 -- Maintainer  :  alexey.radkov@gmail.com
--- Stability   :  experimental
+-- Stability   :  stable
 -- Portability :  non-portable (requires Template Haskell)
 --
 -- PCRE matching and substitution from the more extra tools collection
diff --git a/NgxExport/Tools/Prometheus.hs b/NgxExport/Tools/Prometheus.hs
--- a/NgxExport/Tools/Prometheus.hs
+++ b/NgxExport/Tools/Prometheus.hs
@@ -4,11 +4,11 @@
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  NgxExport.Tools.Prometheus
--- Copyright   :  (c) Alexey Radkov 2020
+-- Copyright   :  (c) Alexey Radkov 2020-2021
 -- License     :  BSD-style
 --
 -- Maintainer  :  alexey.radkov@gmail.com
--- Stability   :  experimental
+-- Stability   :  stable
 -- Portability :  non-portable (requires Template Haskell)
 --
 -- Prometheus metrics from the more extra tools collection for
@@ -440,8 +440,7 @@
     writeIORef conf $ Just a
     return ""
 
-ngxExportSimpleServiceTyped
-    'prometheusConf ''PrometheusConf SingleShotService
+ngxExportSimpleServiceTyped 'prometheusConf ''PrometheusConf SingleShotService
 
 toPrometheusMetrics' :: PrometheusConf -> AllMetrtics -> PrometheusMetrics
 toPrometheusMetrics' PrometheusConf {..} (srv, cnts, hs, ocnts) =
@@ -934,50 +933,50 @@
 --                     ,\"__/hst_request_time\@scope=(in_upstreams)_sum/__\"
 --                     ]
 --                 }\';
--- 
+--
 -- @
 -- @
 --         counter $__/cnt_status\@value=(4xx),from=(response)/__ inc $inc_cnt_4xx;
 --         counter $__/cnt_status\@value=(5xx),from=(response)/__ inc $inc_cnt_5xx;
--- 
+--
 --         haskell_run statusLayout $hs_upstream_status $upstream_status;
 --         counter $__/cnt_status\@value=(4xx),from=(upstream)/__ inc $inc_cnt_u_4xx;
 --         counter $__/cnt_status\@value=(5xx),from=(upstream)/__ inc $inc_cnt_u_5xx;
--- 
+--
 --         # cache $request_time and $bytes_sent
 --         haskell_run ! $hs_request_time $request_time;
 --         haskell_run ! $hs_bytes_sent $bytes_sent;
--- 
+--
 --         histogram $__/hst_request_time\@scope=(total)/__ 11 $request_time_bucket;
 --         haskell_run scale1000 $hs_request_time_scaled $hs_request_time;
 --         counter $hst_request_time\@scope=(total)_sum inc $hs_request_time_scaled;
--- 
+--
 --         histogram $hst_bytes_sent 6 $bytes_sent_bucket;
 --         counter $hst_bytes_sent_sum inc $hs_bytes_sent;
--- 
+--
 --         # cache $upstream_response_time
 --         haskell_run ! $hs_u_response_times $upstream_response_time;
--- 
+--
 --         histogram $__/hst_request_time\@scope=(in_upstreams)/__ 11
 --                 $u_response_time_bucket;
 --         histogram $__/hst_request_time\@scope=(in_upstreams)/__ undo;
 --         haskell_run cumulativeFPValue $hs_u_response_time $hs_u_response_times;
 --         haskell_run scale1000 $hs_u_response_time_scaled $hs_u_response_time;
--- 
+--
 --         location \/ {
 --             echo_sleep 0.5;
 --             echo Ok;
 --         }
--- 
+--
 --         location \/1 {
 --             echo_sleep 1.0;
 --             echo Ok;
 --         }
--- 
+--
 --         location \/404 {
 --             return 404;
 --         }
--- 
+--
 --         location \/backends {
 --             histogram $__/hst_request_time\@scope=(in_upstreams)/__ reuse;
 --             counter $__/hst_request_time\@scope=(in_upstreams)_sum/__ inc
@@ -986,7 +985,7 @@
 --             proxy_intercept_errors on;
 --             proxy_pass http:\/\/backends;
 --         }
--- 
+--
 --         location \@status404 {
 --             histogram $__/hst_request_time\@scope=(in_upstreams)/__ reuse;
 --             counter $__/hst_request_time\@scope=(in_upstreams)_sum/__ inc
@@ -1011,7 +1010,7 @@
 -- > $ for i in {1..20} ; do curl -D- 'http://localhost:8010/backends' & done
 -- >   ...
 --
--- > $ curl -s 'http://localhost:8020/' 
+-- > $ curl -s 'http://localhost:8020/'
 -- > # HELP cnt_status Number of responses with given status
 -- > # TYPE cnt_status counter
 -- > cnt_status{value="4xx",from="response"} 11.0
@@ -1072,3 +1071,4 @@
 -- > # TYPE hst_request_time_err counter
 -- > hst_request_time_err{scope="in_upstreams"} 0.0
 -- > hst_request_time_err{scope="total"} 0.0
+
diff --git a/NgxExport/Tools/ServiceHookAdaptor.hs b/NgxExport/Tools/ServiceHookAdaptor.hs
--- a/NgxExport/Tools/ServiceHookAdaptor.hs
+++ b/NgxExport/Tools/ServiceHookAdaptor.hs
@@ -7,7 +7,7 @@
 -- License     :  BSD-style
 --
 -- Maintainer  :  alexey.radkov@gmail.com
--- Stability   :  experimental
+-- Stability   :  stable
 -- Portability :  non-portable (requires Template Haskell)
 --
 -- A service hook adaptor from the more extra tools collection for
@@ -184,5 +184,6 @@
 hookAdaptor :: ByteString -> Bool -> IO L.ByteString
 hookAdaptor = ignitionService $
     const $ forever $ threadDelaySec $ toSec $ Hr 24
+
 ngxExportSimpleService 'hookAdaptor SingleShotService
 
diff --git a/NgxExport/Tools/Subrequest.hs b/NgxExport/Tools/Subrequest.hs
--- a/NgxExport/Tools/Subrequest.hs
+++ b/NgxExport/Tools/Subrequest.hs
@@ -8,7 +8,7 @@
 -- License     :  BSD-style
 --
 -- Maintainer  :  alexey.radkov@gmail.com
--- Stability   :  experimental
+-- Stability   :  stable
 -- Portability :  non-portable (requires Template Haskell)
 --
 -- Easy HTTP subrequests from the more extra tools collection for
diff --git a/ngx-export-tools-extra.cabal b/ngx-export-tools-extra.cabal
--- a/ngx-export-tools-extra.cabal
+++ b/ngx-export-tools-extra.cabal
@@ -1,5 +1,5 @@
 name:                       ngx-export-tools-extra
-version:                    0.8.2.0
+version:                    1.0
 synopsis:                   More extra tools for Nginx haskell module
 description:                More extra tools for
         <https://github.com/lyokha/nginx-haskell-module Nginx haskell module>.
@@ -9,7 +9,7 @@
 extra-source-files:         Changelog.md
 author:                     Alexey Radkov <alexey.radkov@gmail.com>
 maintainer:                 Alexey Radkov <alexey.radkov@gmail.com>
-stability:                  experimental
+stability:                  stable
 copyright:                  2019-2021 Alexey Radkov
 category:                   Network
 build-type:                 Simple
@@ -19,9 +19,6 @@
   type:                     git
   location:                 https://github.com/lyokha/ngx-export-tools-extra
 
-flag Aggregate
-  description:              Build Aggregate module.
-
 flag EDE
   description:              Build EDE module.
 
@@ -33,6 +30,9 @@
 flag PCRE
   description:              Build PCRE module.
 
+flag SnapAggregateServer
+  description:              Build Snap server for Aggregate module.
+
 library
   default-language:         Haskell2010
   build-depends:            base >= 4.8 && < 5
@@ -41,10 +41,11 @@
                           , base64 >= 0.3.0.0
                           , ngx-export
                           , ngx-export-tools >= 0.4.8.0
-                          , aeson >= 1.0.0.0 && < 2.0.0.0
                           , http-types >= 0.7.0
                           , http-client >= 0.5.3
                           , network >= 2.4.0.0
+                          , aeson >= 1.0.0.0
+                          , time
                           , binary
                           , case-insensitive
                           , containers
@@ -53,11 +54,11 @@
                           , text
                           , safe
 
-  if flag(Aggregate)
+  if flag(SnapAggregateServer)
     build-depends:          snap-core
                           , snap-server
                           , enclosed-exceptions
-                          , time
+    cpp-options:           -DSNAP_AGGREGATE_SERVER
 
   if flag(EDE)
     if flag(EDEUsePrettyprinter)
@@ -69,6 +70,7 @@
       build-depends:        ede
                           , ansi-wl-pprint >= 0.6.3
                           , trifecta <= 2
+                          , aeson >= 1.0.0.0 && < 2.0.0.0
 
   if flag(PCRE)
     build-depends:          pcre-light >= 0.4
@@ -77,9 +79,7 @@
   exposed-modules:          NgxExport.Tools.Prometheus
                           , NgxExport.Tools.Subrequest
                           , NgxExport.Tools.ServiceHookAdaptor
-
-  if flag(Aggregate)
-    exposed-modules:        NgxExport.Tools.Aggregate
+                          , NgxExport.Tools.Aggregate
 
   if flag(EDE)
     exposed-modules:        NgxExport.Tools.EDE
