Repository: apache/airflow

Issue:
Unable to clear Failed task with retries

**Apache Airflow version**: 2.0.1


**Kubernetes version (if you are using kubernetes)** (use `kubectl version`): NA

**Environment**: Windows WSL2 (Ubuntu) Local

- **Cloud provider or hardware configuration**:
- **OS** (e.g. from /etc/os-release): Ubuntu 18.04
- **Kernel** (e.g. `uname -a`): Linux d255bce4dcd5 5.4.72-microsoft-standard-WSL2
- **Install tools**: Docker -compose
- **Others**:

**What happened**:
I have a dag with tasks:
Task1 - Get Date
Task 2 - Get data from Api call (Have set retires to 3)
Task 3 - Load Data

Task 2 had failed after three attempts. I am unable to clear the task Instance and get the below error in UI. 

[Dag Code](https://github.com/anilkulkarni87/airflow-docker/blob/master/dags/covidNyDaily.py)

```
Python version: 3.8.7
Airflow version: 2.0.1rc2
Node: d255bce4dcd5
-------------------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/airflow/.local/lib/python3.8/site-packages/flask/app.py", line 2447, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/airflow/.local/lib/python3.8/site-packages/flask/app.py", line 1952, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/airflow/.local/lib/python3.8/site-packages/flask/app.py", line 1821, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/airflow/.local/lib/python3.8/site-packages/flask/_compat.py", line 39, in reraise
    raise value
  File "/home/airflow/.local/lib/python3.8/site-packages/flask/app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/airflow/.local/lib/python3.8/site-packages/flask/app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/airflow/.local/lib/python3.8/site-packages/airflow/www/auth.py", line 34, in decorated
    return func(*args, **kwargs)
  File "/home/airflow/.local/lib/python3.8/site-packages/airflow/www/decorators.py", line 60, in wrapper
    return f(*args, **kwargs)
  File "/home/airflow/.local/lib/python3.8/site-packages/airflow/www/views.py", line 1547, in clear
    return self._clear_dag_tis(
  File "/home/airflow/.local/lib/python3.8/site-packages/airflow/www/views.py", line 1475, in _clear_dag_tis
    count = dag.clear(
  File "/home/airflow/.local/lib/python3.8/site-packages/airflow/utils/session.py", line 65, in wrapper
    return func(*args, session=session, **kwargs)
  File "/home/airflow/.local/lib/python3.8/site-packages/airflow/models/dag.py", line 1324, in clear
    clear_task_instances(
  File "/home/airflow/.local/lib/python3.8/site-packages/airflow/models/taskinstance.py", line 160, in clear_task_instances
    ti.max_tries = ti.try_number + task_retries - 1
TypeError: unsupported operand type(s) for +: 'int' and 'str'
```

**What you expected to happen**:

I expected to clear the Task Instance so that the task could be scheduled again.

**How to reproduce it**:
1) Clone the repo link shared above
2) Follow instructions to setup cluster.
3) Change code to enforce error in Task 2 
4) Execute and try to clear task instance after three attempts.

![Error pops up when clicked on Clear](https://user-images.githubusercontent.com/10644132/107998258-8e1ee180-6f99-11eb-8442-0c0be5b23478.png)









Discussion:
I have the same problem with Airflow 2.0.1. I made an update from version 1.10.14 and the clear function is not working anymore. Can we try to fix this issue? I think it's a quite important function.
we also have the same issues on Airflow 1.10.10, Python 3.6. This is happening only on few dags the clear function is not working anymore. Can someone help us try to fix the issues? And it is super important for our Production environments
Isn’t the `retries` value supposed to be an int? The repro above has

```python
 @dag.task(default_args={'retries': '2', 'retry_delay': timedelta(minutes=30)})
```

Which is the cause to the exception, if I’m not mistaken.

That said, Airflow should probably be more resilient against user issue like this. Probably set the value to default with a warning?
> Isn’t the `retries` value supposed to be an int? The repro above has
> 
> ```python
>  @dag.task(default_args={'retries': '2', 'retry_delay': timedelta(minutes=30)})
> ```
> 
> Which is the cause to the exception, if I’m not mistaken.
> 
> That said, Airflow should probably be more resilient against user issue like this. Probably set the value to default with a warning?

Excellent, it is working for us by changing the str to int at retries. Thanks much for the help !! 
@uranusjr And if the retries is an string i think we can try to parse it as integer if we can.

Resolving patch:
diff --git a/airflow/models/baseoperator.py b/airflow/models/baseoperator.py
--- a/airflow/models/baseoperator.py
+++ b/airflow/models/baseoperator.py
@@ -559,6 +559,14 @@ def __init__(
         if wait_for_downstream:
             self.depends_on_past = True
 
+        if retries is not None and not isinstance(retries, int):
+            try:
+                parsed_retries = int(retries)
+            except (TypeError, ValueError):
+                raise AirflowException(f"'retries' type must be int, not {type(retries).__name__}")
+            self.log.warning("Implicitly converting 'retries' for %s from %r to int", self, retries)
+            retries = parsed_retries
+
         self.retries = retries
         self.queue = queue
         self.pool = Pool.DEFAULT_POOL_NAME if pool is None else pool


Test patch:
diff --git a/tests/core/test_core.py b/tests/core/test_core.py
--- a/tests/core/test_core.py
+++ b/tests/core/test_core.py
@@ -16,6 +16,7 @@
 # specific language governing permissions and limitations
 # under the License.
 
+import logging
 import multiprocessing
 import os
 import signal
@@ -453,3 +454,48 @@ def test_dag_params_and_task_params(self):
 
         assert context1['params'] == {'key_1': 'value_1', 'key_2': 'value_2_new', 'key_3': 'value_3'}
         assert context2['params'] == {'key_1': 'value_1', 'key_2': 'value_2_old'}
+
+
+@pytest.fixture()
+def dag():
+    return DAG(TEST_DAG_ID, default_args={'owner': 'airflow', 'start_date': DEFAULT_DATE})
+
+
+def test_operator_retries_invalid(dag):
+    with pytest.raises(AirflowException) as ctx:
+        BashOperator(
+            task_id='test_illegal_args',
+            bash_command='echo success',
+            dag=dag,
+            retries='foo',
+        )
+    assert str(ctx.value) == "'retries' type must be int, not str"
+
+
+def test_operator_retries_coerce(caplog, dag):
+    with caplog.at_level(logging.WARNING):
+        BashOperator(
+            task_id='test_illegal_args',
+            bash_command='echo success',
+            dag=dag,
+            retries='1',
+        )
+    assert caplog.record_tuples == [
+        (
+            "airflow.operators.bash.BashOperator",
+            logging.WARNING,
+            "Implicitly converting 'retries' for <Task(BashOperator): test_illegal_args> from '1' to int",
+        ),
+    ]
+
+
+@pytest.mark.parametrize("retries", [None, 5])
+def test_operator_retries(caplog, dag, retries):
+    with caplog.at_level(logging.WARNING):
+        BashOperator(
+            task_id='test_illegal_args',
+            bash_command='echo success',
+            dag=dag,
+            retries=retries,
+        )
+    assert caplog.records == []