@@ -687,24 +687,33 @@ smpServer started cfg@ServerConfig {transports, transportConfig = tCfg, startOpt
687
687
let threadsCount = 0
688
688
#endif
689
689
clientsCount <- IM. size <$> getServerClients srv
690
- deliveredSubs <- getDeliveredMetrics
690
+ ( deliveredSubs, sumTimes, maxTime) <- getDeliveredMetrics =<< getSystemSeconds
691
691
smpSubs <- getSubscribersMetrics subscribers
692
692
ntfSubs <- getSubscribersMetrics ntfSubscribers
693
693
loadedCounts <- loadedQueueCounts $ fromMsgStore ms
694
- pure RealTimeMetrics {socketStats, threadsCount, clientsCount, deliveredSubs, smpSubs, ntfSubs, loadedCounts}
694
+ let avgTime = sumTimes `div` fromIntegral (subsCount deliveredSubs)
695
+ deliveredTimes = TimeAggregations {avgTime, maxTime}
696
+ pure RealTimeMetrics {socketStats, threadsCount, clientsCount, deliveredSubs, deliveredTimes, smpSubs, ntfSubs, loadedCounts}
695
697
where
696
698
getSubscribersMetrics ServerSubscribers {queueSubscribers, serviceSubscribers, subClients} = do
697
699
subsCount <- M. size <$> getSubscribedClients queueSubscribers
698
700
subClientsCount <- IS. size <$> readTVarIO subClients
699
701
subServicesCount <- M. size <$> getSubscribedClients serviceSubscribers
700
702
pure RTSubscriberMetrics {subsCount, subClientsCount, subServicesCount}
701
- getDeliveredMetrics = foldM countClnt (RTSubscriberMetrics 0 0 0 ) =<< getServerClients srv
702
- countClnt metrics Client {subscriptions} = do
703
- cnt <- foldM countSubs 0 =<< readTVarIO subscriptions
704
- pure $ if cnt > 0
705
- then metrics {subsCount = subsCount metrics + cnt, subClientsCount = subClientsCount metrics + 1 }
706
- else metrics
707
- countSubs ! cnt Sub {delivered} = (\ empty -> if empty then cnt else cnt + 1 ) <$> atomically (isEmptyTMVar delivered)
703
+ getDeliveredMetrics (RoundedSystemTime ts') = foldM countClnt (RTSubscriberMetrics 0 0 0 , 0 , 0 ) =<< getServerClients srv
704
+ where
705
+ countClnt acc@ (metrics, ! sumTimes, ! maxTime) Client {subscriptions} = do
706
+ (cnt, sumTimes', maxTime') <- foldM countSubs (0 , sumTimes, maxTime) =<< readTVarIO subscriptions
707
+ pure $ if cnt > 0
708
+ then (metrics {subsCount = subsCount metrics + cnt, subClientsCount = subClientsCount metrics + 1 }, sumTimes', maxTime')
709
+ else acc
710
+ countSubs acc@ (! cnt, ! sumTimes, ! maxTime) Sub {delivered} = do
711
+ delivered_ <- readTVarIO delivered
712
+ pure $ case delivered_ of
713
+ Nothing -> acc
714
+ Just (_, RoundedSystemTime ts) ->
715
+ let t = ts' - ts
716
+ in (cnt + 1 , sumTimes + t, max maxTime t)
708
717
709
718
runClient :: Transport c => X. CertificateChain -> C. APrivateSignKey -> TProxy c 'TServer -> c 'TServer -> M s ()
710
719
runClient srvCert srvSignKey tp h = do
@@ -1588,15 +1597,16 @@ client
1588
1597
pure (err (CMD PROHIBITED ), Nothing )
1589
1598
_ -> do
1590
1599
incStat $ qSubDuplicate stats
1591
- atomically (tryTakeTMVar $ delivered s) >> deliver False s
1600
+ atomically (writeTVar ( delivered s) Nothing ) >> deliver False s
1592
1601
where
1593
1602
deliver :: Bool -> Sub -> M s ResponseAndMessage
1594
1603
deliver hasSub sub = do
1595
1604
stats <- asks serverStats
1596
1605
fmap (either ((,Nothing ) . err) id ) $ liftIO $ runExceptT $ do
1597
1606
msg_ <- tryPeekMsg ms q
1598
- msg' <- forM msg_ $ \ msg -> do
1599
- void $ atomically $ setDelivered sub msg
1607
+ msg' <- forM msg_ $ \ msg -> liftIO $ do
1608
+ ts <- getSystemSeconds
1609
+ atomically $ setDelivered sub msg ts
1600
1610
unless hasSub $ incStat $ qSub stats
1601
1611
pure (NoCorrId , entId, MSG (encryptMsg qr msg))
1602
1612
pure ((corrId, entId, SOK clntServiceId), msg')
@@ -1627,7 +1637,7 @@ client
1627
1637
Just s@ Sub {subThread} ->
1628
1638
case subThread of
1629
1639
ProhibitSub ->
1630
- atomically (tryTakeTMVar $ delivered s)
1640
+ atomically (swapTVar ( delivered s) Nothing )
1631
1641
>>= getMessage_ s
1632
1642
-- cannot use GET in the same connection where there is an active subscription
1633
1643
_ -> do
@@ -1644,15 +1654,16 @@ client
1644
1654
-- This is tracked as "subscription" in the client to prevent these
1645
1655
-- clients from being able to subscribe.
1646
1656
pure s
1647
- getMessage_ :: Sub -> Maybe MsgId -> M s (Transmission BrokerMsg )
1657
+ getMessage_ :: Sub -> Maybe ( MsgId , RoundedSystemTime ) -> M s (Transmission BrokerMsg )
1648
1658
getMessage_ s delivered_ = do
1649
1659
stats <- asks serverStats
1650
1660
fmap (either err id ) $ liftIO $ runExceptT $
1651
1661
tryPeekMsg ms q >>= \ case
1652
1662
Just msg -> do
1653
1663
let encMsg = encryptMsg qr msg
1654
1664
incStat $ (if isJust delivered_ then msgGetDuplicate else msgGet) stats
1655
- atomically $ setDelivered s msg $> (corrId, entId, MSG encMsg)
1665
+ ts <- liftIO getSystemSeconds
1666
+ atomically $ setDelivered s msg ts $> (corrId, entId, MSG encMsg)
1656
1667
Nothing -> incStat (msgGetNoMsg stats) $> ok
1657
1668
1658
1669
withQueue :: (StoreQueue s -> QueueRec -> M s (Transmission BrokerMsg )) -> M s (Transmission BrokerMsg )
@@ -1760,16 +1771,18 @@ client
1760
1771
(deletedMsg_, msg_) <- tryDelPeekMsg ms q msgId
1761
1772
liftIO $ do
1762
1773
mapM_ (updateStats stats False ) deletedMsg_
1763
- mapM_ (atomically . setDelivered sub) msg_
1774
+ forM_ msg_ $ \ msg -> do
1775
+ ts <- getSystemSeconds
1776
+ atomically $ setDelivered sub msg ts
1764
1777
pure (corrId, entId, maybe OK (MSG . encryptMsg qr) msg_)
1765
1778
_ -> pure $ err NO_MSG
1766
1779
where
1767
1780
getDelivered :: Sub -> STM (Maybe ServerSub )
1768
1781
getDelivered Sub {delivered, subThread} = do
1769
- tryTakeTMVar delivered $>>= \ msgId' ->
1782
+ readTVar delivered $>>= \ ( msgId', _) ->
1770
1783
if msgId == msgId' || B. null msgId
1771
- then pure $ Just subThread
1772
- else putTMVar delivered msgId' $> Nothing
1784
+ then writeTVar delivered Nothing $> Just subThread
1785
+ else pure Nothing
1773
1786
updateStats :: ServerStats -> Bool -> Message -> IO ()
1774
1787
updateStats stats isGet = \ case
1775
1788
MessageQuota {} -> pure ()
@@ -1855,11 +1868,14 @@ client
1855
1868
-- the subscribed client var is read outside of STM to avoid transaction cost
1856
1869
-- in case no client is subscribed.
1857
1870
getSubscribedClient rId (queueSubscribers subscribers)
1858
- $>>= atomically . deliverToSub
1871
+ $>>= deliverToSub
1859
1872
>>= mapM_ forkDeliver
1860
1873
where
1861
1874
rId = recipientId q
1862
- deliverToSub rcv =
1875
+ deliverToSub rcv = do
1876
+ ts <- getSystemSeconds
1877
+ atomically $ deliverToSub_ rcv ts
1878
+ deliverToSub_ rcv ts = do
1863
1879
-- reading client TVar in the same transaction,
1864
1880
-- so that if subscription ends, it re-evalutates
1865
1881
-- and delivery is cancelled -
@@ -1870,18 +1886,18 @@ client
1870
1886
ProhibitSub -> pure Nothing
1871
1887
ServerSub st -> readTVar st >>= \ case
1872
1888
NoSub ->
1873
- tryReadTMVar delivered >>= \ case
1889
+ readTVar delivered >>= \ case
1874
1890
Just _ -> pure Nothing -- if a message was already delivered, should not deliver more
1875
1891
Nothing ->
1876
1892
ifM
1877
1893
(isFullTBQueue sndQ')
1878
1894
(writeTVar st SubPending $> Just (rc, s, st))
1879
- (deliver sndQ' s $> Nothing )
1895
+ (deliver sndQ' s ts $> Nothing )
1880
1896
_ -> pure Nothing
1881
- deliver sndQ' s = do
1897
+ deliver sndQ' s ts = do
1882
1898
let encMsg = encryptMsg qr msg
1883
1899
writeTBQueue sndQ' ([(NoCorrId , rId, MSG encMsg)], [] )
1884
- void $ setDelivered s msg
1900
+ setDelivered s msg ts
1885
1901
forkDeliver (rc@ Client {sndQ = sndQ'}, s@ Sub {delivered}, st) = do
1886
1902
t <- mkWeakThreadId =<< forkIO deliverThread
1887
1903
atomically $ modifyTVar' st $ \ case
@@ -1894,13 +1910,14 @@ client
1894
1910
-- lookup can be outside of STM transaction,
1895
1911
-- as long as the check that it is the same client is inside.
1896
1912
getSubscribedClient rId (queueSubscribers subscribers) >>= mapM_ deliverIfSame
1897
- deliverIfSame rcv = atomically $
1898
- whenM (sameClient rc rcv) $
1899
- tryReadTMVar delivered >>= \ case
1913
+ deliverIfSame rcv = do
1914
+ ts <- getSystemSeconds
1915
+ atomically $ whenM (sameClient rc rcv) $
1916
+ readTVar delivered >>= \ case
1900
1917
Just _ -> pure () -- if a message was already delivered, should not deliver more
1901
1918
Nothing -> do
1902
1919
-- a separate thread is needed because it blocks when client sndQ is full.
1903
- deliver sndQ' s
1920
+ deliver sndQ' s ts
1904
1921
writeTVar st NoSub
1905
1922
1906
1923
enqueueNotification :: NtfCreds -> Message -> M s ()
@@ -1984,8 +2001,10 @@ client
1984
2001
msgId' = messageId msg
1985
2002
msgTs' = messageTs msg
1986
2003
1987
- setDelivered :: Sub -> Message -> STM Bool
1988
- setDelivered s msg = tryPutTMVar (delivered s) $! messageId msg
2004
+ setDelivered :: Sub -> Message -> RoundedSystemTime -> STM ()
2005
+ setDelivered Sub {delivered} msg ! ts = do
2006
+ let ! msgId = messageId msg
2007
+ writeTVar delivered $ Just (msgId, ts)
1989
2008
1990
2009
delQueueAndMsgs :: (StoreQueue s , QueueRec ) -> M s (Transmission BrokerMsg )
1991
2010
delQueueAndMsgs (q, QueueRec {rcvServiceId}) = do
@@ -2026,7 +2045,7 @@ client
2026
2045
SubPending -> QSubPending
2027
2046
SubThread _ -> QSubThread
2028
2047
ProhibitSub -> pure QProhibitSub
2029
- qDelivered <- atomically $ decodeLatin1 . encode <$$> tryReadTMVar delivered
2048
+ qDelivered <- decodeLatin1 . encode . fst <$$> readTVarIO delivered
2030
2049
pure QSub {qSubThread, qDelivered}
2031
2050
2032
2051
ok :: Transmission BrokerMsg
0 commit comments