Skip to content

Timeout parameters are accepted but not used #983

Description

@idan3

Bug Report: Timeout parameters are accepted but not used

Summary

The RESTClient constructor accepts connect_timeout and read_timeout parameters, creates a urllib3.Timeout object, but never passes it to the PoolManager or uses it in HTTP requests. This means requests can hang indefinitely.

Environment

  • Package: massive==2.0.3
  • Python: 3.13
  • OS: macOS

Steps to Reproduce

from massive import RESTClient

# Create client with explicit timeouts
client = RESTClient(
    api_key="your_api_key",
    connect_timeout=5.0,
    read_timeout=5.0
)

# Check if timeout is actually used
print("Timeout object:", client.timeout)
print("PoolManager kwargs:", client.client.connection_pool_kw)

Expected Behavior

The timeout should be passed to either:

  1. urllib3.PoolManager(timeout=...) at construction, or
  2. self.client.request(..., timeout=self.timeout) on each request

Actual Behavior

Timeout object: Timeout(connect=5.0, read=5.0, total=None)
PoolManager kwargs: {'ca_certs': '...', 'cert_reqs': 'CERT_REQUIRED', 'retries': Retry(...)}

The timeout object is created but never used. The connection_pool_kw does not contain a timeout, and the _get method in base.py does not pass timeout to requests.

Root Cause

In massive/rest/base.py:

# Line 81: Timeout is created
self.timeout = urllib3.Timeout(connect=connect_timeout, read=read_timeout)

# Line 73-79: PoolManager is created WITHOUT timeout
self.client = urllib3.PoolManager(
    num_pools=num_pools,
    headers=self.headers,
    ca_certs=certifi.where(),
    cert_reqs="CERT_REQUIRED",
    retries=retry_strategy,
    # timeout=self.timeout  ← MISSING
)

# Line 119-124: Request is made WITHOUT timeout
resp = self.client.request(
    "GET",
    self.BASE + path,
    fields=params,
    headers=headers,
    # timeout=self.timeout  ← MISSING
)

Suggested Fix

Either pass timeout to PoolManager (applies to all requests):

self.client = urllib3.PoolManager(
    num_pools=num_pools,
    headers=self.headers,
    ca_certs=certifi.where(),
    cert_reqs="CERT_REQUIRED",
    retries=retry_strategy,
    timeout=self.timeout,  # Add this
)

Or pass timeout on each request (more flexible):

resp = self.client.request(
    "GET",
    self.BASE + path,
    fields=params,
    headers=headers,
    timeout=self.timeout,  # Add this
)

Impact

Without a working timeout, any network issue (slow server, DNS hang, etc.) can cause the SDK to hang indefinitely, blocking the calling thread.

Workaround

For async code, wrap SDK calls with asyncio.timeout():

import asyncio

async def get_data_with_timeout():
    async with asyncio.timeout(15):
        return await asyncio.to_thread(client.get_snapshot_ticker, ...)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions