Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
haskell-gargantext
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
160
Issues
160
List
Board
Labels
Milestones
Merge Requests
14
Merge Requests
14
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
gargantext
haskell-gargantext
Commits
ea7821be
Verified
Commit
ea7821be
authored
Oct 29, 2024
by
Przemyslaw Kaminski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[workers] more progress towards the end goal, this is still WIP
parent
eba70196
Pipeline
#6911
failed with stages
in 19 minutes and 30 seconds
Changes
19
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
309 additions
and
172 deletions
+309
-172
cabal.project
cabal.project
+1
-1
Routes.hs
src/Gargantext/API/Routes.hs
+17
-6
Named.hs
src/Gargantext/API/Routes/Named.hs
+1
-1
Corpus.hs
src/Gargantext/API/Routes/Named/Corpus.hs
+4
-3
Worker.hs
src/Gargantext/API/Worker.hs
+10
-19
CentralExchange.hs
src/Gargantext/Core/Notifications/CentralExchange.hs
+4
-7
Types.hs
src/Gargantext/Core/Notifications/CentralExchange/Types.hs
+0
-11
Dispatcher.hs
src/Gargantext/Core/Notifications/Dispatcher.hs
+19
-14
Types.hs
src/Gargantext/Core/Notifications/Dispatcher/Types.hs
+39
-27
Worker.hs
src/Gargantext/Core/Worker.hs
+72
-23
Env.hs
src/Gargantext/Core/Worker/Env.hs
+14
-8
Jobs.hs
src/Gargantext/Core/Worker/Jobs.hs
+9
-2
Types.hs
src/Gargantext/Core/Worker/Jobs/Types.hs
+38
-19
Types.hs
src/Gargantext/Core/Worker/Types.hs
+8
-2
UpdateOpaleye.hs
src/Gargantext/Database/Query/Table/Node/UpdateOpaleye.hs
+7
-10
Error.hs
src/Gargantext/Utils/Jobs/Error.hs
+10
-1
Notifications.hs
test/Test/API/Notifications.hs
+9
-6
UpdateList.hs
test/Test/API/UpdateList.hs
+12
-7
Utils.hs
test/Test/Utils.hs
+35
-5
No files found.
cabal.project
View file @
ea7821be
...
@@ -196,7 +196,7 @@ source-repository-package
...
@@ -196,7 +196,7 @@ source-repository-package
source
-
repository
-
package
source
-
repository
-
package
type
:
git
type
:
git
location
:
https
://
gitlab
.
iscpif
.
fr
/
gargantext
/
haskell
-
bee
location
:
https
://
gitlab
.
iscpif
.
fr
/
gargantext
/
haskell
-
bee
tag
:
ec2c3f345049f7cd0b8f4e39edf11c7e437d0cf6
tag
:
307f6760383
b74cddd5a586d0b5b1f1a2fc94429
source
-
repository
-
package
source
-
repository
-
package
type
:
git
type
:
git
...
...
src/Gargantext/API/Routes.hs
View file @
ea7821be
...
@@ -27,7 +27,7 @@ import Gargantext.API.Routes.Named.Annuaire qualified as Named
...
@@ -27,7 +27,7 @@ import Gargantext.API.Routes.Named.Annuaire qualified as Named
import
Gargantext.API.Routes.Named.Corpus
qualified
as
Named
import
Gargantext.API.Routes.Named.Corpus
qualified
as
Named
import
Gargantext.API.Worker
(
serveWorkerAPI
)
import
Gargantext.API.Worker
(
serveWorkerAPI
)
import
Gargantext.Core.Types.Individu
(
User
(
..
))
import
Gargantext.Core.Types.Individu
(
User
(
..
))
import
Gargantext.Core.Worker.Jobs
qualified
as
Jobs
--
import Gargantext.Core.Worker.Jobs qualified as Jobs
import
Gargantext.Core.Worker.Jobs.Types
qualified
as
Jobs
import
Gargantext.Core.Worker.Jobs.Types
qualified
as
Jobs
import
Gargantext.Prelude
import
Gargantext.Prelude
import
Gargantext.Utils.Jobs
(
serveJobsAPI
)
import
Gargantext.Utils.Jobs
(
serveJobsAPI
)
...
@@ -67,16 +67,27 @@ addCorpusWithQuery user = Named.AddWithQuery $ \cId ->
...
@@ -67,16 +67,27 @@ addCorpusWithQuery user = Named.AddWithQuery $ \cId ->
,
Jobs
.
_acq_user
=
user
,
Jobs
.
_acq_user
=
user
,
Jobs
.
_acq_cid
=
cId
}
,
Jobs
.
_acq_cid
=
cId
}
-- addCorpusWithForm :: User -> Named.AddWithForm (AsServerT (GargM Env BackendInternalError))
-- addCorpusWithForm user = Named.AddWithForm $ \cid -> AsyncJobs $
-- serveJobsAPI AddCorpusFormJob $ \_jHandle i -> do
-- -- /NOTE(adinapoli)/ Track the initial steps outside 'addToCorpusWithForm', because it's
-- -- called in a few places, and the job status might be different between invocations.
-- -- markStarted 3 jHandle
-- -- New.addToCorpusWithForm user cid i jHandle
-- void $ Jobs.sendJob $ Jobs.AddCorpusFormAsync { Jobs._acf_args = i
-- , Jobs._acf_user = user
-- , Jobs._acf_cid = cid }
addCorpusWithForm
::
User
->
Named
.
AddWithForm
(
AsServerT
(
GargM
Env
BackendInternalError
))
addCorpusWithForm
::
User
->
Named
.
AddWithForm
(
AsServerT
(
GargM
Env
BackendInternalError
))
addCorpusWithForm
user
=
Named
.
AddWithForm
$
\
c
id
->
AsyncJobs
$
addCorpusWithForm
user
=
Named
.
AddWithForm
$
\
c
Id
->
serve
JobsAPI
AddCorpusFormJob
$
\
_jHandle
i
->
do
serve
WorkerAPI
$
\
p
->
-- /NOTE(adinapoli)/ Track the initial steps outside 'addToCorpusWithForm', because it's
-- /NOTE(adinapoli)/ Track the initial steps outside 'addToCorpusWithForm', because it's
-- called in a few places, and the job status might be different between invocations.
-- called in a few places, and the job status might be different between invocations.
-- markStarted 3 jHandle
-- markStarted 3 jHandle
-- New.addToCorpusWithForm user cid i jHandle
-- New.addToCorpusWithForm user cid i jHandle
void
$
Jobs
.
sendJob
$
Jobs
.
AddCorpusFormAsync
{
Jobs
.
_acf_args
=
i
Jobs
.
AddCorpusFormAsync
{
Jobs
.
_acf_args
=
p
,
Jobs
.
_acf_user
=
user
,
Jobs
.
_acf_user
=
user
,
Jobs
.
_acf_cid
=
ci
d
}
,
Jobs
.
_acf_cid
=
cI
d
}
--addCorpusWithFile :: User -> ServerT Named.AddWithFile (GargM Env BackendInternalError)
--addCorpusWithFile :: User -> ServerT Named.AddWithFile (GargM Env BackendInternalError)
...
...
src/Gargantext/API/Routes/Named.hs
View file @
ea7821be
...
@@ -97,7 +97,7 @@ data ForgotPasswordAPI mode = ForgotPasswordAPI
...
@@ -97,7 +97,7 @@ data ForgotPasswordAPI mode = ForgotPasswordAPI
data
ForgotPasswordAsyncAPI
mode
=
ForgotPasswordAsyncAPI
data
ForgotPasswordAsyncAPI
mode
=
ForgotPasswordAsyncAPI
{
forgotPasswordAsyncEp
::
mode
:-
Summary
"Forgot password asnc"
{
forgotPasswordAsyncEp
::
mode
:-
Summary
"Forgot password asnc"
:>
NamedRoutes
(
WorkerAPI
ForgotPasswordAsyncParams
)
:>
NamedRoutes
(
WorkerAPI
'[
J
SON
]
ForgotPasswordAsyncParams
)
}
deriving
Generic
}
deriving
Generic
...
...
src/Gargantext/API/Routes/Named/Corpus.hs
View file @
ea7821be
...
@@ -9,7 +9,7 @@ module Gargantext.API.Routes.Named.Corpus (
...
@@ -9,7 +9,7 @@ module Gargantext.API.Routes.Named.Corpus (
import
Data.Text
(
Text
)
import
Data.Text
(
Text
)
import
GHC.Generics
import
GHC.Generics
import
Gargantext.API.Admin.Orchestrator.Types
--
import Gargantext.API.Admin.Orchestrator.Types
import
Gargantext.API.Node.Corpus.Export.Types
import
Gargantext.API.Node.Corpus.Export.Types
import
Gargantext.API.Node.Types
import
Gargantext.API.Node.Types
import
Gargantext.API.Worker
(
WorkerAPI
)
import
Gargantext.API.Worker
(
WorkerAPI
)
...
@@ -33,7 +33,8 @@ newtype AddWithForm mode = AddWithForm
...
@@ -33,7 +33,8 @@ newtype AddWithForm mode = AddWithForm
:>
"add"
:>
"add"
:>
"form"
:>
"form"
:>
"async"
:>
"async"
:>
NamedRoutes
(
AsyncJobs
JobLog
'[
F
ormUrlEncoded
]
NewWithForm
JobLog
)
-- :> NamedRoutes (AsyncJobs JobLog '[FormUrlEncoded] NewWithForm JobLog)
:>
NamedRoutes
(
WorkerAPI
'[
F
ormUrlEncoded
]
NewWithForm
)
}
deriving
Generic
}
deriving
Generic
newtype
AddWithQuery
mode
=
AddWithQuery
newtype
AddWithQuery
mode
=
AddWithQuery
...
@@ -42,5 +43,5 @@ newtype AddWithQuery mode = AddWithQuery
...
@@ -42,5 +43,5 @@ newtype AddWithQuery mode = AddWithQuery
:>
Capture
"corpus_id"
CorpusId
:>
Capture
"corpus_id"
CorpusId
:>
"query"
:>
"query"
-- :> NamedRoutes (AsyncJobs JobLog '[JSON] WithQuery JobLog)
-- :> NamedRoutes (AsyncJobs JobLog '[JSON] WithQuery JobLog)
:>
NamedRoutes
(
WorkerAPI
WithQuery
)
:>
NamedRoutes
(
WorkerAPI
'[
J
SON
]
WithQuery
)
}
deriving
Generic
}
deriving
Generic
src/Gargantext/API/Worker.hs
View file @
ea7821be
...
@@ -15,35 +15,26 @@ module Gargantext.API.Worker where
...
@@ -15,35 +15,26 @@ module Gargantext.API.Worker where
import
Gargantext.API.Prelude
(
IsGargServer
)
import
Gargantext.API.Prelude
(
IsGargServer
)
import
Gargantext.Core.Worker.Jobs
(
sendJob
)
import
Gargantext.Core.Worker.Jobs
(
sendJob
)
import
Gargantext.Core.Worker.Jobs.Types
(
Job
(
..
))
import
Gargantext.Core.Worker.Jobs.Types
(
Job
(
..
)
,
getWorkerMNodeId
)
import
Gargantext.Core.Worker.Types
import
Gargantext.Core.Worker.Types
(
JobInfo
(
..
))
import
Gargantext.Prelude
import
Gargantext.Prelude
import
Servant.API
((
:>
),
(
:-
),
JSON
,
Post
,
ReqBody
)
import
Servant.API
((
:>
),
(
:-
),
JSON
,
Post
,
ReqBody
)
import
Servant.Server.Generic
(
AsServerT
)
import
Servant.Server.Generic
(
AsServerT
)
data
WorkerAPI
input
mode
=
WorkerAPI
data
WorkerAPI
contentType
input
mode
=
WorkerAPI
{
workerAPIPost
::
mode
:-
ReqBody
'[
J
SON
]
input
{
workerAPIPost
::
mode
:-
ReqBody
contentType
input
:>
Post
'[
J
SON
]
JobInfo
}
:>
Post
'[
J
SON
]
JobInfo
}
deriving
Generic
deriving
Generic
-- serveWorkerAPI :: ( HasWorkerBroker PGMQBroker Job
-- , m ~ GargM Env BackendInternalError )
-- => (input -> Job)
-- -> input
-- -> WorkerJob (AsServerT m)
-- -- -> ServerT (Post '[JSON] JobInfo) m
-- -- -> Cmd' env err JobInfo
-- serveWorkerAPI f i = do
-- mId <- sendJob $ f i
-- pure $ JobInfo { _ji_message_id = mId }
serveWorkerAPI
::
IsGargServer
env
err
m
serveWorkerAPI
::
IsGargServer
env
err
m
=>
(
input
->
Job
)
=>
(
input
->
Job
)
->
WorkerAPI
input
(
AsServerT
m
)
->
WorkerAPI
contentType
input
(
AsServerT
m
)
serveWorkerAPI
f
=
WorkerAPI
{
workerAPIPost
}
serveWorkerAPI
f
=
WorkerAPI
{
workerAPIPost
}
where
where
workerAPIPost
i
=
do
workerAPIPost
i
=
do
mId
<-
sendJob
$
f
i
let
job
=
f
i
pure
$
JobInfo
{
_ji_message_id
=
mId
}
mId
<-
sendJob
job
pure
$
JobInfo
{
_ji_message_id
=
mId
,
_ji_mNode_id
=
getWorkerMNodeId
job
}
src/Gargantext/Core/Notifications/CentralExchange.hs
View file @
ea7821be
...
@@ -77,8 +77,8 @@ gServer (NotificationsConfig { .. }) = do
...
@@ -77,8 +77,8 @@ gServer (NotificationsConfig { .. }) = do
-- send the same message that we received
-- send the same message that we received
-- void $ sendNonblocking s_dispatcher r
-- void $ sendNonblocking s_dispatcher r
void
$
timeout
100
_000
$
send
s_dispatcher
r
void
$
timeout
100
_000
$
send
s_dispatcher
r
Just
(
UpdateTreeFirstLevel
node_id
)
->
do
Just
(
UpdateTreeFirstLevel
_
node_id
)
->
do
logMsg
ioLogger
DEBUG
$
"[central_exchange] update tree: "
<>
show
node_id
--
logMsg ioLogger DEBUG $ "[central_exchange] update tree: " <> show node_id
-- putText $ "[central_exchange] sending that to the dispatcher: " <> show node_id
-- putText $ "[central_exchange] sending that to the dispatcher: " <> show node_id
-- To make this more robust, use withAsync so we don't
-- To make this more robust, use withAsync so we don't
-- block the main thread (send is blocking)
-- block the main thread (send is blocking)
...
@@ -96,11 +96,8 @@ gServer (NotificationsConfig { .. }) = do
...
@@ -96,11 +96,8 @@ gServer (NotificationsConfig { .. }) = do
-- send the same message that we received
-- send the same message that we received
-- void $ sendNonblocking s_dispatcher r
-- void $ sendNonblocking s_dispatcher r
void
$
timeout
100
_000
$
send
s_dispatcher
r
void
$
timeout
100
_000
$
send
s_dispatcher
r
Just
(
UpdateWorkerProgress
ji
jl
)
->
do
Just
(
UpdateWorkerProgress
_ji
_jl
)
->
do
logMsg
ioLogger
DEBUG
$
"[central_exchange] update worker progress: "
<>
show
ji
<>
", "
<>
show
jl
-- logMsg ioLogger DEBUG $ "[central_exchange] update worker progress: " <> show ji <> ", " <> show jl
Just
(
WorkerJobStarted
nodeId
ji
)
->
do
logMsg
ioLogger
DEBUG
$
"[central_exchange] worker job started: "
<>
show
nodeId
<>
", "
<>
show
ji
void
$
timeout
100
_000
$
send
s_dispatcher
r
void
$
timeout
100
_000
$
send
s_dispatcher
r
Nothing
->
Nothing
->
logMsg
ioLogger
ERROR
$
"[central_exchange] cannot decode message: "
<>
show
r
logMsg
ioLogger
ERROR
$
"[central_exchange] cannot decode message: "
<>
show
r
...
...
src/Gargantext/Core/Notifications/CentralExchange/Types.hs
View file @
ea7821be
...
@@ -47,13 +47,11 @@ data CEMessage =
...
@@ -47,13 +47,11 @@ data CEMessage =
|
UpdateWorkerProgress
JobInfo
JobLog
|
UpdateWorkerProgress
JobInfo
JobLog
-- | Update tree for given nodeId
-- | Update tree for given nodeId
|
UpdateTreeFirstLevel
NodeId
|
UpdateTreeFirstLevel
NodeId
|
WorkerJobStarted
NodeId
JobInfo
instance
Prelude
.
Show
CEMessage
where
instance
Prelude
.
Show
CEMessage
where
show
(
UpdateJobProgress
js
)
=
"UpdateJobProgress "
<>
(
CBUTF8
.
decode
$
BSL
.
unpack
$
Aeson
.
encode
js
)
show
(
UpdateJobProgress
js
)
=
"UpdateJobProgress "
<>
(
CBUTF8
.
decode
$
BSL
.
unpack
$
Aeson
.
encode
js
)
-- show (UpdateWorkerProgress ji nodeId jl) = "UpdateWorkerProgress " <> show ji <> " " <> show nodeId <> " " <> show jl
-- show (UpdateWorkerProgress ji nodeId jl) = "UpdateWorkerProgress " <> show ji <> " " <> show nodeId <> " " <> show jl
show
(
UpdateWorkerProgress
ji
jl
)
=
"UpdateWorkerProgress "
<>
show
ji
<>
" "
<>
show
jl
show
(
UpdateWorkerProgress
ji
jl
)
=
"UpdateWorkerProgress "
<>
show
ji
<>
" "
<>
show
jl
show
(
UpdateTreeFirstLevel
nodeId
)
=
"UpdateTreeFirstLevel "
<>
show
nodeId
show
(
UpdateTreeFirstLevel
nodeId
)
=
"UpdateTreeFirstLevel "
<>
show
nodeId
show
(
WorkerJobStarted
nodeId
ji
)
=
"WorkerJobStarted "
<>
show
nodeId
<>
" "
<>
show
ji
instance
FromJSON
CEMessage
where
instance
FromJSON
CEMessage
where
parseJSON
=
withObject
"CEMessage"
$
\
o
->
do
parseJSON
=
withObject
"CEMessage"
$
\
o
->
do
type_
<-
o
.:
"type"
type_
<-
o
.:
"type"
...
@@ -70,10 +68,6 @@ instance FromJSON CEMessage where
...
@@ -70,10 +68,6 @@ instance FromJSON CEMessage where
"update_tree_first_level"
->
do
"update_tree_first_level"
->
do
node_id
<-
o
.:
"node_id"
node_id
<-
o
.:
"node_id"
pure
$
UpdateTreeFirstLevel
node_id
pure
$
UpdateTreeFirstLevel
node_id
"worker_job_started"
->
do
nodeId
<-
o
.:
"node_id"
ji
<-
o
.:
"ji"
pure
$
WorkerJobStarted
nodeId
ji
s
->
prependFailure
"parsing type failed, "
(
typeMismatch
"type"
s
)
s
->
prependFailure
"parsing type failed, "
(
typeMismatch
"type"
s
)
instance
ToJSON
CEMessage
where
instance
ToJSON
CEMessage
where
toJSON
(
UpdateJobProgress
js
)
=
object
[
toJSON
(
UpdateJobProgress
js
)
=
object
[
...
@@ -91,11 +85,6 @@ instance ToJSON CEMessage where
...
@@ -91,11 +85,6 @@ instance ToJSON CEMessage where
"type"
.=
toJSON
(
"update_tree_first_level"
::
Text
)
"type"
.=
toJSON
(
"update_tree_first_level"
::
Text
)
,
"node_id"
.=
toJSON
nodeId
,
"node_id"
.=
toJSON
nodeId
]
]
toJSON
(
WorkerJobStarted
nodeId
ji
)
=
object
[
"type"
.=
toJSON
(
"worker_job_started"
::
Text
)
,
"node_id"
.=
toJSON
nodeId
,
"ji"
.=
toJSON
ji
]
class
HasCentralExchangeNotification
env
where
class
HasCentralExchangeNotification
env
where
...
...
src/Gargantext/Core/Notifications/Dispatcher.hs
View file @
ea7821be
...
@@ -34,6 +34,7 @@ import DeferredFolds.UnfoldlM qualified as UnfoldlM
...
@@ -34,6 +34,7 @@ import DeferredFolds.UnfoldlM qualified as UnfoldlM
import
Gargantext.Core.Config.Types
(
NotificationsConfig
(
..
))
import
Gargantext.Core.Config.Types
(
NotificationsConfig
(
..
))
import
Gargantext.Core.Notifications.CentralExchange.Types
qualified
as
CETypes
import
Gargantext.Core.Notifications.CentralExchange.Types
qualified
as
CETypes
import
Gargantext.Core.Notifications.Dispatcher.Types
import
Gargantext.Core.Notifications.Dispatcher.Types
import
Gargantext.Core.Worker.Types
(
JobInfo
(
..
))
import
Gargantext.Prelude
import
Gargantext.Prelude
import
Gargantext.System.Logging
(
LogLevel
(
DEBUG
),
withLogger
,
logMsg
)
import
Gargantext.System.Logging
(
LogLevel
(
DEBUG
),
withLogger
,
logMsg
)
import
Nanomsg
(
Pull
(
..
),
bind
,
recv
,
withSocket
)
import
Nanomsg
(
Pull
(
..
),
bind
,
recv
,
withSocket
)
...
@@ -113,8 +114,9 @@ dispatcherListener (NotificationsConfig { _nc_dispatcher_bind }) subscriptions =
...
@@ -113,8 +114,9 @@ dispatcherListener (NotificationsConfig { _nc_dispatcher_bind }) subscriptions =
-- putText $ "[" <> show tId <> "] received a message: " <> decodeUtf8 r
-- putText $ "[" <> show tId <> "] received a message: " <> decodeUtf8 r
case
Aeson
.
decode
(
BSL
.
fromStrict
r
)
of
case
Aeson
.
decode
(
BSL
.
fromStrict
r
)
of
Nothing
->
withLogger
()
$
\
ioL
->
Nothing
->
logMsg
ioL
DEBUG
"[dispatcher_listener] unknown message from central exchange"
withLogger
()
$
\
ioL
->
logMsg
ioL
DEBUG
"[dispatcher_listener] unknown message from central exchange"
Just
ceMessage
->
do
Just
ceMessage
->
do
-- putText $ "[dispatcher_listener] received message: " <> show ceMessage
-- putText $ "[dispatcher_listener] received message: " <> show ceMessage
-- subs <- atomically $ readTVar subscriptions
-- subs <- atomically $ readTVar subscriptions
...
@@ -144,38 +146,43 @@ sendNotification throttleTChan ceMessage sub = do
...
@@ -144,38 +146,43 @@ sendNotification throttleTChan ceMessage sub = do
-- message to a client
-- message to a client
let
topic
=
s_topic
sub
let
topic
=
s_topic
sub
let
mNotification
=
let
mNotification
=
-- | OK so given a websocket subscription and a central
-- exchange message - decide whether to send this message via
-- that socket or not
case
(
topic
,
ceMessage
)
of
case
(
topic
,
ceMessage
)
of
(
UpdateJobProgress
jId
,
CETypes
.
UpdateJobProgress
jobStatus
)
->
do
(
UpdateJobProgress
jId
,
CETypes
.
UpdateJobProgress
jobStatus
)
->
do
if
jId
==
jobStatus
^.
job_id
if
jId
==
jobStatus
^.
job_id
then
Just
$
NUpdateJobProgress
jId
(
MJobStatus
jobStatus
)
then
Just
$
NUpdateJobProgress
jId
jobStatus
--
(MJobStatus jobStatus)
else
Nothing
else
Nothing
-- (UpdateWorkerProgress jobInfo, CETypes.UpdateWorkerProgress jobInfo' nodeId jobLog) -> do
-- (UpdateWorkerProgress jobInfo, CETypes.UpdateWorkerProgress jobInfo' nodeId jobLog) -> do
(
UpdateWorkerProgress
jobInfo
,
CETypes
.
UpdateWorkerProgress
jobInfo'
jobLog
)
->
do
(
UpdateWorkerProgress
jobInfo
,
CETypes
.
UpdateWorkerProgress
jobInfo'
jobLog
)
->
do
if
jobInfo
==
jobInfo'
if
jobInfo
==
jobInfo'
-- then Just $ NUpdateWorkerProgress jobInfo nodeId (MJobLog jobLog)
-- then Just $ NUpdateWorkerProgress jobInfo nodeId (MJobLog jobLog)
then
Just
$
NUpdateWorkerProgress
jobInfo
(
MJobLog
jobLog
)
then
Just
$
NUpdateWorkerProgress
jobInfo
jobLog
-- (MJobLog jobLog)
else
Nothing
(
UpdateTree
nodeId
,
CETypes
.
UpdateWorkerProgress
jobInfo
jobLog
)
->
do
if
Just
nodeId
==
_ji_mNode_id
jobInfo
then
Just
$
NUpdateWorkerProgress
jobInfo
jobLog
-- (MJobLog jobLog)
else
Nothing
else
Nothing
(
UpdateTree
nodeId
,
CETypes
.
UpdateTreeFirstLevel
nodeId'
)
->
(
UpdateTree
nodeId
,
CETypes
.
UpdateTreeFirstLevel
nodeId'
)
->
if
nodeId
==
nodeId'
if
nodeId
==
nodeId'
then
Just
$
NUpdateTree
nodeId
then
Just
$
NUpdateTree
nodeId
else
Nothing
else
Nothing
(
UpdateTree
nodeId
,
CETypes
.
WorkerJobStarted
nodeId'
ji
)
->
if
nodeId
==
nodeId'
then
Just
$
NWorkerJobStarted
nodeId
ji
else
Nothing
_
->
Nothing
_
->
Nothing
case
mNotification
of
case
mNotification
of
Nothing
->
pure
()
Nothing
->
pure
()
Just
notification
->
do
Just
notification
->
do
let
id'
=
(
wsKey
ws
,
topic
)
let
id'
=
(
wsKey
ws
,
topic
)
withLogger
()
$
\
ioL
->
logMsg
ioL
DEBUG
$
"[sendNotification] dispatching notification: "
<>
show
notification
atomically
$
do
atomically
$
do
TChan
.
writeTChan
throttleTChan
(
id'
,
(
wsConn
ws
,
WS
.
Text
(
Aeson
.
encode
notification
)
Nothing
))
TChan
.
writeTChan
throttleTChan
(
id'
,
(
wsConn
ws
,
WS
.
Text
(
Aeson
.
encode
notification
)
Nothing
))
-- | The "true" message sending to websocket. After it was withheld
-- for a while (for throttling), it is finally sent here
sendDataMessageThrottled
::
(
WS
.
Connection
,
WS
.
DataMessage
)
->
IO
()
sendDataMessageThrottled
::
(
WS
.
Connection
,
WS
.
DataMessage
)
->
IO
()
sendDataMessageThrottled
(
conn
,
msg
)
=
sendDataMessageThrottled
(
conn
,
msg
)
=
do
withLogger
()
$
\
ioL
->
logMsg
ioL
DEBUG
$
"[sendDataMessageThrottled] dispatching notification: "
<>
show
msg
WS
.
sendDataMessage
conn
msg
WS
.
sendDataMessage
conn
msg
...
@@ -195,8 +202,6 @@ ceMessageSubPred (CETypes.UpdateJobProgress js) (Subscription { s_topic }) =
...
@@ -195,8 +202,6 @@ ceMessageSubPred (CETypes.UpdateJobProgress js) (Subscription { s_topic }) =
-- ceMessageSubPred (CETypes.UpdateWorkerProgress ji nodeId _jl) (Subscription { s_topic }) =
-- ceMessageSubPred (CETypes.UpdateWorkerProgress ji nodeId _jl) (Subscription { s_topic }) =
ceMessageSubPred
(
CETypes
.
UpdateWorkerProgress
ji
_jl
)
(
Subscription
{
s_topic
})
=
ceMessageSubPred
(
CETypes
.
UpdateWorkerProgress
ji
_jl
)
(
Subscription
{
s_topic
})
=
s_topic
==
UpdateWorkerProgress
ji
s_topic
==
UpdateWorkerProgress
ji
-- || s_topic == UpdateTree nodeId
||
Just
s_topic
==
(
UpdateTree
<$>
_ji_mNode_id
ji
)
ceMessageSubPred
(
CETypes
.
UpdateTreeFirstLevel
nodeId
)
(
Subscription
{
s_topic
})
=
ceMessageSubPred
(
CETypes
.
UpdateTreeFirstLevel
nodeId
)
(
Subscription
{
s_topic
})
=
s_topic
==
UpdateTree
nodeId
s_topic
==
UpdateTree
nodeId
ceMessageSubPred
(
CETypes
.
WorkerJobStarted
nodeId
_ji
)
(
Subscription
{
s_topic
})
=
s_topic
==
UpdateTree
nodeId
src/Gargantext/Core/Notifications/Dispatcher/Types.hs
View file @
ea7821be
...
@@ -101,32 +101,32 @@ instance ToJSON Topic where
...
@@ -101,32 +101,32 @@ instance ToJSON Topic where
]
]
-- | A job status message
-- | A job status message
newtype
MJobStatus
=
MJobStatus
(
JobStatus
'S
a
fe
JobLog
)
--
newtype MJobStatus = MJobStatus (JobStatus 'Safe JobLog)
instance
Prelude
.
Show
MJobStatus
where
--
instance Prelude.Show MJobStatus where
show
(
MJobStatus
js
)
=
"MJobStatus "
<>
show
(
CBUTF8
.
decode
$
BSL
.
unpack
$
Aeson
.
encode
js
)
--
show (MJobStatus js) = "MJobStatus " <> show (CBUTF8.decode $ BSL.unpack $ Aeson.encode js)
instance
ToJSON
MJobStatus
where
--
instance ToJSON MJobStatus where
toJSON
(
MJobStatus
js
)
=
Aeson
.
object
[
--
toJSON (MJobStatus js) = Aeson.object [
"type"
.=
toJSON
(
"MJobLog"
::
Text
)
--
"type" .= toJSON ("MJobLog" :: Text)
,
"job_status"
.=
toJSON
js
--
, "job_status" .= toJSON js
]
--
]
instance
FromJSON
MJobStatus
where
--
instance FromJSON MJobStatus where
parseJSON
=
Aeson
.
withObject
"MJobStatus"
$
\
o
->
do
--
parseJSON = Aeson.withObject "MJobStatus" $ \o -> do
js
<-
o
.:
"job_status"
--
js <- o .: "job_status"
pure
$
MJobStatus
js
--
pure $ MJobStatus js
-- | A job progress message
-- | A job progress message
newtype
MJobLog
=
MJobLog
JobLog
--
newtype MJobLog = MJobLog JobLog
instance
Prelude
.
Show
MJobLog
where
--
instance Prelude.Show MJobLog where
show
(
MJobLog
jl
)
=
"MJobLog "
<>
show
jl
--
show (MJobLog jl) = "MJobLog " <> show jl
instance
ToJSON
MJobLog
where
--
instance ToJSON MJobLog where
toJSON
(
MJobLog
jl
)
=
Aeson
.
object
[
--
toJSON (MJobLog jl) = Aeson.object [
"type"
.=
toJSON
(
"MJobLog"
::
Text
)
--
"type" .= toJSON ("MJobLog" :: Text)
,
"job_log"
.=
toJSON
jl
--
, "job_log" .= toJSON jl
]
--
]
instance
FromJSON
MJobLog
where
--
instance FromJSON MJobLog where
parseJSON
=
Aeson
.
withObject
"MJobLog"
$
\
o
->
do
--
parseJSON = Aeson.withObject "MJobLog" $ \o -> do
jl
<-
o
.:
"job_log"
--
jl <- o .: "job_log"
pure
$
MJobLog
jl
--
pure $ MJobLog jl
...
@@ -216,17 +216,20 @@ class HasDispatcher env dispatcher where
...
@@ -216,17 +216,20 @@ class HasDispatcher env dispatcher where
-- | A notification is sent to clients who subscribed to specific topics
-- | A notification is sent to clients who subscribed to specific topics
data
Notification
=
data
Notification
=
NUpdateJobProgress
(
JobID
'S
a
fe
)
MJobStatus
-- NUpdateJobProgress (JobID 'Safe) MJobStatus
NUpdateJobProgress
(
JobID
'S
a
fe
)
(
JobStatus
'S
a
fe
JobLog
)
-- | NUpdateWorkerProgress JobInfo NodeId MJobLog
-- | NUpdateWorkerProgress JobInfo NodeId MJobLog
|
NUpdateWorkerProgress
JobInfo
M
JobLog
|
NUpdateWorkerProgress
JobInfo
JobLog
|
NUpdateTree
NodeId
|
NUpdateTree
NodeId
|
NWorkerJobStarted
NodeId
JobInfo
|
NWorkerJobStarted
NodeId
JobInfo
|
NWorkerJobFinished
NodeId
JobInfo
instance
Prelude
.
Show
Notification
where
instance
Prelude
.
Show
Notification
where
show
(
NUpdateJobProgress
jId
mjs
)
=
"NUpdateJobProgress "
<>
(
CBUTF8
.
decode
$
BSL
.
unpack
$
Aeson
.
encode
jId
)
<>
", "
<>
show
mjs
show
(
NUpdateJobProgress
jId
mjs
)
=
"NUpdateJobProgress "
<>
(
CBUTF8
.
decode
$
BSL
.
unpack
$
Aeson
.
encode
jId
)
--
<> ", " <> show mjs
-- show (NUpdateWorkerProgress jobInfo nodeId mJobLog) = "NUpdateWorkerProgress " <> show jobInfo <> ", " <> show nodeId <> ", " <> show mJobLog
-- show (NUpdateWorkerProgress jobInfo nodeId mJobLog) = "NUpdateWorkerProgress " <> show jobInfo <> ", " <> show nodeId <> ", " <> show mJobLog
show
(
NUpdateWorkerProgress
jobInfo
mJobLog
)
=
"NUpdateWorkerProgress "
<>
show
jobInfo
<>
", "
<>
show
mJobLog
show
(
NUpdateWorkerProgress
jobInfo
mJobLog
)
=
"NUpdateWorkerProgress "
<>
show
jobInfo
<>
", "
<>
show
mJobLog
show
(
NUpdateTree
nodeId
)
=
"NUpdateTree "
<>
show
nodeId
show
(
NUpdateTree
nodeId
)
=
"NUpdateTree "
<>
show
nodeId
show
(
NWorkerJobStarted
nodeId
ji
)
=
"NWorkerJobStarted "
<>
show
nodeId
<>
", "
<>
show
ji
show
(
NWorkerJobStarted
nodeId
ji
)
=
"NWorkerJobStarted "
<>
show
nodeId
<>
", "
<>
show
ji
show
(
NWorkerJobFinished
nodeId
ji
)
=
"NWorkerJobFinished "
<>
show
nodeId
<>
", "
<>
show
ji
instance
ToJSON
Notification
where
instance
ToJSON
Notification
where
toJSON
(
NUpdateJobProgress
jId
mjs
)
=
Aeson
.
object
[
toJSON
(
NUpdateJobProgress
jId
mjs
)
=
Aeson
.
object
[
"type"
.=
(
"update_job_progress"
::
Text
)
"type"
.=
(
"update_job_progress"
::
Text
)
...
@@ -249,6 +252,11 @@ instance ToJSON Notification where
...
@@ -249,6 +252,11 @@ instance ToJSON Notification where
,
"node_id"
.=
toJSON
nodeId
,
"node_id"
.=
toJSON
nodeId
,
"ji"
.=
toJSON
ji
,
"ji"
.=
toJSON
ji
]
]
toJSON
(
NWorkerJobFinished
nodeId
ji
)
=
Aeson
.
object
[
"type"
.=
(
"worker_job_finished"
::
Text
)
,
"node_id"
.=
toJSON
nodeId
,
"ji"
.=
toJSON
ji
]
-- We don't need to decode notifications, this is for tests only
-- We don't need to decode notifications, this is for tests only
instance
FromJSON
Notification
where
instance
FromJSON
Notification
where
parseJSON
=
Aeson
.
withObject
"Notification"
$
\
o
->
do
parseJSON
=
Aeson
.
withObject
"Notification"
$
\
o
->
do
...
@@ -271,4 +279,8 @@ instance FromJSON Notification where
...
@@ -271,4 +279,8 @@ instance FromJSON Notification where
nodeId
<-
o
.:
"node_id"
nodeId
<-
o
.:
"node_id"
ji
<-
o
.:
"ji"
ji
<-
o
.:
"ji"
pure
$
NWorkerJobStarted
nodeId
ji
pure
$
NWorkerJobStarted
nodeId
ji
"worker_job_finished"
->
do
nodeId
<-
o
.:
"node_id"
ji
<-
o
.:
"ji"
pure
$
NWorkerJobFinished
nodeId
ji
s
->
prependFailure
"parsing type failed, "
(
typeMismatch
"type"
s
)
s
->
prependFailure
"parsing type failed, "
(
typeMismatch
"type"
s
)
src/Gargantext/Core/Worker.hs
View file @
ea7821be
...
@@ -27,19 +27,18 @@ import Gargantext.API.Admin.Auth (forgotUserPassword)
...
@@ -27,19 +27,18 @@ import Gargantext.API.Admin.Auth (forgotUserPassword)
import
Gargantext.API.Admin.Auth.Types
(
ForgotPasswordAsyncParams
(
..
))
import
Gargantext.API.Admin.Auth.Types
(
ForgotPasswordAsyncParams
(
..
))
import
Gargantext.API.Node.Corpus.New
(
addToCorpusWithForm
,
addToCorpusWithQuery
)
import
Gargantext.API.Node.Corpus.New
(
addToCorpusWithForm
,
addToCorpusWithQuery
)
import
Gargantext.API.Node.New
(
postNode'
)
import
Gargantext.API.Node.New
(
postNode'
)
import
Gargantext.API.Node.Types
(
WithQuery
(
..
))
import
Gargantext.Core.Config
(
hasConfig
,
gc_jobs
)
import
Gargantext.Core.Config
(
hasConfig
,
gc_jobs
)
import
Gargantext.Core.Config.Types
(
jc_max_docs_scrapers
)
import
Gargantext.Core.Config.Types
(
jc_max_docs_scrapers
)
import
Gargantext.Core.Config.Worker
(
WorkerDefinition
(
..
))
import
Gargantext.Core.Config.Worker
(
WorkerDefinition
(
..
))
import
Gargantext.Core.Notifications.CentralExchange.Types
qualified
as
CE
import
Gargantext.Core.Worker.Broker
(
initBrokerWithDBCreate
)
import
Gargantext.Core.Worker.Broker
(
initBrokerWithDBCreate
)
import
Gargantext.Core.Worker.Env
import
Gargantext.Core.Worker.Env
import
Gargantext.Core.Worker.Jobs.Types
(
Job
(
..
))
import
Gargantext.Core.Worker.Jobs.Types
(
Job
(
..
)
,
getWorkerMNodeId
)
import
Gargantext.Core.Worker.Types
(
JobInfo
(
..
))
import
Gargantext.Core.Worker.Types
(
JobInfo
(
..
))
import
Gargantext.Database.Admin.Types.Node
(
NodeId
(
..
))
import
Gargantext.Database.Query.Table.User
(
getUsersWithEmail
)
import
Gargantext.Database.Query.Table.User
(
getUsersWithEmail
)
import
Gargantext.Prelude
import
Gargantext.Prelude
import
Gargantext.System.Logging
(
logLocM
,
LogLevel
(
..
)
)
import
Gargantext.System.Logging
(
logLocM
,
LogLevel
(
..
),
logMsg
,
withLogger
)
import
Gargantext.Utils.Jobs.Error
(
HumanFriendlyErrorText
(
..
))
import
Gargantext.Utils.Jobs.Monad
(
MonadJobStatus
(
markStarted
,
markComplete
,
markFailed
))
...
@@ -55,25 +54,73 @@ initWorkerState env (WorkerDefinition { .. }) = do
...
@@ -55,25 +54,73 @@ initWorkerState env (WorkerDefinition { .. }) = do
,
queueName
=
_wdQueue
,
queueName
=
_wdQueue
,
name
=
T
.
unpack
_wdName
,
name
=
T
.
unpack
_wdName
,
performAction
=
performAction
env
,
performAction
=
performAction
env
,
onMessageReceived
=
Just
$
markJobStarted
env
,
onMessageReceived
=
Just
$
notifyJobStarted
env
,
onJobFinish
=
Nothing
,
onJobFinish
=
Just
$
notifyJobFinished
env
,
onJobTimeout
=
Just
$
\
_s
bm
->
putStrLn
(
"on job timeout: "
<>
show
(
toA
$
getMessage
bm
)
::
Text
)
,
onJobTimeout
=
Just
$
notifyJobTimeout
env
,
onJobError
=
Nothing
,
onJobError
=
Just
$
notifyJobFailed
env
-- TODO Implement Ctrl-C, notify job killed
,
onWorkerKilledSafely
=
Nothing
}
,
onWorkerKilledSafely
=
Nothing
}
mark
JobStarted
::
(
HasWorkerBroker
PGMQBroker
Job
)
notify
JobStarted
::
(
HasWorkerBroker
PGMQBroker
Job
)
=>
WorkerEnv
=>
WorkerEnv
->
Worker
.
State
PGMQBroker
Job
->
Worker
.
State
PGMQBroker
Job
->
BrokerMessage
PGMQBroker
(
Worker
.
Job
Job
)
->
BrokerMessage
PGMQBroker
(
Worker
.
Job
Job
)
->
IO
()
->
IO
()
mark
JobStarted
env
(
Worker
.
State
{
name
})
bm
=
do
notify
JobStarted
env
(
Worker
.
State
{
name
})
bm
=
do
let
j
=
toA
$
getMessage
bm
let
j
=
toA
$
getMessage
bm
putStrLn
$
"["
<>
name
<>
"] starting job: "
<>
show
j
let
job
=
Worker
.
job
j
let
ji
=
JobInfo
{
_ji_message_id
=
messageId
bm
}
withLogger
()
$
\
ioL
->
case
Worker
.
job
j
of
logMsg
ioL
DEBUG
$
"[notifyJobStarted] ["
<>
name
<>
"] starting job: "
<>
show
j
AddCorpusWithQuery
{
_acq_args
=
WithQuery
{
_wq_node_id
}
}
->
do
let
ji
=
JobInfo
{
_ji_message_id
=
messageId
bm
runWorkerMonad
env
$
CE
.
ce_notify
$
CE
.
WorkerJobStarted
(
UnsafeMkNodeId
_wq_node_id
)
ji
,
_ji_mNode_id
=
getWorkerMNodeId
job
}
_
->
pure
()
let
jh
=
WorkerJobHandle
{
_w_job_info
=
ji
}
runWorkerMonad
env
$
markStarted
1
jh
notifyJobFinished
::
(
HasWorkerBroker
PGMQBroker
Job
)
=>
WorkerEnv
->
Worker
.
State
PGMQBroker
Job
->
BrokerMessage
PGMQBroker
(
Worker
.
Job
Job
)
->
IO
()
notifyJobFinished
env
(
Worker
.
State
{
name
})
bm
=
do
let
j
=
toA
$
getMessage
bm
let
job
=
Worker
.
job
j
withLogger
()
$
\
ioL
->
logMsg
ioL
DEBUG
$
"[notifyJobFinished] ["
<>
name
<>
"] finished job: "
<>
show
j
let
ji
=
JobInfo
{
_ji_message_id
=
messageId
bm
,
_ji_mNode_id
=
getWorkerMNodeId
job
}
let
jh
=
WorkerJobHandle
{
_w_job_info
=
ji
}
runWorkerMonad
env
$
markComplete
jh
notifyJobTimeout
::
(
HasWorkerBroker
PGMQBroker
Job
)
=>
WorkerEnv
->
Worker
.
State
PGMQBroker
Job
->
BrokerMessage
PGMQBroker
(
Worker
.
Job
Job
)
->
IO
()
notifyJobTimeout
env
(
Worker
.
State
{
name
})
bm
=
do
let
j
=
toA
$
getMessage
bm
let
job
=
Worker
.
job
j
withLogger
()
$
\
ioL
->
logMsg
ioL
ERROR
$
"[notifyJobTimeout] ["
<>
name
<>
"] job timed out: "
<>
show
j
let
ji
=
JobInfo
{
_ji_message_id
=
messageId
bm
,
_ji_mNode_id
=
getWorkerMNodeId
job
}
let
jh
=
WorkerJobHandle
{
_w_job_info
=
ji
}
runWorkerMonad
env
$
markFailed
(
Just
$
UnsafeMkHumanFriendlyErrorText
"Worker job timed out!"
)
jh
notifyJobFailed
::
(
HasWorkerBroker
PGMQBroker
Job
)
=>
WorkerEnv
->
Worker
.
State
PGMQBroker
Job
->
BrokerMessage
PGMQBroker
(
Worker
.
Job
Job
)
->
SomeException
->
IO
()
notifyJobFailed
env
(
Worker
.
State
{
name
})
bm
exc
=
do
let
j
=
toA
$
getMessage
bm
let
job
=
Worker
.
job
j
withLogger
()
$
\
ioL
->
logMsg
ioL
ERROR
$
"[notifyJobFailed] ["
<>
name
<>
"] failed job: "
<>
show
j
<>
" --- ERROR: "
<>
show
exc
let
ji
=
JobInfo
{
_ji_message_id
=
messageId
bm
,
_ji_mNode_id
=
getWorkerMNodeId
job
}
let
jh
=
WorkerJobHandle
{
_w_job_info
=
ji
}
runWorkerMonad
env
$
markFailed
(
Just
$
UnsafeMkHumanFriendlyErrorText
"Worker job failed"
)
jh
-- | Spawn a worker with PGMQ broker
-- | Spawn a worker with PGMQ broker
...
@@ -111,9 +158,11 @@ performAction :: (HasWorkerBroker PGMQBroker Job)
...
@@ -111,9 +158,11 @@ performAction :: (HasWorkerBroker PGMQBroker Job)
->
IO
()
->
IO
()
performAction
env
_state
bm
=
do
performAction
env
_state
bm
=
do
let
job'
=
toA
$
getMessage
bm
let
job'
=
toA
$
getMessage
bm
let
ji
=
JobInfo
{
_ji_message_id
=
messageId
bm
}
let
job
=
Worker
.
job
job'
let
ji
=
JobInfo
{
_ji_message_id
=
messageId
bm
,
_ji_mNode_id
=
getWorkerMNodeId
job
}
let
jh
=
WorkerJobHandle
{
_w_job_info
=
ji
}
let
jh
=
WorkerJobHandle
{
_w_job_info
=
ji
}
case
Worker
.
job
job'
of
case
job
of
Ping
->
runWorkerMonad
env
$
do
Ping
->
runWorkerMonad
env
$
do
$
(
logLocM
)
DEBUG
"[performAction] ping"
$
(
logLocM
)
DEBUG
"[performAction] ping"
AddCorpusFormAsync
{
..
}
->
runWorkerMonad
env
$
do
AddCorpusFormAsync
{
..
}
->
runWorkerMonad
env
$
do
...
...
src/Gargantext/Core/Worker/Env.hs
View file @
ea7821be
...
@@ -27,7 +27,7 @@ import Database.PostgreSQL.Simple qualified as PSQL
...
@@ -27,7 +27,7 @@ import Database.PostgreSQL.Simple qualified as PSQL
import
Gargantext.API.Admin.EnvTypes
(
GargJob
,
Mode
(
Dev
),
modeToLoggingLevels
)
import
Gargantext.API.Admin.EnvTypes
(
GargJob
,
Mode
(
Dev
),
modeToLoggingLevels
)
import
Gargantext.API.Admin.Orchestrator.Types
(
JobLog
,
noJobLog
)
import
Gargantext.API.Admin.Orchestrator.Types
(
JobLog
,
noJobLog
)
-- import Gargantext.API.Admin.Settings ( newPool )
-- import Gargantext.API.Admin.Settings ( newPool )
import
Gargantext.API.Job
(
RemainingSteps
(
..
),
jobLogStart
)
import
Gargantext.API.Job
(
RemainingSteps
(
..
),
jobLogStart
,
jobLogProgress
,
jobLogFailures
,
jobLogComplete
,
addErrorEvent
,
jobLogFailTotal
,
jobLogFailTotalWithMessage
,
jobLogAddMore
)
import
Gargantext.API.Prelude
(
GargM
)
import
Gargantext.API.Prelude
(
GargM
)
import
Gargantext.Core.Notifications.CentralExchange
qualified
as
CE
import
Gargantext.Core.Notifications.CentralExchange
qualified
as
CE
import
Gargantext.Core.Notifications.CentralExchange.Types
qualified
as
CET
import
Gargantext.Core.Notifications.CentralExchange.Types
qualified
as
CET
...
@@ -138,7 +138,7 @@ instance CET.HasCentralExchangeNotification WorkerEnv where
...
@@ -138,7 +138,7 @@ instance CET.HasCentralExchangeNotification WorkerEnv where
c
<-
asks
(
view
$
to
_w_env_config
)
c
<-
asks
(
view
$
to
_w_env_config
)
liftBase
$
do
liftBase
$
do
withLogger
()
$
\
ioL
->
withLogger
()
$
\
ioL
->
logMsg
ioL
DEBUG
$
"[ce_notify]
informing about job start
: "
<>
show
(
_gc_notifications_config
c
)
<>
" :: "
<>
show
m
logMsg
ioL
DEBUG
$
"[ce_notify]: "
<>
show
(
_gc_notifications_config
c
)
<>
" :: "
<>
show
m
CE
.
notify
(
_gc_notifications_config
c
)
m
CE
.
notify
(
_gc_notifications_config
c
)
m
---------
---------
...
@@ -230,15 +230,21 @@ instance MonadJobStatus WorkerMonad where
...
@@ -230,15 +230,21 @@ instance MonadJobStatus WorkerMonad where
-- noJobHandle _ = WorkerNoJobHandle
-- noJobHandle _ = WorkerNoJobHandle
-- noJobHandle _ = noJobHandle (Proxy :: Proxy (GargM WorkerEnv IOException)) -- ConcreteNullHandle
-- noJobHandle _ = noJobHandle (Proxy :: Proxy (GargM WorkerEnv IOException)) -- ConcreteNullHandle
noJobHandle
_
=
noJobHandle
(
Proxy
::
Proxy
WorkerMonad
)
noJobHandle
Proxy
=
WorkerNoJobHandle
getLatestJobStatus
_
=
WorkerMonad
(
pure
noJobLog
)
getLatestJobStatus
_
=
WorkerMonad
(
pure
noJobLog
)
withTracer
_
jh
n
=
n
jh
withTracer
_
jh
n
=
n
jh
markStarted
n
jh
=
updateJobProgress
jh
(
const
$
jobLogStart
$
RemainingSteps
n
)
markStarted
n
jh
=
updateJobProgress
jh
(
const
$
jobLogStart
$
RemainingSteps
n
)
markProgress
_
_
=
WorkerMonad
$
pure
()
markProgress
steps
jh
=
updateJobProgress
jh
(
jobLogProgress
steps
)
markFailure
_
_
_
=
WorkerMonad
$
pure
()
markFailure
steps
mb_msg
jh
=
markComplete
_
=
WorkerMonad
$
pure
()
updateJobProgress
jh
(
\
latest
->
case
mb_msg
of
markFailed
_
_
=
WorkerMonad
$
pure
()
Nothing
->
jobLogFailures
steps
latest
addMoreSteps
_
_
=
WorkerMonad
$
pure
()
Just
msg
->
addErrorEvent
msg
(
jobLogFailures
steps
latest
))
markComplete
jh
=
updateJobProgress
jh
jobLogComplete
markFailed
mb_msg
jh
=
updateJobProgress
jh
(
\
latest
->
case
mb_msg
of
Nothing
->
jobLogFailTotal
latest
Just
msg
->
jobLogFailTotalWithMessage
msg
latest
)
addMoreSteps
steps
jh
=
updateJobProgress
jh
(
jobLogAddMore
steps
)
updateJobProgress
::
WorkerJobHandle
->
(
JobLog
->
JobLog
)
->
WorkerMonad
()
updateJobProgress
::
WorkerJobHandle
->
(
JobLog
->
JobLog
)
->
WorkerMonad
()
...
...
src/Gargantext/Core/Worker/Jobs.hs
View file @
ea7821be
...
@@ -42,12 +42,19 @@ sendJob job = do
...
@@ -42,12 +42,19 @@ sendJob job = do
Just
wd
->
liftBase
$
do
Just
wd
->
liftBase
$
do
b
<-
initBrokerWithDBCreate
gcConfig
b
<-
initBrokerWithDBCreate
gcConfig
let
queueName
=
_wdQueue
wd
let
queueName
=
_wdQueue
wd
Worker
.
sendJob'
$
Worker
.
mkDefaultSendJob'
b
queueName
job
Worker
.
sendJob'
$
Worker
.
mkDefaultSendJob
b
queueName
job
(
jobTimeout
job
)
-- | Some predefined job timeouts (in seconds)
jobTimeout
::
Job
->
Int
jobTimeout
(
AddCorpusFormAsync
{})
=
300
jobTimeout
(
AddCorpusWithQuery
{})
=
3000
jobTimeout
_
=
10
-- | This is just a list of what's implemented and what not.
-- | This is just a list of what's implemented and what not.
-- After we migrate to async workers, this should be removed
-- After we migrate to async workers, this should be removed
-- (see G.C.Worker -> performAction on what's implemented already)
-- (see G.C.Worker -> performAction on what's implemented already)
handledJobs
::
[
EnvTypes
.
GargJob
]
handledJobs
::
[
EnvTypes
.
GargJob
]
handledJobs
=
[
EnvTypes
.
AddCorpusQueryJob
handledJobs
=
[
EnvTypes
.
AddCorpusFormJob
,
EnvTypes
.
AddCorpusQueryJob
,
EnvTypes
.
ForgotPasswordJob
]
,
EnvTypes
.
ForgotPasswordJob
]
src/Gargantext/Core/Worker/Jobs/Types.hs
View file @
ea7821be
...
@@ -18,9 +18,9 @@ import Data.Aeson.Types (prependFailure, typeMismatch)
...
@@ -18,9 +18,9 @@ import Data.Aeson.Types (prependFailure, typeMismatch)
import
Gargantext.API.Admin.Auth.Types
(
AuthenticatedUser
,
ForgotPasswordAsyncParams
)
import
Gargantext.API.Admin.Auth.Types
(
AuthenticatedUser
,
ForgotPasswordAsyncParams
)
import
Gargantext.API.Admin.EnvTypes
(
GargJob
)
import
Gargantext.API.Admin.EnvTypes
(
GargJob
)
import
Gargantext.API.Node.New.Types
(
PostNode
(
..
)
)
import
Gargantext.API.Node.New.Types
(
PostNode
(
..
)
)
import
Gargantext.API.Node.Types
(
NewWithForm
,
WithQuery
)
import
Gargantext.API.Node.Types
(
NewWithForm
,
WithQuery
(
..
)
)
import
Gargantext.Core.Types.Individu
(
User
)
import
Gargantext.Core.Types.Individu
(
User
)
import
Gargantext.Database.Admin.Types.Node
(
CorpusId
,
NodeId
)
import
Gargantext.Database.Admin.Types.Node
(
CorpusId
,
NodeId
(
UnsafeMkNodeId
)
)
import
Gargantext.Prelude
import
Gargantext.Prelude
...
@@ -66,25 +66,44 @@ instance FromJSON Job where
...
@@ -66,25 +66,44 @@ instance FromJSON Job where
return
$
GargJob
{
_gj_garg_job
}
return
$
GargJob
{
_gj_garg_job
}
s
->
prependFailure
"parsing job type failed, "
(
typeMismatch
"type"
s
)
s
->
prependFailure
"parsing job type failed, "
(
typeMismatch
"type"
s
)
instance
ToJSON
Job
where
instance
ToJSON
Job
where
toJSON
Ping
=
object
[
(
"type"
.=
(
"Ping"
::
Text
)
)
]
toJSON
Ping
=
object
[
"type"
.=
(
"Ping"
::
Text
)
]
toJSON
(
AddCorpusFormAsync
{
..
})
=
toJSON
(
AddCorpusFormAsync
{
..
})
=
object
[
(
"type"
.=
(
"AddCorpusFormAsync"
::
Text
)
)
object
[
"type"
.=
(
"AddCorpusFormAsync"
::
Text
)
,
(
"args"
.=
_acf_args
)
,
"args"
.=
_acf_args
,
(
"user"
.=
_acf_user
)
,
"user"
.=
_acf_user
,
(
"cid"
.=
_acf_cid
)
]
,
"cid"
.=
_acf_cid
]
toJSON
(
AddCorpusWithQuery
{
..
})
=
toJSON
(
AddCorpusWithQuery
{
..
})
=
object
[
(
"type"
.=
(
"AddCorpusWithQuery"
::
Text
)
)
object
[
"type"
.=
(
"AddCorpusWithQuery"
::
Text
)
,
(
"args"
.=
_acq_args
)
,
"args"
.=
_acq_args
,
(
"user"
.=
_acq_user
)
,
"user"
.=
_acq_user
,
(
"cid"
.=
_acq_cid
)
]
,
"cid"
.=
_acq_cid
]
toJSON
(
ForgotPasswordAsync
{
..
})
=
toJSON
(
ForgotPasswordAsync
{
..
})
=
object
[
(
"type"
.=
(
"ForgotPasswordAsync"
::
Text
)
)
object
[
"type"
.=
(
"ForgotPasswordAsync"
::
Text
)
,
(
"args"
.=
_fpa_args
)
]
,
"args"
.=
_fpa_args
]
toJSON
(
NewNodeAsync
{
..
})
=
toJSON
(
NewNodeAsync
{
..
})
=
object
[
(
"type"
.=
(
"NewNodeAsync"
::
Text
)
)
object
[
"type"
.=
(
"NewNodeAsync"
::
Text
)
,
(
"node_id"
.=
_nna_node_id
)
,
"node_id"
.=
_nna_node_id
,
(
"authenticated_user"
.=
_nna_authenticatedUser
)
,
"authenticated_user"
.=
_nna_authenticatedUser
,
(
"post_node"
.=
_nna_postNode
)
]
,
"post_node"
.=
_nna_postNode
]
toJSON
(
GargJob
{
..
})
=
toJSON
(
GargJob
{
..
})
=
object
[
(
"type"
.=
(
"GargJob"
::
Text
))
object
[
"type"
.=
(
"GargJob"
::
Text
)
,
(
"garg_job"
.=
_gj_garg_job
)
]
,
"garg_job"
.=
_gj_garg_job
]
-- | We want to have a way to specify 'Maybe NodeId' from given worker
-- parameters. The given 'Maybe CorpusId' is an alternative, when
-- params don't have node id access.
-- class HasWorkerNodeId input where
-- getMNodeId :: job -> Maybe CorpusId -> Maybe NodeId
getWorkerMNodeId
::
Job
->
Maybe
NodeId
getWorkerMNodeId
Ping
=
Nothing
getWorkerMNodeId
(
AddCorpusFormAsync
{
_acf_args
,
_acf_cid
})
=
Just
_acf_cid
getWorkerMNodeId
(
AddCorpusWithQuery
{
_acq_args
=
WithQuery
{
_wq_node_id
}})
=
Just
$
UnsafeMkNodeId
_wq_node_id
getWorkerMNodeId
(
NewNodeAsync
{
_nna_node_id
})
=
Just
_nna_node_id
getWorkerMNodeId
(
ForgotPasswordAsync
{})
=
Nothing
getWorkerMNodeId
(
GargJob
{})
=
Nothing
src/Gargantext/Core/Worker/Types.hs
View file @
ea7821be
...
@@ -15,11 +15,15 @@ import Async.Worker.Broker.PGMQ (PGMQBroker)
...
@@ -15,11 +15,15 @@ import Async.Worker.Broker.PGMQ (PGMQBroker)
import
Async.Worker.Broker.Types
qualified
as
BT
import
Async.Worker.Broker.Types
qualified
as
BT
import
Data.Aeson
((
.=
),
(
.:
),
object
,
withObject
)
import
Data.Aeson
((
.=
),
(
.:
),
object
,
withObject
)
import
Data.Swagger
(
NamedSchema
(
..
),
ToSchema
(
..
))
-- , genericDeclareNamedSchema)
import
Data.Swagger
(
NamedSchema
(
..
),
ToSchema
(
..
))
-- , genericDeclareNamedSchema)
import
Gargantext.Core.Types
(
NodeId
)
import
Gargantext.Prelude
import
Gargantext.Prelude
data
JobInfo
=
JobInfo
{
_ji_message_id
::
!
(
BT
.
MessageId
PGMQBroker
)
}
data
JobInfo
=
JobInfo
{
_ji_message_id
::
BT
.
MessageId
PGMQBroker
-- NOTE: Most jobs are associated with node id.
-- The 'node_id' allows the frontend to assign progress bar to a node.
,
_ji_mNode_id
::
Maybe
NodeId
}
deriving
(
Show
,
Eq
,
Ord
,
Generic
)
deriving
(
Show
,
Eq
,
Ord
,
Generic
)
instance
ToSchema
JobInfo
where
-- TODO
instance
ToSchema
JobInfo
where
-- TODO
--declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_ji_")
--declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_ji_")
...
@@ -28,7 +32,9 @@ instance ToSchema JobInfo where -- TODO
...
@@ -28,7 +32,9 @@ instance ToSchema JobInfo where -- TODO
instance
FromJSON
JobInfo
where
instance
FromJSON
JobInfo
where
parseJSON
=
withObject
"JobInfo"
$
\
o
->
do
parseJSON
=
withObject
"JobInfo"
$
\
o
->
do
_ji_message_id
<-
o
.:
"message_id"
_ji_message_id
<-
o
.:
"message_id"
_ji_mNode_id
<-
o
.:
"node_id"
pure
$
JobInfo
{
..
}
pure
$
JobInfo
{
..
}
instance
ToJSON
JobInfo
where
instance
ToJSON
JobInfo
where
toJSON
(
JobInfo
{
..
})
=
object
[
(
"message_id"
.=
_ji_message_id
)]
toJSON
(
JobInfo
{
..
})
=
object
[
"message_id"
.=
_ji_message_id
,
"node_id"
.=
_ji_mNode_id
]
src/Gargantext/Database/Query/Table/Node/UpdateOpaleye.hs
View file @
ea7821be
...
@@ -21,7 +21,7 @@ import Gargantext.Database.Query.Table.Node ( getNodeWithType, getNodesIdWithTyp
...
@@ -21,7 +21,7 @@ import Gargantext.Database.Query.Table.Node ( getNodeWithType, getNodesIdWithTyp
import
Gargantext.Database.Query.Table.Node.Error
(
HasNodeError
)
import
Gargantext.Database.Query.Table.Node.Error
(
HasNodeError
)
import
Gargantext.Database.Schema.Node
import
Gargantext.Database.Schema.Node
import
Gargantext.Prelude
import
Gargantext.Prelude
import
Gargantext.System.Logging
(
withLogger
,
logMsg
,
LogLevel
(
..
))
--
import Gargantext.System.Logging (withLogger, logMsg, LogLevel(..))
import
Opaleye
import
Opaleye
-- import Debug.Trace (trace)
-- import Debug.Trace (trace)
...
@@ -29,17 +29,14 @@ import Opaleye
...
@@ -29,17 +29,14 @@ import Opaleye
updateHyperdata
::
HyperdataC
a
=>
NodeId
->
a
->
DBCmd
err
Int64
updateHyperdata
::
HyperdataC
a
=>
NodeId
->
a
->
DBCmd
err
Int64
updateHyperdata
i
h
=
do
updateHyperdata
i
h
=
do
mkCmd
$
\
c
->
do
mkCmd
$
\
c
->
do
res
<-
withLogger
()
$
\
ioLogger
->
do
-- res <- withLogger () $ \ioLogger -> do
logMsg
ioLogger
DEBUG
"[updateHyperdata] before runUpdate_"
-- logMsg ioLogger DEBUG "[updateHyperdata] before runUpdate_"
liftBase
$
putText
"[updateHyperdata] before runUpdate_"
res
<-
runUpdate_
c
$
updateHyperdataQuery
i
h
res
<-
runUpdate_
c
$
updateHyperdataQuery
i
h
logMsg
ioLogger
DEBUG
$
"[updateHyperdata] after runUpdate_: "
<>
show
res
-- logMsg ioLogger DEBUG $ "[updateHyperdata] after runUpdate_: " <> show res
liftBase
putText
$
"[updateHyperdata] after runUpdate_: "
<>
show
res
pure
res
pure
res
withLogger
()
$
\
ioLogger
->
do
-- withLogger () $ \ioLogger -> do
logMsg
ioLogger
DEBUG
$
"[updateHyperdata] after mkCmd"
-- logMsg ioLogger DEBUG $ "[updateHyperdata] after mkCmd"
liftBase
putText
$
"[updateHyperdata] after mkCmd"
-- pure res
pure
res
updateHyperdataQuery
::
HyperdataC
a
=>
NodeId
->
a
->
Update
Int64
updateHyperdataQuery
::
HyperdataC
a
=>
NodeId
->
a
->
Update
Int64
updateHyperdataQuery
i
h
=
seq
h'
$
{- trace "updateHyperdataQuery: encoded JSON" $ -}
Update
updateHyperdataQuery
i
h
=
seq
h'
$
{- trace "updateHyperdataQuery: encoded JSON" $ -}
Update
...
...
src/Gargantext/Utils/Jobs/Error.hs
View file @
ea7821be
{-# LANGUAGE LambdaCase #-}
{-|
Module : Gargantext.Utils.Jobs.Error
Description : Error utilities
Copyright : (c) CNRS, 2024
License : AGPL + CECILL v3
Maintainer : team@gargantext.org
Stability : experimental
Portability : POSIX
-}
module
Gargantext.Utils.Jobs.Error
module
Gargantext.Utils.Jobs.Error
(
ToHumanFriendlyError
(
..
)
(
ToHumanFriendlyError
(
..
)
...
...
test/Test/API/Notifications.hs
View file @
ea7821be
...
@@ -39,6 +39,11 @@ import Test.Hspec
...
@@ -39,6 +39,11 @@ import Test.Hspec
import
Test.Instances
()
import
Test.Instances
()
instance
Eq
DT
.
Notification
where
-- simple
(
==
)
n1
n2
=
show
n1
==
show
n2
tests
::
NotificationsConfig
->
D
.
Dispatcher
->
Spec
tests
::
NotificationsConfig
->
D
.
Dispatcher
->
Spec
tests
nc
dispatcher
=
sequential
$
aroundAll
(
withTestDBAndNotifications
dispatcher
)
$
do
tests
nc
dispatcher
=
sequential
$
aroundAll
(
withTestDBAndNotifications
dispatcher
)
$
do
describe
"Dispatcher, Central Exchange, WebSockets"
$
do
describe
"Dispatcher, Central Exchange, WebSockets"
$
do
...
@@ -61,15 +66,13 @@ tests nc dispatcher = sequential $ aroundAll (withTestDBAndNotifications dispatc
...
@@ -61,15 +66,13 @@ tests nc dispatcher = sequential $ aroundAll (withTestDBAndNotifications dispatc
withAsync
wsConnect
$
\
_a
->
do
withAsync
wsConnect
$
\
_a
->
do
-- wait a bit to connect
-- wait a bit to connect
threadDelay
(
500
*
millisecond
)
threadDelay
(
500
*
millisecond
)
CE
.
notify
nc
$
CET
.
UpdateTreeFirstLevel
0
let
nodeId
=
0
CE
.
notify
nc
$
CET
.
UpdateTreeFirstLevel
nodeId
md
<-
atomically
$
readTChan
tchan
md
<-
atomically
$
readTChan
tchan
md
`
shouldSatisfy
`
isJust
md
`
shouldBe
`
Just
(
DT
.
NUpdateTree
nodeId
)
let
(
Just
(
DT
.
Notification
topic'
message'
))
=
md
topic'
`
shouldBe
`
topic
message'
`
shouldBe
`
DT
.
MEmpty
millisecond
::
Int
millisecond
::
Int
...
...
test/Test/API/UpdateList.hs
View file @
ea7821be
...
@@ -41,6 +41,7 @@ import Gargantext.API.Routes.Named
...
@@ -41,6 +41,7 @@ import Gargantext.API.Routes.Named
import
Gargantext.API.Routes.Named.Corpus
import
Gargantext.API.Routes.Named.Corpus
import
Gargantext.API.Routes.Named.Node
import
Gargantext.API.Routes.Named.Node
import
Gargantext.API.Routes.Named.Private
import
Gargantext.API.Routes.Named.Private
import
Gargantext.API.Worker
(
workerAPIPost
)
import
Gargantext.Core
qualified
as
Lang
import
Gargantext.Core
qualified
as
Lang
import
Gargantext.Core.Text.Corpus.Query
(
RawQuery
(
..
))
import
Gargantext.Core.Text.Corpus.Query
(
RawQuery
(
..
))
import
Gargantext.Core.Text.List.Social
import
Gargantext.Core.Text.List.Social
...
@@ -49,6 +50,7 @@ import Gargantext.Core.Types ( CorpusId, ListId, NodeId, _NodeId)
...
@@ -49,6 +50,7 @@ import Gargantext.Core.Types ( CorpusId, ListId, NodeId, _NodeId)
import
Gargantext.Core.Types.Individu
import
Gargantext.Core.Types.Individu
import
Gargantext.Core.Types.Main
(
ListType
(
..
))
import
Gargantext.Core.Types.Main
(
ListType
(
..
))
import
Gargantext.Core.Types
(
TableResult
(
..
))
import
Gargantext.Core.Types
(
TableResult
(
..
))
import
Gargantext.Core.Worker.Types
(
JobInfo
)
import
Gargantext.Database.Action.User
import
Gargantext.Database.Action.User
import
Gargantext.Database.Admin.Types.Hyperdata.Corpus
import
Gargantext.Database.Admin.Types.Hyperdata.Corpus
import
Gargantext.Database.Admin.Types.Hyperdata.Folder
(
defaultHyperdataFolderPrivate
)
import
Gargantext.Database.Admin.Types.Hyperdata.Folder
(
defaultHyperdataFolderPrivate
)
...
@@ -351,10 +353,13 @@ createDocsList testDataPath testEnv port clientEnv token = do
...
@@ -351,10 +353,13 @@ createDocsList testDataPath testEnv port clientEnv token = do
-- Import the docsList with only two documents, both containing a \"fortran\" term.
-- Import the docsList with only two documents, both containing a \"fortran\" term.
simpleDocs
<-
liftIO
(
TIO
.
readFile
=<<
getDataFileName
testDataPath
)
simpleDocs
<-
liftIO
(
TIO
.
readFile
=<<
getDataFileName
testDataPath
)
let
newWithForm
=
mkNewWithForm
simpleDocs
(
T
.
pack
$
takeBaseName
testDataPath
)
let
newWithForm
=
mkNewWithForm
simpleDocs
(
T
.
pack
$
takeBaseName
testDataPath
)
(
j
::
JobPollHandle
)
<-
checkEither
$
fmap
toJobPollHandle
<$>
liftIO
(
runClientM
(
add_file_async
token
corpusId
newWithForm
)
clientEnv
)
-- (j :: JobPollHandle) <- checkEither $ fmap toJobPollHandle <$> liftIO (runClientM (add_file_async token corpusId newWithForm) clientEnv)
let
mkPollUrl
jh
=
"/corpus/"
<>
fromString
(
show
$
_NodeId
corpusId
)
<>
"/add/form/async/"
+|
_jph_id
jh
|+
"/poll?limit=1"
ji
<-
checkEither
$
liftIO
$
runClientM
(
add_file_async
token
corpusId
newWithForm
)
clientEnv
j'
<-
pollUntilFinished
token
port
mkPollUrl
j
-- let mkPollUrl jh = "/corpus/" <> fromString (show $ _NodeId corpusId) <> "/add/form/async/" +|_jph_id jh|+ "/poll?limit=1"
liftIO
(
_jph_status
j'
`
shouldBe
`
"IsFinished"
)
-- j' <- pollUntilFinished token port mkPollUrl j
-- liftIO (_jph_status j' `shouldBe` "IsFinished")
j'
<-
pollUntilWorkFinished
token
port
ji
liftIO
$
j'
`
shouldSatisfy
`
isRight
pure
corpusId
pure
corpusId
createFortranDocsList
::
TestEnv
->
Int
->
ClientEnv
->
Token
->
WaiSession
()
CorpusId
createFortranDocsList
::
TestEnv
->
Int
->
ClientEnv
->
Token
->
WaiSession
()
CorpusId
...
@@ -388,7 +393,7 @@ mkNewWithForm content name = NewWithForm
...
@@ -388,7 +393,7 @@ mkNewWithForm content name = NewWithForm
add_file_async
::
Token
add_file_async
::
Token
->
CorpusId
->
CorpusId
->
NewWithForm
->
NewWithForm
->
ClientM
(
JobStatus
'S
a
fe
JobLog
)
->
ClientM
JobInfo
add_file_async
(
toServantToken
->
token
)
corpusId
nwf
=
add_file_async
(
toServantToken
->
token
)
corpusId
nwf
=
clientRoutes
&
apiWithCustomErrorScheme
clientRoutes
&
apiWithCustomErrorScheme
&
(
$
GES_new
)
&
(
$
GES_new
)
...
@@ -402,8 +407,8 @@ add_file_async (toServantToken -> token) corpusId nwf =
...
@@ -402,8 +407,8 @@ add_file_async (toServantToken -> token) corpusId nwf =
&
addWithFormAPI
&
addWithFormAPI
&
addWithFormEp
&
addWithFormEp
&
(
$
corpusId
)
&
(
$
corpusId
)
&
asyncJobsAPI'
&
workerAPIPost
&
(
\
(
_
:<|>
submitForm
:<|>
_
)
->
submitForm
(
JobInput
nwf
Nothing
)
)
&
(
\
submitForm
->
submitForm
nwf
)
-- | Utility to trash a document by performing a raw query towards GQL. Not very type safe,
-- | Utility to trash a document by performing a raw query towards GQL. Not very type safe,
...
...
test/Test/Utils.hs
View file @
ea7821be
...
@@ -5,26 +5,27 @@ module Test.Utils where
...
@@ -5,26 +5,27 @@ module Test.Utils where
import
Control.Exception.Safe
()
import
Control.Exception.Safe
()
import
Control.Monad
()
import
Control.Monad
()
import
Data.Aeson.KeyMap
qualified
as
KM
import
Data.Aeson
qualified
as
JSON
import
Data.Aeson
qualified
as
JSON
import
Data.Aeson.KeyMap
qualified
as
KM
import
Data.ByteString.Char8
qualified
as
B
import
Data.ByteString.Char8
qualified
as
B
import
Data.ByteString.Lazy
qualified
as
L
import
Data.ByteString.Lazy
qualified
as
L
import
Data.Map.Strict
qualified
as
Map
import
Data.Map.Strict
qualified
as
Map
import
Data.Text
qualified
as
T
import
Data.Text.Encoding
qualified
as
TE
import
Data.Text.Encoding
qualified
as
TE
import
Data.Text.Lazy.Encoding
qualified
as
TLE
import
Data.Text.Lazy
qualified
as
TL
import
Data.Text.Lazy
qualified
as
TL
import
Data.Text
qualified
as
T
import
Data.Text
.Lazy.Encoding
qualified
as
TLE
import
Data.TreeDiff
import
Data.TreeDiff
import
Fmt
(
Builder
)
import
Fmt
(
Builder
)
import
Gargantext.API.Admin.Auth.Types
(
AuthRequest
(
..
),
Token
,
authRes_token
)
import
Gargantext.API.Admin.Auth.Types
(
AuthRequest
(
..
),
Token
,
authRes_token
)
import
Gargantext.API.Admin.Orchestrator.Types
import
Gargantext.API.Admin.Orchestrator.Types
import
Gargantext.API.Routes.Types
(
xGargErrorScheme
)
import
Gargantext.API.Routes.Types
(
xGargErrorScheme
)
import
Gargantext.Core.Types.Individu
(
Username
,
GargPassword
)
import
Gargantext.Core.Types.Individu
(
Username
,
GargPassword
)
import
Gargantext.Core.Worker.Types
(
JobInfo
(
..
))
import
Gargantext.Prelude
import
Gargantext.Prelude
import
Network.HTTP.Client
(
defaultManagerSettings
,
newManager
)
import
Network.HTTP.Client
(
defaultManagerSettings
,
newManager
)
import
Network.HTTP.Client
qualified
as
HTTP
import
Network.HTTP.Client
qualified
as
HTTP
import
Network.HTTP.Types.Header
(
hAccept
,
hAuthorization
,
hContentType
)
import
Network.HTTP.Types
(
Header
,
Method
,
status200
)
import
Network.HTTP.Types
(
Header
,
Method
,
status200
)
import
Network.HTTP.Types.Header
(
hAccept
,
hAuthorization
,
hContentType
)
import
Network.Wai.Handler.Warp
(
Port
)
import
Network.Wai.Handler.Warp
(
Port
)
import
Network.Wai.Test
(
SResponse
(
..
))
import
Network.Wai.Test
(
SResponse
(
..
))
import
Prelude
qualified
import
Prelude
qualified
...
@@ -35,8 +36,8 @@ import System.Environment (lookupEnv)
...
@@ -35,8 +36,8 @@ import System.Environment (lookupEnv)
import
System.Timeout
qualified
as
Timeout
import
System.Timeout
qualified
as
Timeout
import
Test.API.Routes
(
auth_api
,
mkUrl
)
import
Test.API.Routes
(
auth_api
,
mkUrl
)
import
Test.Hspec.Expectations
import
Test.Hspec.Expectations
import
Test.Hspec.Wai.JSON
(
FromValue
(
..
))
import
Test.Hspec.Wai
(
MatchBody
(
..
),
WaiExpectation
,
WaiSession
,
request
)
import
Test.Hspec.Wai
(
MatchBody
(
..
),
WaiExpectation
,
WaiSession
,
request
)
import
Test.Hspec.Wai.JSON
(
FromValue
(
..
))
import
Test.Hspec.Wai.Matcher
(
MatchHeader
(
..
),
ResponseMatcher
(
..
),
bodyEquals
,
formatHeader
,
match
)
import
Test.Hspec.Wai.Matcher
(
MatchHeader
(
..
),
ResponseMatcher
(
..
),
bodyEquals
,
formatHeader
,
match
)
import
Test.Tasty.HUnit
(
Assertion
,
assertBool
)
import
Test.Tasty.HUnit
(
Assertion
,
assertBool
)
import
Test.Types
import
Test.Types
...
@@ -236,6 +237,35 @@ pollUntilFinished tkn port mkUrlPiece = go 60
...
@@ -236,6 +237,35 @@ pollUntilFinished tkn port mkUrlPiece = go 60
Nothing
->
False
Nothing
->
False
Just
errs
->
errs
>
1
Just
errs
->
errs
>
1
pollUntilWorkFinished
::
HasCallStack
=>
Token
->
Port
->
JobInfo
->
WaiSession
()
JobInfo
pollUntilWorkFinished
tkn
port
=
go
60
-- TODO Poll dispatcher for markJobFinished
where
go
::
Int
->
JobInfo
->
WaiSession
()
JobInfo
go
0
ji
=
panicTrace
$
"pollUntilWorkFinished exhausted attempts. Last found JobInfo: "
<>
TE
.
decodeUtf8
(
L
.
toStrict
$
JSON
.
encode
ji
)
go
n
ji
=
case
_jph_status
h
==
"IsPending"
||
_jph_status
h
==
"IsRunning"
of
True
->
do
liftIO
$
threadDelay
1
_000_000
h'
<-
protectedJSON
tkn
"GET"
(
mkUrl
port
$
mkUrlPiece
h
)
""
go
(
n
-
1
)
h'
False
|
_jph_status
h
==
"IsFailure"
->
panicTrace
$
"JobPollHandle contains a failure: "
<>
TE
.
decodeUtf8
(
L
.
toStrict
$
JSON
.
encode
h
)
|
otherwise
->
case
any
hasError
(
_jph_log
h
)
of
True
->
panicTrace
$
"JobPollHandle contains a failure: "
<>
TE
.
decodeUtf8
(
L
.
toStrict
$
JSON
.
encode
h
)
False
->
pure
h
-- FIXME(adn) This is wrong, errs should be >= 1.
hasError
::
JobLog
->
Bool
hasError
JobLog
{
..
}
=
case
_scst_failed
of
Nothing
->
False
Just
errs
->
errs
>
1
-- | Like HUnit's '@?=', but With a nicer error message in case the two entities are not equal.
-- | Like HUnit's '@?=', but With a nicer error message in case the two entities are not equal.
(
@??=
)
::
(
HasCallStack
,
ToExpr
a
,
Eq
a
)
=>
a
->
a
->
Assertion
(
@??=
)
::
(
HasCallStack
,
ToExpr
a
,
Eq
a
)
=>
a
->
a
->
Assertion
actual
@??=
expected
=
actual
@??=
expected
=
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment