---
title: "faster-whisper Loads Model at Startup Regardless of Task Routing"
aliases: [faster-whisper-memory, whisper-startup-ram, faster-whisper-cloud-run-memory]
tags: [python, faster-whisper, docker, memory, celery, cloud-run, gotcha]
sources:
  - "daily/2026-04-30.md"
created: 2026-04-30
updated: 2026-04-30
---

# faster-whisper Loads Model at Startup Regardless of Task Routing

`faster_whisper` loads the full model into RAM when the worker process initialises — not when the first transcription task arrives. This means memory limits must reflect model size even when tasks are routed away from the worker (e.g., to Cloud Run).

## Key Points

- `faster_whisper.WhisperModel(...)` loads the full model at import/init time, not lazily on first task
- A Docker container running a Celery worker with `faster_whisper` will consume model RAM immediately on startup, regardless of whether any tasks are routed to it
- Routing transcription tasks to Cloud Run does NOT reduce local worker RAM usage
- Downsizing memory limits after enabling Cloud Run routing causes OOM kills
- Memory limits must reflect the model size, not task routing configuration

## Details

### The Trap

When Cloud Run routing is enabled for transcription tasks, developers assume the local worker no longer needs to load the Whisper model. This reasoning is wrong:

```python
# worker/__init__.py or wherever the model is initialized
from faster_whisper import WhisperModel

# This runs at container startup, NOT at task execution time
model = WhisperModel("large-v2", device="cpu", compute_type="int8")
```

Even if zero transcription tasks are ever sent to this worker, the model occupies RAM from the moment the container starts.

### Memory Requirements by Model

| Model | Approximate RAM (CPU, int8) |
|-------|----------------------------|
| `tiny` | ~200 MB |
| `base` | ~300 MB |
| `small` | ~500 MB |
| `medium` | ~1.5 GB |
| `large-v2` | ~3 GB |
| `large-v3` | ~3.5 GB |

### Correct Approach

If you route transcription to Cloud Run but keep the local worker:
- Keep memory limits that accommodate the model size
- OR refactor model loading to be truly lazy (load inside the task function with a check)
- OR remove `faster_whisper` import from containers that don't need it

### Lazy Loading Alternative

```python
_model = None

def get_model():
    global _model
    if _model is None:
        from faster_whisper import WhisperModel
        _model = WhisperModel("large-v2", device="cpu", compute_type="int8")
    return _model

@celery.task
def transcribe(audio_path: str):
    model = get_model()  # loads only when first task arrives
    ...
```

This defers memory allocation until the first task — safe only if the task truly won't be called in your routing setup.

## Related Concepts

- [[wiki/architecture/cloud-run-jobs-celery]] — Cloud Run Jobs + Celery pattern for heavy tasks
- [[wiki/concepts/celery-queue-worker-specialization]] — queue-based routing and which container handles which task

## Sources

- [[daily/2026-04-30.md]] — Session 14:42, OOM after downsizing worker memory limits post–Cloud Run routing
