Describe the bug
The retry logic in the Bitfinex Spot candle-import driver is dead: it calls
jh.random_uniform(), which does not exist in jesse.helpers. Any transient network error
during an import therefore raises AttributeError from inside the exception handler, and the
import worker dies silently instead of retrying.
jesse/modes/import_candles_mode/drivers/Bitfinex/BitfinexSpot.py:36
except (ConnectionError, RequestException) as e:
if attempt == self.max_retries - 1: # Last attempt
raise e
# Exponential backoff with jitter
delay = (self.base_delay * 2 ** attempt) + (jh.random_uniform(0, 1)) # <-- AttributeError
time.sleep(delay)
jesse.helpers exposes random and random_str, but there is no random_uniform:
>>> import jesse.helpers as jh
>>> hasattr(jh, 'random_uniform')
False
>>> [n for n in dir(jh) if 'rand' in n.lower()]
['random', 'random_str']
Actual traceback:
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='api-pub.bitfinex.com', port=443):
Max retries exceeded with url: /v2/candles/trade:1m:tBTCUSD/hist?start=...&end=...&limit=1440&sort=1
(Caused by NewConnectionError("... Failed to establish a new connection: [Errno 111] Connection refused"))
During handling of the above exception, another exception occurred:
AttributeError: module 'jesse.helpers' has no attribute 'random_uniform'
==> Removed finished worker <import_id> from active workers
This is easy to miss because the failure is silent from the caller's perspective: the import
API/MCP call has already returned status: started, and nothing in the response indicates the
worker died. Only the container log shows it.
api-pub.bitfinex.com refuses connections fairly often during long imports (hours of consecutive
1m-candle requests), so in practice the retry path is hit regularly — and always fails.
Grep shows this is the only occurrence in the codebase; the Gate driver implements backoff without
jitter and is unaffected.
To Reproduce
- Import a long range of Bitfinex Spot candles, e.g.
BTC-USD starting from 2017-01-01
(several years of 1m candles).
- Let it run long enough for the exchange to refuse a connection (happened ~3 times over several
hours in my case).
- The worker dies. The last log lines are the
ConnectionError followed immediately by
AttributeError: module 'jesse.helpers' has no attribute 'random_uniform'.
A minimal reproduction of the root cause, no network needed:
import jesse.helpers as jh
jh.random_uniform(0, 1) # AttributeError
Expected behavior
A transient ConnectionError should trigger the exponential backoff and retry (up to
max_retries), not kill the import worker.
Proposed fix
Use the stdlib directly — random is not currently imported in this module:
import requests
import time
+import random
from requests.exceptions import ConnectionError, RequestException
- delay = (self.base_delay * 2 ** attempt) + (jh.random_uniform(0, 1))
+ delay = (self.base_delay * 2 ** attempt) + random.uniform(0, 1)
Alternatively, add random_uniform to jesse.helpers if it is meant to exist as part of the
helpers API (there may be other call sites planned).
Happy to send a PR for whichever approach you prefer.
Environment
- OS: Docker (
salehmir/jesse:latest), Linux container on Windows host
- Version: jesse 2.5.0
- Exchange: Bitfinex Spot,
BTC-USD, 1m candles
Additional context
Two other ways a long import can stop, for context (not bugs, but they look similar in the logs and
made this one harder to isolate):
- a full day missing on the exchange raises
CandleNotFoundInExchange (e.g. Bitfinex 2016-04-02) —
correct behaviour, but requires restarting past the gap;
- restarting the
jesse container kills any in-flight import worker.
Because of those, I initially misdiagnosed the three stops as unrelated network flakiness, until I
read the full traceback and saw the AttributeError below the ConnectionError.
Describe the bug
The retry logic in the Bitfinex Spot candle-import driver is dead: it calls
jh.random_uniform(), which does not exist injesse.helpers. Any transient network errorduring an import therefore raises
AttributeErrorfrom inside the exception handler, and theimport worker dies silently instead of retrying.
jesse/modes/import_candles_mode/drivers/Bitfinex/BitfinexSpot.py:36jesse.helpersexposesrandomandrandom_str, but there is norandom_uniform:Actual traceback:
This is easy to miss because the failure is silent from the caller's perspective: the import
API/MCP call has already returned
status: started, and nothing in the response indicates theworker died. Only the container log shows it.
api-pub.bitfinex.comrefuses connections fairly often during long imports (hours of consecutive1m-candle requests), so in practice the retry path is hit regularly — and always fails.
Grep shows this is the only occurrence in the codebase; the Gate driver implements backoff without
jitter and is unaffected.
To Reproduce
BTC-USDstarting from 2017-01-01(several years of 1m candles).
hours in my case).
ConnectionErrorfollowed immediately byAttributeError: module 'jesse.helpers' has no attribute 'random_uniform'.A minimal reproduction of the root cause, no network needed:
Expected behavior
A transient
ConnectionErrorshould trigger the exponential backoff and retry (up tomax_retries), not kill the import worker.Proposed fix
Use the stdlib directly —
randomis not currently imported in this module:Alternatively, add
random_uniformtojesse.helpersif it is meant to exist as part of thehelpers API (there may be other call sites planned).
Happy to send a PR for whichever approach you prefer.
Environment
salehmir/jesse:latest), Linux container on Windows hostBTC-USD, 1m candlesAdditional context
Two other ways a long import can stop, for context (not bugs, but they look similar in the logs and
made this one harder to isolate):
CandleNotFoundInExchange(e.g. Bitfinex 2016-04-02) —correct behaviour, but requires restarting past the gap;
jessecontainer kills any in-flight import worker.Because of those, I initially misdiagnosed the three stops as unrelated network flakiness, until I
read the full traceback and saw the
AttributeErrorbelow theConnectionError.