function call
timeout
programming
asynchronous
code optimization

Timeout on a function call

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

A timeout on a function call means you stop waiting after a chosen amount of time instead of letting the call block forever. That sounds simple, but there is an important distinction: timing out the caller is not always the same as forcibly stopping the underlying work.

First Decide What Timeout Should Mean

When developers say "add a timeout," they may mean one of several things:

  • give up waiting and raise an error
  • cancel the task if the runtime supports cancellation
  • kill an external process or network operation
  • mark the result as failed but let the work continue in the background

Those are different behaviors. A good timeout design starts by deciding which one the application actually needs.

For many APIs, a timeout only means "the caller stops waiting." The underlying task may still run unless the library or runtime has a real cancellation mechanism.

Timeout a Background Task with concurrent.futures

In Python, a simple way to limit wait time is to run the function in an executor and apply a timeout to result():

python
1from concurrent.futures import ThreadPoolExecutor, TimeoutError
2import time
3
4
5def slow_operation():
6    time.sleep(5)
7    return "done"
8
9
10with ThreadPoolExecutor(max_workers=1) as executor:
11    future = executor.submit(slow_operation)
12
13    try:
14        result = future.result(timeout=1)
15        print(result)
16    except TimeoutError:
17        print("operation timed out")

This times out the wait after one second. It does not magically kill the thread. The submitted work may continue running unless you designed it to cooperate with cancellation.

That distinction is one of the most misunderstood parts of function-call timeouts.

Use asyncio.wait_for in Async Code

If your code is already asynchronous, asyncio.wait_for is usually the right tool:

python
1import asyncio
2
3
4async def slow_operation():
5    await asyncio.sleep(5)
6    return "done"
7
8
9async def main():
10    try:
11        result = await asyncio.wait_for(slow_operation(), timeout=1)
12        print(result)
13    except asyncio.TimeoutError:
14        print("operation timed out")
15
16
17asyncio.run(main())

This is cleaner than wrapping async code in threads. It also fits naturally with event-loop-based networking libraries, where timeouts are a normal part of API usage.

In cooperative async systems, cancellation is often more meaningful because the coroutine can actually be cancelled at an await point.

Put the Timeout at the Right Layer

Sometimes the best timeout is not around the function call at all. It belongs inside the operation’s own API.

Examples:

  • HTTP clients usually expose request timeouts
  • database drivers often expose query or socket timeouts
  • subprocess APIs may let you kill child processes on timeout

If the function is just a wrapper around a network request, use the network client’s timeout rather than only timing the wrapper from the outside. That gives the lower-level library a chance to clean up resources properly.

For example, with requests:

python
1import requests
2
3response = requests.get("https://example.com", timeout=2)
4print(response.status_code)

This is usually better than running requests.get in a thread and timing the thread externally.

Design for Cancellation When It Matters

If the work is CPU-bound or runs in a thread, timeout alone may not stop it. In those cases, you often need cooperative cancellation, such as a shared flag, an event, or a cancellable process boundary.

That is why external process boundaries are sometimes easier to manage than threads for hard time limits. Killing a subprocess is straightforward. Killing a Python thread safely is not.

A timeout policy is therefore not just a syntax choice. It is part of the execution model of the code.

Common Pitfalls

The biggest mistake is assuming a timeout automatically kills the underlying work. In many runtimes it only stops the caller from waiting.

Another issue is applying a generic outer timeout while ignoring the operation’s native timeout support. That can leave sockets, queries, or child processes running longer than intended.

Developers also often forget cleanup. If a timed-out operation opened files, connections, or transactions, the code needs a plan for releasing them.

Finally, do not use one timeout value everywhere without context. The right limit for a local cache lookup is very different from the right limit for a slow external API.

Summary

  • A timeout usually means "stop waiting after a limit," not necessarily "stop the work instantly."
  • 'future.result(timeout=...) works for executor-based code.'
  • 'asyncio.wait_for is the natural timeout tool for async Python.'
  • Prefer an operation’s built-in timeout support when it exists.
  • If true cancellation matters, design for it explicitly instead of assuming timeout alone will provide it.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.