Skip to content

Workers

We use Temporal to run workflows and activities in the background. If you have not used Temporal before, their docs have a comprehensive introduction. We recommend reading that to get used to the concepts that we use on a daily basis.

Temporal provides different types of workers to handle different workloads. Our setup includes:

  • Default Worker: Handles I/O bound workflows and activities (API calls, database operations)
  • CPU Worker: Handles CPU intensive activities (image processing, OCR)

The default worker uses a thread pool executor to handle I/O bound operations. This worker:

  • Runs workflows and activities that are primarily I/O bound
  • Uses ThreadPoolExecutor for concurrency
  • Handles most of our business logic workflows

The CPU worker uses a process pool executor for CPU intensive tasks. This worker:

  • Handles CPU bound activities like image processing and OCR
  • Uses ProcessPoolExecutor to bypass Python’s GIL
  • Runs on a separate task queue (cpu_intensive)

Our backend is highly concurrent and, for the most part, I/O bound. Most of our time is spent waiting for API calls to LLMs and other external services.

Workers are configured in our Docker setup:

worker:
image: slidespeak-backend-code
command: python -m server.temporal.worker
depends_on:
- temporal
cpu-worker:
image: slidespeak-backend-code
command: python -m server.temporal.cpu_worker
depends_on:
- temporal
deploy:
resources:
limits:
cpus: '2.0'