From cd1dfa04e35c9211368aadb39111a8377ee416b7 Mon Sep 17 00:00:00 2001 From: qqmyers Date: Wed, 20 Jan 2021 13:47:48 -0500 Subject: [PATCH 1/6] Don't call Finalize if pre-pub workflow exists --- .../engine/command/impl/PublishDatasetCommand.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/PublishDatasetCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/PublishDatasetCommand.java index 66f0838de23..88bfe832cd4 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/PublishDatasetCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/PublishDatasetCommand.java @@ -213,7 +213,11 @@ public boolean onSuccess(CommandContext ctxt, Object r) { if (dataset != null) { logger.fine("From onSuccess, calling FinalizeDatasetPublicationCommand for dataset " + dataset.getGlobalId().asString()); - ctxt.datasets().callFinalizePublishCommandAsynchronously(dataset.getId(), ctxt, request, datasetExternallyReleased); + Optional prePubWf = ctxt.workflows().getDefaultWorkflow(TriggerType.PrePublishDataset); + //A pre-publication workflow will call this when it completes + if (! prePubWf.isPresent() ) { + ctxt.datasets().callFinalizePublishCommandAsynchronously(dataset.getId(), ctxt, request, datasetExternallyReleased); + } return true; } From 6edf1ea502c75685f3ea1db8df7d4c50b1818692 Mon Sep 17 00:00:00 2001 From: qqmyers Date: Thu, 21 Jan 2021 13:51:07 -0500 Subject: [PATCH 2/6] keep invocationId when refreshing --- .../iq/dataverse/workflow/WorkflowServiceBean.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/workflow/WorkflowServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/workflow/WorkflowServiceBean.java index 5795556b9d8..0df3ec011b3 100644 --- a/src/main/java/edu/harvard/iq/dataverse/workflow/WorkflowServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/workflow/WorkflowServiceBean.java @@ -429,9 +429,12 @@ private WorkflowContext refresh( WorkflowContext ctxt, Map setti * resumed workflows. (The overall method is needed to allow the context to be updated in the start() method with the * settings and APItoken retrieved by the WorkflowServiceBean) - JM - 9/18. */ - return new WorkflowContext( ctxt.getRequest(), - em.merge(ctxt.getDataset()), ctxt.getNextVersionNumber(), - ctxt.getNextMinorVersionNumber(), ctxt.getType(), settings, apiToken, ctxt.getDatasetExternallyReleased()); + String id = ctxt.getInvocationId(); + WorkflowContext newCtxt =new WorkflowContext( ctxt.getRequest(), + em.merge(ctxt.getDataset()), ctxt.getNextVersionNumber(), + ctxt.getNextMinorVersionNumber(), ctxt.getType(), settings, apiToken, ctxt.getDatasetExternallyReleased()); + newCtxt.setInvocationId(id); + return newCtxt; } } From 359f3654ade387f3be9fa58548471b71d75bd82d Mon Sep 17 00:00:00 2001 From: qqmyers Date: Thu, 21 Jan 2021 13:54:39 -0500 Subject: [PATCH 3/6] keep original inovcationId when refreshing --- .../iq/dataverse/workflow/WorkflowServiceBean.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/workflow/WorkflowServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/workflow/WorkflowServiceBean.java index 5795556b9d8..0df3ec011b3 100644 --- a/src/main/java/edu/harvard/iq/dataverse/workflow/WorkflowServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/workflow/WorkflowServiceBean.java @@ -429,9 +429,12 @@ private WorkflowContext refresh( WorkflowContext ctxt, Map setti * resumed workflows. (The overall method is needed to allow the context to be updated in the start() method with the * settings and APItoken retrieved by the WorkflowServiceBean) - JM - 9/18. */ - return new WorkflowContext( ctxt.getRequest(), - em.merge(ctxt.getDataset()), ctxt.getNextVersionNumber(), - ctxt.getNextMinorVersionNumber(), ctxt.getType(), settings, apiToken, ctxt.getDatasetExternallyReleased()); + String id = ctxt.getInvocationId(); + WorkflowContext newCtxt =new WorkflowContext( ctxt.getRequest(), + em.merge(ctxt.getDataset()), ctxt.getNextVersionNumber(), + ctxt.getNextMinorVersionNumber(), ctxt.getType(), settings, apiToken, ctxt.getDatasetExternallyReleased()); + newCtxt.setInvocationId(id); + return newCtxt; } } From e5f7fb8bc825f147afea922bf10ab4219ba07c39 Mon Sep 17 00:00:00 2001 From: qqmyers Date: Thu, 21 Jan 2021 14:11:18 -0500 Subject: [PATCH 4/6] move logging statement to correct place --- .../engine/command/impl/PublishDatasetCommand.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/PublishDatasetCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/PublishDatasetCommand.java index 88bfe832cd4..15485b0097e 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/PublishDatasetCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/PublishDatasetCommand.java @@ -212,12 +212,12 @@ public boolean onSuccess(CommandContext ctxt, Object r) { } if (dataset != null) { - logger.fine("From onSuccess, calling FinalizeDatasetPublicationCommand for dataset " + dataset.getGlobalId().asString()); Optional prePubWf = ctxt.workflows().getDefaultWorkflow(TriggerType.PrePublishDataset); - //A pre-publication workflow will call this when it completes + //A pre-publication workflow will call FinalizeDatasetPublicationCommand itself when it completes if (! prePubWf.isPresent() ) { + logger.fine("From onSuccess, calling FinalizeDatasetPublicationCommand for dataset " + dataset.getGlobalId().asString()); ctxt.datasets().callFinalizePublishCommandAsynchronously(dataset.getId(), ctxt, request, datasetExternallyReleased); - } + } return true; } From 8f169cc7bef7d53b434b183fab07086b24904404 Mon Sep 17 00:00:00 2001 From: qqmyers Date: Thu, 21 Jan 2021 14:31:46 -0500 Subject: [PATCH 5/6] per review - adding a constructor with invocationId instead --- .../iq/dataverse/workflow/WorkflowContext.java | 11 +++++++++-- .../iq/dataverse/workflow/WorkflowServiceBean.java | 4 +--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/workflow/WorkflowContext.java b/src/main/java/edu/harvard/iq/dataverse/workflow/WorkflowContext.java index 6ea87a27013..39284f5bc8b 100644 --- a/src/main/java/edu/harvard/iq/dataverse/workflow/WorkflowContext.java +++ b/src/main/java/edu/harvard/iq/dataverse/workflow/WorkflowContext.java @@ -40,9 +40,13 @@ public WorkflowContext( DataverseRequest aRequest, Dataset aDataset, TriggerType aDataset.getLatestVersion().getMinorVersionNumber(), aTriggerType, null, null, datasetExternallyReleased); } - public WorkflowContext(DataverseRequest request, Dataset dataset, long nextVersionNumber, - long nextMinorVersionNumber, TriggerType type, Map settings, ApiToken apiToken, boolean datasetExternallyReleased) { + long nextMinorVersionNumber, TriggerType type, Map settings, ApiToken apiToken, boolean datasetExternallyReleased) { + this(request, dataset, nextVersionNumber,nextMinorVersionNumber, type, settings, apiToken, datasetExternallyReleased, null); + } + + public WorkflowContext(DataverseRequest request, Dataset dataset, long nextVersionNumber, + long nextMinorVersionNumber, TriggerType type, Map settings, ApiToken apiToken, boolean datasetExternallyReleased, String invocationId) { this.request = request; this.dataset = dataset; this.nextVersionNumber = nextVersionNumber; @@ -51,6 +55,9 @@ public WorkflowContext(DataverseRequest request, Dataset dataset, long nextVersi this.settings = settings; this.apiToken = apiToken; this.datasetExternallyReleased = datasetExternallyReleased; + if(invocationId!=null) { + setInvocationId(invocationId); + } } public Dataset getDataset() { diff --git a/src/main/java/edu/harvard/iq/dataverse/workflow/WorkflowServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/workflow/WorkflowServiceBean.java index 0df3ec011b3..0538ab9851e 100644 --- a/src/main/java/edu/harvard/iq/dataverse/workflow/WorkflowServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/workflow/WorkflowServiceBean.java @@ -429,11 +429,9 @@ private WorkflowContext refresh( WorkflowContext ctxt, Map setti * resumed workflows. (The overall method is needed to allow the context to be updated in the start() method with the * settings and APItoken retrieved by the WorkflowServiceBean) - JM - 9/18. */ - String id = ctxt.getInvocationId(); WorkflowContext newCtxt =new WorkflowContext( ctxt.getRequest(), em.merge(ctxt.getDataset()), ctxt.getNextVersionNumber(), - ctxt.getNextMinorVersionNumber(), ctxt.getType(), settings, apiToken, ctxt.getDatasetExternallyReleased()); - newCtxt.setInvocationId(id); + ctxt.getNextMinorVersionNumber(), ctxt.getType(), settings, apiToken, ctxt.getDatasetExternallyReleased(), ctxt.getInvocationId()); return newCtxt; } From 7a04ae30caefc2d58afa246c7fdaaea04503ef7a Mon Sep 17 00:00:00 2001 From: qqmyers Date: Thu, 21 Jan 2021 14:41:15 -0500 Subject: [PATCH 6/6] Updating documentation re: restarting https/r and paused workflows --- doc/sphinx-guides/source/developers/workflows.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/sphinx-guides/source/developers/workflows.rst b/doc/sphinx-guides/source/developers/workflows.rst index b9090b86be3..ec02aa803e1 100644 --- a/doc/sphinx-guides/source/developers/workflows.rst +++ b/doc/sphinx-guides/source/developers/workflows.rst @@ -16,7 +16,7 @@ Workflow steps are created using *step providers*. Dataverse ships with an inter Steps can be internal (say, writing some data to the log) or external. External steps involve Dataverse sending a request to an external system, and waiting for the system to reply. The wait period is arbitrary, and so allows the external system unbounded operation time. This is useful, e.g., for steps that require human intervension, such as manual approval of a dataset publication. -The external system reports the step result back to dataverse, by sending a HTTP ``POST`` command to ``api/workflows/{invocation-id}``. The body of the request is passed to the paused step for further processing. +The external system reports the step result back to dataverse, by sending a HTTP ``POST`` command to ``api/workflows/{invocation-id}`` with Content-Type: text/plain. The body of the request is passed to the paused step for further processing. If a step in a workflow fails, Dataverse make an effort to roll back all the steps that preceded it. Some actions, such as writing to the log, cannot be rolled back. If such an action has a public external effect (e.g. send an EMail to a mailing list) it is advisable to put it in the post-release workflow. @@ -60,7 +60,7 @@ A step that writes data about the current workflow invocation to the instance lo pause +++++ -A step that pauses the workflow. The workflow is paused until a POST request is sent to ``/api/workflows/{invocation-id}``. +A step that pauses the workflow. The workflow is paused until a POST request is sent to ``/api/workflows/{invocation-id}``. Sending 'fail' in the POST body (Content-type:text/plain) will trigger a failure and workflow rollback. All other responses are considered as successes. .. code:: json @@ -74,6 +74,7 @@ http/sr +++++++ A step that sends a HTTP request to an external system, and then waits for a response. The response has to match a regular expression specified in the step parameters. The url, content type, and message body can use data from the workflow context, using a simple markup language. This step has specific parameters for rollback. +The workflow is restarted when the external system replies with a POST request to ``/api/workflows/{invocation-id}``. Responses starting with "OK" (Content-type:text/plain) are considered successes. Other responses will be considered failures and trigger workflow rollback. .. code:: json