diff --git a/src/Jobs/Handler/Print.hs b/src/Jobs/Handler/Print.hs index 630a946eb..60ac7484b 100644 --- a/src/Jobs/Handler/Print.hs +++ b/src/Jobs/Handler/Print.hs @@ -18,34 +18,52 @@ import qualified Data.Text as Text -- import Database.Persist.Sql (deleteWhereCount) -- import Database.Esqueleto.Experimental ((:&)(..)) --- import qualified Database.Esqueleto.Experimental as E --- import qualified Database.Esqueleto.Legacy as E +import qualified Database.Esqueleto.Experimental as E +import qualified Database.Esqueleto.Utils as E -- import qualified Database.Esqueleto.PostgreSQL as E -- for insertSelect variant --- import qualified Database.Esqueleto.Utils as E +-- import qualified Database.Esqueleto.Legacy as E - -jobPrintAckChunkSize :: Int +jobPrintAckChunkSize :: Int jobPrintAckChunkSize = 64 +-- | Maximum length difference between received and stored apcIdent +-- APC sometimes sends ids back that are shorter than expected +apcIdentMaxDiff :: Int +apcIdentMaxDiff = 3 + -- needed, since JobPrintAck cannot requeue itself due to JobNoQueueSame (and having no parameters) dispatchJobPrintAckAgain :: JobHandler UniWorX dispatchJobPrintAckAgain = JobHandlerException act - where + where act = void $ queueJob JobPrintAck -- liftIO $ threadDelay 3e6 -- wait 3s before continuing UPDATE: no wait needed - + dispatchJobPrintAck :: JobHandler UniWorX dispatchJobPrintAck = JobHandlerException act - where + where act = do - moretodo <- runDB $ do + moretodo <- runDB $ do aliases <- selectList [] [Desc PrintAckIdAliasPriority] let ftransAliases = id : fmap (\Entity{entityVal=PrintAckIdAlias{printAckIdAliasNeedle=n, printAckIdAliasReplacement=r}} -> Text.replace n r) aliases - ackOneId ackt apci = selectKeysList [PrintJobApcIdent ==. apci, PrintJobAcknowledged ==. Nothing] [Asc PrintJobCreated, LimitTo 1] >>= \case - [pjid] -> update pjid [PrintJobAcknowledged =. Just ackt] >> - return True - _ -> return False + ackOneId ackt apci = selectKeysList [PrintJobApcIdent ==. apci, PrintJobAcknowledged ==. Nothing] [Asc PrintJobCreated, LimitTo 1] >>= \case -- mark oldest as done, if there are multiple with the same identifier + [pjid] -> update pjid [PrintJobAcknowledged =. Just ackt] $> True + _ -> do + pjcs <- E.select $ do + let len_apci = Text.length apci + ifx_bounds = (E.val $ len_apci - apcIdentMaxDiff, E.val $ len_apci + apcIdentMaxDiff) + pj <- E.from $ E.table @PrintJob + E.where_ $ E.isNothing (pj E.^. PrintJobAcknowledged) + E.&&. (E.length_ (pj E.^. PrintJobApcIdent) `E.between` ifx_bounds) + E.&&. (E.isInfixOf (E.val apci) (pj E.^. PrintJobApcIdent) + E.||. E.isInfixOf (pj E.^. PrintJobApcIdent) (E.val apci) + ) + E.orderBy [E.asc $ pj E.^. PrintJobCreated] -- mark oldest printjob as done, if there are multiple matching jobs + E.limit 1 + return $ pj E.^. PrintJobId + case pjcs of + [E.Value pjid] -> update pjid [PrintJobAcknowledged =. Just ackt] $> True + _ -> return False procOneId oks Entity{entityKey=paid, entityVal=PrintAcknowledge{printAcknowledgeApcIdent=Text.strip -> apci, printAcknowledgeTimestamp=ackt}} = orM [ackOneId ackt $ ftrans apci | ftrans <- ftransAliases] >>= \case True -> delete paid >> return (succ oks)