Repository: dbt-labs/dbt-core
Pull request: Fixes dbt retry does not respect --threads
Resolves #10584 

### Problem
Solving the problem when retry has been run. dbt does not respect a new --threads value when passed in on a retry.

### Solution

Added the threads in ALLOW_CLI_OVERRIDE_FLAGS to fetch the thread value

### Checklist

- [x] I have read [the contributing guide](https://github.com/dbt-labs/dbt-core/blob/main/CONTRIBUTING.md) and understand what's expected of me.
- [x] I have run this code in development, and it appears to resolve the stated issue.
- [x] This PR includes tests.



Problem statement:
[Bug] dbt retry does not respect --threads
### Is this a new bug in dbt-core?

- [X] I believe this is a new bug in dbt-core
- [X] I have searched the existing issues, and I could not find an existing issue for this bug

### Current Behavior

Sometimes concurrency can be the cause of failures (e.g. database OOM, connection timeouts) and I would want to retry with a lower --threads value.  dbt does not respect a new --threads value when passed in on a retry.

### Expected Behavior

Expect that --threads is respected on retry, otherwise if not passed, re-use same threads from the previous invocation of dbt.

### Steps To Reproduce

dbt build --threads 10
dbt retry --threads 1

### Relevant log output

_No response_

### Environment

```markdown
- OS: all
- Python: 3.11.9
- dbt: 1.8.5
```


### Which database adapter are you using with dbt?

other (mention it in "Additional Context")

### Additional Context

Using clickhouse adapter currently

Hints from issue discussion:
Thanks for reaching out about this @barberscott !

Was able to reproduce what you described. Agreed that `dbt retry` should respect any CLI flags (including `--threads`!).

<details>

<summary>

### Reprex
</summary>

`models/my_model.sql`

```sql
{% if execute %}
  {{ exceptions.raise_compiler_error("Forced error") }}
{% endif %}

select 1 as id
```

Run these commands:

```shell
dbt build -s my_model --threads 3
dbt retry --threads 2
```

See that the output for retry says "Concurrency: 3 threads" instead of "Concurrency: 1 threads":

```
(dbt_1.8) $ dbt build -s my_model --threads 3

14:39:12  Running with dbt=1.8.3
14:39:15  Registered adapter: duckdb=1.8.1
14:39:15  Found 2 models, 406 macros
14:39:15  
14:39:15  Concurrency: 3 threads (target='dev')
14:39:15  
14:39:15  1 of 1 START sql view model dev.my_model ....................................... [RUN]
14:39:15  1 of 1 ERROR creating sql view model dev.my_model .............................. [ERROR in 0.01s]
14:39:15  
14:39:15  Finished running 1 view model in 0 hours 0 minutes and 0.19 seconds (0.19s).
14:39:15  
14:39:15  Completed with 1 error and 0 warnings:
14:39:15  
14:39:15    Compilation Error in model my_model (models/my_model.sql)
  Forced error
14:39:16  
14:39:16  Done. PASS=0 WARN=0 ERROR=1 SKIP=0 TOTAL=1

(dbt_1.8) $ dbt retry --threads 2

14:39:17  Running with dbt=1.8.3
14:39:17  Registered adapter: duckdb=1.8.1
14:39:17  Found 2 models, 406 macros
14:39:17  
14:39:18  Concurrency: 3 threads (target='dev')
14:39:18  
14:39:18  1 of 1 START sql view model dev.my_model ....................................... [RUN]
14:39:18  1 of 1 ERROR creating sql view model dev.my_model .............................. [ERROR in 0.01s]
14:39:18  
14:39:18  Finished running 1 view model in 0 hours 0 minutes and 0.17 seconds (0.17s).
14:39:18  
14:39:18  Completed with 1 error and 0 warnings:
14:39:18  
14:39:18    Compilation Error in model my_model (models/my_model.sql)
  Forced error
14:39:18  
14:39:18  Done. PASS=0 WARN=0 ERROR=1 SKIP=0 TOTAL=1
```

</details>

Commit message: Bug Fix: 10584

Patch to review:
diff --git a/.changes/unreleased/Fixes-20240822-122132.yaml b/.changes/unreleased/Fixes-20240822-122132.yaml
new file mode 100644
index 00000000000..d169520ea99
--- /dev/null
+++ b/.changes/unreleased/Fixes-20240822-122132.yaml
@@ -0,0 +1,6 @@
+kind: Fixes
+body: dbt retry does not respect --threads
+time: 2024-08-22T12:21:32.358066+05:30
+custom:
+    Author: donjin-master
+    Issue: "10584"
diff --git a/core/dbt/task/retry.py b/core/dbt/task/retry.py
index fd943b1151f..8e69dc87590 100644
--- a/core/dbt/task/retry.py
+++ b/core/dbt/task/retry.py
@@ -36,7 +36,7 @@
     "warn_error",
 }
 
-ALLOW_CLI_OVERRIDE_FLAGS = {"vars"}
+ALLOW_CLI_OVERRIDE_FLAGS = {"vars", "threads"}
 
 TASK_DICT = {
     "build": BuildTask,
diff --git a/tests/functional/retry/fixtures.py b/tests/functional/retry/fixtures.py
index 64adf9c684f..52c9d8afdfc 100644
--- a/tests/functional/retry/fixtures.py
+++ b/tests/functional/retry/fixtures.py
@@ -1,5 +1,6 @@
 models__sample_model = """select 1 as id, baz as foo"""
 models__second_model = """select 1 as id, 2 as bar"""
+models__thread_model = """select idx as id"""
 
 models__union_model = """
 select foo + bar as sum3 from {{ ref('sample_model') }}
@@ -58,3 +59,13 @@
         data_tests:
           - not_null
 """
+
+schema_test_thread_yml = """
+models:
+  - name: thread_model
+    columns:
+      - name: id
+        data_tests:
+          - not_null
+
+"""
diff --git a/tests/functional/retry/test_retry_threads.py b/tests/functional/retry/test_retry_threads.py
new file mode 100644
index 00000000000..b6366af1b4f
--- /dev/null
+++ b/tests/functional/retry/test_retry_threads.py
@@ -0,0 +1,57 @@
+import pytest
+
+from dbt.contracts.results import RunStatus, TestStatus
+from dbt.tests.util import run_dbt, write_file
+from tests.functional.retry.fixtures import models__thread_model, schema_test_thread_yml
+
+
+class TestCustomThreadRetry:
+    @pytest.fixture(scope="class")
+    def models(self):
+        return {
+            "thread_model.sql": models__thread_model,
+            "schema.yml": schema_test_thread_yml,
+        }
+
+    def test_thread_target(self, project):
+        # Passing Threads to check
+        results = run_dbt(
+            ["build", "--select", "thread_model", "--threads", "3"], expect_pass=False
+        )
+        expected_statuses = {
+            "thread_model": RunStatus.Error,
+            "not_null_thread_model_id": TestStatus.Skipped,
+        }
+        assert {n.node.name: n.status for n in results.results} == expected_statuses
+
+        # Retry Running the Dbt with simple Retry
+        results = run_dbt(["retry", "--threads", "2"], expect_pass=False)
+        expected_statuses = {
+            "thread_model": RunStatus.Error,
+            "not_null_thread_model_id": TestStatus.Skipped,
+        }
+        assert {n.node.name: n.status for n in results.results} == expected_statuses
+        assert results.args["threads"] == 2
+
+        # running with retry withour threads
+        results = run_dbt(["retry"], expect_pass=False)
+        expected_statuses = {
+            "thread_model": RunStatus.Error,
+            "not_null_thread_model_id": TestStatus.Skipped,
+        }
+        assert {n.node.name: n.status for n in results.results} == expected_statuses
+        assert results.args["threads"] == 2
+
+        # Retry with fixing the model and running with --threads 1
+        fixed_sql = "select 1 as id"
+        write_file(fixed_sql, "models", "thread_model.sql")
+
+        results = run_dbt(["retry", "--threads", "1"])
+        expected_statuses = {
+            "thread_model": RunStatus.Success,
+            "not_null_thread_model_id": TestStatus.Pass,
+        }
+
+        assert {n.node.name: n.status for n in results.results} == expected_statuses
+        assert results.args["threads"] == 1
+        write_file(models__thread_model, "models", "thread_model.sql")


Code review comments:
diff_hunk: @@ -0,0 +1,57 @@
+import pytest
+
+from dbt.contracts.results import RunStatus, TestStatus
+from dbt.tests.util import run_dbt, write_file
+from tests.functional.retry.fixtures import models__thread_model, schema_test_thread_yml
+
+
+class TestCustomThreadRetry:
+    @pytest.fixture(scope="class")
+    def models(self):
+        return {
+            "thread_model.sql": models__thread_model,
+            "schema.yml": schema_test_thread_yml,
+        }
+
+    def test_thread_target(self, project):
+        # Passing Threads to check
+        results = run_dbt(
+            ["build", "--select", "thread_model", "--threads", "3"], expect_pass=False
+        )
+        expected_statuses = {
+            "thread_model": RunStatus.Error,
+            "not_null_thread_model_id": TestStatus.Skipped,
+        }
+        assert {n.node.name: n.status for n in results.results} == expected_statuses
+
+        # Retry Running the Dbt with simple Retry
+        results = run_dbt(["retry", "--threads", "2"], expect_pass=False)
+        expected_statuses = {
+            "thread_model": RunStatus.Error,
+            "not_null_thread_model_id": TestStatus.Skipped,
+        }
+        assert {n.node.name: n.status for n in results.results} == expected_statuses
+        assert results.args["threads"] == 2
+
+        # running with retry withour threads
+        results = run_dbt(["retry"], expect_pass=False)
+        expected_statuses = {
+            "thread_model": RunStatus.Error,
+            "not_null_thread_model_id": TestStatus.Skipped,
+        }
+        assert {n.node.name: n.status for n in results.results} == expected_statuses
+        assert results.args["threads"] == 2
+
+        # Retry with fixing the model and running with --threads 1
+        fixed_sql = "select 1 as id"
+        write_file(fixed_sql, "models", "thread_model.sql")
+
+        results = run_dbt(["retry", "--threads", "1"])
+        expected_statuses = {
+            "thread_model": RunStatus.Success,
+            "not_null_thread_model_id": TestStatus.Pass,
+        }
+
+        assert {n.node.name: n.status for n in results.results} == expected_statuses
+        assert results.args["threads"] == 1
+        write_file(models__thread_model, "models", "thread_model.sql")
path: tests/functional/retry/test_retry_threads.py
text: @user1:
Is this and the `write_file` above needed?

@user1:
@user2-master Hope you don't mind, I am removing the last line here and going to merge it afterwards