<!--- Verify first that your issue is not already reported on GitHub -->
<!--- Also test if the latest release and devel branch are affected too -->
<!--- Complete *all* sections as described, this form is processed automatically -->

##### SUMMARY
https://github.com/ansible/ansible/issues/31543#issuecomment-390455919

@mixja wrote:
To add to this, if you rescue a block and then have a failure in the always section, the playbook will exit with a failure message, however the shell exit code is 0 (success). If you don't have a rescue block, failures in the always section do fail and correctly return an non-zero (error) shell exit code.

Also discovered this in https://github.com/linux-system-roles/network/pull/232#discussion_r435540835
##### ISSUE TYPE
- Bug Report

##### COMPONENT NAME
<!--- Write the short name of the module, plugin, task or feature below, use your best guess if unsure -->
ansible-playbook

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes -->
```paste below
ansible 2.9.9
  config file = /home/till/.ansible.cfg
  configured module search path = ['/home/till/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.8/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 3.8.3 (default, May 15 2020, 00:00:00) [GCC 10.1.1 20200507 (Red Hat 10.1.1-1)]

```

##### CONFIGURATION
<!--- Paste verbatim output from "ansible-config dump --only-changed" between quotes -->
```paste below

```

##### OS / ENVIRONMENT
<!--- Provide all relevant information below, e.g. target OS versions, network device firmware, etc. -->


##### STEPS TO REPRODUCE
<!--- Describe exactly how to reproduce the problem, using a minimal test-case -->

<!--- Paste example playbooks or commands between quotes below -->
```yaml
- name: block always failure
  hosts: localhost
  gather_facts: no
  tasks:
    - block:
        - debug: msg="Hello"
        - fail: msg="Initial failure"
      rescue:
        - debug: msg="Rescued"
      always:
        - fail: msg="Failed"

```
ansible-playbook testfail.yml -i localhost; echo $?
<!--- HINT: You can paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- Describe what you expected to happen when running the steps above -->
```
PLAY RECAP *************************************************************************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=1    skipped=0    rescued=1    ignored=0   

1
```

or some other returncode than 0

##### ACTUAL RESULTS
<!--- Describe what actually happened. If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes -->
```paste below
ansible-playbook 2.9.9
  config file = /home/till/.ansible.cfg
  configured module search path = ['/home/till/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.8/site-packages/ansible
  executable location = /usr/bin/ansible-playbook
  python version = 3.8.3 (default, May 15 2020, 00:00:00) [GCC 10.1.1 20200507 (Red Hat 10.1.1-1)]
Using /home/till/.ansible.cfg as config file
setting up inventory plugins
host_list declined parsing /home/till/localhost as it did not pass its verify_file() method
Skipping due to inventory source not existing or not being readable by the current user
script declined parsing /home/till/localhost as it did not pass its verify_file() method
auto declined parsing /home/till/localhost as it did not pass its verify_file() method
Skipping due to inventory source not existing or not being readable by the current user
yaml declined parsing /home/till/localhost as it did not pass its verify_file() method
Skipping due to inventory source not existing or not being readable by the current user
ini declined parsing /home/till/localhost as it did not pass its verify_file() method
Skipping due to inventory source not existing or not being readable by the current user
toml declined parsing /home/till/localhost as it did not pass its verify_file() method
[WARNING]: Unable to parse /home/till/localhost as an inventory source
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
Loading callback plugin default of type stdout, v2.0 from /usr/lib/python3.8/site-packages/ansible/plugins/callback/default.py

PLAYBOOK: testfail.yml *************************************************************************************************************************************************************************************
Positional arguments: testfail.yml
verbosity: 4
connection: smart
timeout: 10
become_method: sudo
tags: ('all',)
inventory: ('/home/till/localhost',)
forks: 5
1 plays in testfail.yml

PLAY [block always failure] ********************************************************************************************************************************************************************************
META: ran handlers

TASK [debug] ***********************************************************************************************************************************************************************************************
task path: /home/till/testfail.yml:6
ok: [localhost] => {
    "msg": "Hello"
}

TASK [fail] ************************************************************************************************************************************************************************************************
task path: /home/till/testfail.yml:7
fatal: [localhost]: FAILED! => {
    "changed": false,
    "msg": "Initial failure"
}

TASK [debug] ***********************************************************************************************************************************************************************************************
task path: /home/till/testfail.yml:9
ok: [localhost] => {
    "msg": "Rescued"
}

TASK [fail] ************************************************************************************************************************************************************************************************
task path: /home/till/testfail.yml:11
fatal: [localhost]: FAILED! => {
    "changed": false,
    "msg": "Failed"
}

PLAY RECAP *************************************************************************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=1    skipped=0    rescued=1    ignored=0   

0

```

ITERATING_SETUP = 0
    ITERATING_TASKS = 1
    ITERATING_RESCUE = 2
    ITERATING_ALWAYS = 3
    ITERATING_COMPLETE = 4
    
    
    FAILED_NONE = 0
    FAILED_SETUP = 1
    FAILED_TASKS = 2
    FAILED_RESCUE = 4
    FAILED_ALWAYS = 8
    def __init__(self, inventory, play, play_context, variable_manager, all_vars, start_at_done=False):
        self._play = play
        self._blocks = []
        self._variable_manager = variable_manager
        
        gather_subset = self._play.gather_subset
        gather_timeout = self._play.gather_timeout
        fact_path = self._play.fact_path
        setup_block = Block(play=self._play)
        
        
        setup_block.run_once = False
        setup_task = Task(block=setup_block)
        setup_task.action = 'gather_facts'
        setup_task.name = 'Gathering Facts'
        setup_task.args = {
            'gather_subset': gather_subset,