### Apache Airflow version

main (development)

### What happened

asset compilation background thread is not killed when running `stop_airflow`  or `breeze stop`.

Webpack process takes a lot of memory, each `start-airflow` starts 4-5 of them.

After a few breeze start, we end up with 15+ webpack background processes that takes more than 20G RAM

### What you think should happen instead

`run_compile_www_assets` should stop when running `stop_airflow` from tmux. It looks like it spawn a `compile-www-assets-dev` pre-commit in a subprocess, that doesn't get killed when stopping breeze

### How to reproduce

```
breeze start-airflow --backend postgres --python 3.8 --dev-mode
# Wait for tmux session to start
breeze_stop

breeze start-airflow --backend postgres --python 3.8 --dev-mode
# Wait for tmux session to start
breeze_stop

# do a couple more if needed
```

Open tmux and monitor your memory, and specifically webpack processes.

### Operating System

Ubuntu 20.04.6 LTS

### Versions of Apache Airflow Providers

_No response_

### Deployment

Other

### Deployment details

_No response_

### Anything else

_No response_

### Are you willing to submit PR?

- [ ] Yes I am willing to submit a PR!

### Code of Conduct

- [X] I agree to follow this project's [Code of Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)

"""
    Checks if buildx plugin is locally available.
    :return True if the buildx plugin is installed.
    """
    check_buildx = ["docker", "buildx", "version"]
    docker_buildx_version_result = run_command(
        check_buildx,
        no_output_dump_on_exception=True,
        capture_output=True,
        text=True,
        check=False,
    )
    if docker_buildx_version_result.returncode == 0:
        return True
    return False
@lru_cache(maxsize=None)
def commit_sha():
    """Returns commit SHA of current repo. Cached for various usages."""
    command_result = run_command(["git", "rev-parse", "HEAD"], capture_output=True, text=True, check=False)
    if command_result.stdout:
        return command_result.stdout.strip()
    else:
        return "COMMIT_SHA_NOT_FOUND"
def filter_out_none(**kwargs) -> dict:
    """Filters out all None values from parameters passed."""
    for key in list(kwargs):
        if kwargs[key] is None:
            kwargs.pop(key)
    return kwargs
def check_if_image_exists(image: str) -> bool: