From 058091a6f4d4c92def709dae8a9db2ca75f52a03 Mon Sep 17 00:00:00 2001 From: Antonio Gonzalez Date: Tue, 9 Jan 2024 12:30:57 -0700 Subject: [PATCH] fix #3327 --- qiita_db/processing_job.py | 14 ++++++++++++++ qiita_db/support_files/patches/90.sql | 6 ++++++ qiita_db/test/test_processing_job.py | 12 ++++++++++++ qiita_db/test/test_util.py | 5 +++++ qiita_db/util.py | 14 ++++++++++++++ 5 files changed, 51 insertions(+) create mode 100644 qiita_db/support_files/patches/90.sql diff --git a/qiita_db/processing_job.py b/qiita_db/processing_job.py index 9c9aa1186..dcce029a6 100644 --- a/qiita_db/processing_job.py +++ b/qiita_db/processing_job.py @@ -2392,6 +2392,20 @@ def add(self, dflt_params, connections=None, req_params=None, with qdb.sql_connection.TRN: self._raise_if_not_in_construction() + # checking that the new number of artifacts is not above + # max_artifacts_in_workflow + current_artifacts = sum( + [len(j.command.outputs) for j in self.graph.nodes()]) + to_add_artifacts = len(dflt_params.command.outputs) + total_artifacts = current_artifacts + to_add_artifacts + max_artifacts = qdb.util.max_artifacts_in_workflow() + if total_artifacts > max_artifacts: + raise ValueError( + "Cannot add new job because it will create more " + f"artifacts (current: {current_artifacts} + new: " + f"{to_add_artifacts} = {total_artifacts}) that what is " + f"allowed in a single workflow ({max_artifacts})") + if connections: # The new Job depends on previous jobs in the workflow req_params = req_params if req_params else {} diff --git a/qiita_db/support_files/patches/90.sql b/qiita_db/support_files/patches/90.sql new file mode 100644 index 000000000..a0b5d58c9 --- /dev/null +++ b/qiita_db/support_files/patches/90.sql @@ -0,0 +1,6 @@ +-- Jan 9, 2024 +-- add control of max artifacts in analysis to the settings +-- using 35 as default considering that a core div creates ~17 so allowing +-- for 2 of those + 1 +ALTER TABLE settings + ADD COLUMN IF NOT EXISTS max_artifacts_in_workflow INT DEFAULT 35; diff --git a/qiita_db/test/test_processing_job.py b/qiita_db/test/test_processing_job.py index b3b8be2c6..4940e039c 100644 --- a/qiita_db/test/test_processing_job.py +++ b/qiita_db/test/test_processing_job.py @@ -1205,6 +1205,18 @@ def test_add_error(self): qdb.exceptions.QiitaDBOperationNotPermittedError): qdb.processing_job.ProcessingWorkflow(1).add({}, None) + # test that the qdb.util.max_artifacts_in_workflow + with qdb.sql_connection.TRN: + qdb.sql_connection.perform_as_transaction( + "UPDATE settings set max_artifacts_in_workflow = 1") + with self.assertRaisesRegex( + ValueError, "Cannot add new job because it will create " + "more artifacts "): + qdb.processing_job.ProcessingWorkflow(2).add( + qdb.software.DefaultParameters(1), + req_params={'input_data': 1}, force=True) + qdb.sql_connection.TRN.rollback() + def test_remove(self): exp_command = qdb.software.Command(1) json_str = ( diff --git a/qiita_db/test/test_util.py b/qiita_db/test/test_util.py index 112cb3e6b..33766f3e4 100644 --- a/qiita_db/test/test_util.py +++ b/qiita_db/test/test_util.py @@ -45,6 +45,11 @@ def test_max_preparation_samples(self): obs = qdb.util.max_preparation_samples() self.assertEqual(obs, 800) + def test_max_artifacts_in_workflow(self): + """Test that we get the correct max_artifacts_in_workflow""" + obs = qdb.util.max_artifacts_in_workflow() + self.assertEqual(obs, 35) + def test_filepath_id_to_object_id(self): # filepaths 1, 2 belongs to artifact 1 self.assertEqual(qdb.util.filepath_id_to_object_id(1), 1) diff --git a/qiita_db/util.py b/qiita_db/util.py index df7153bb4..76d27e90b 100644 --- a/qiita_db/util.py +++ b/qiita_db/util.py @@ -416,6 +416,20 @@ def max_preparation_samples(): return qdb.sql_connection.TRN.execute_fetchlast() +def max_artifacts_in_workflow(): + r"""Returns the max number of artifacts allowed in a single workflow + + Returns + ------- + int + The max number of artifacts allowed in a single workflow + """ + with qdb.sql_connection.TRN: + qdb.sql_connection.TRN.add( + "SELECT max_artifacts_in_workflow FROM settings") + return qdb.sql_connection.TRN.execute_fetchlast() + + def compute_checksum(path): r"""Returns the checksum of the file pointed by path