Skip to content

Fix Overpass status check, cap retries, add CI - #34

Merged
smmaurer merged 8 commits into
mainfrom
fix/overpass-status-and-retries
Oct 14, 2026
Merged

smmaurer merged 8 commits into
mainfrom
fix/overpass-status-and-retries

Conversation

@waddell

@waddell waddell commented Oct 4, 2026

Copy link
Copy Markdown
Member

#33 (Rhys Williams) fixed the HTTP 406 on the main Overpass request by sending a User-Agent and switching to https. This follows up on the rest of that code path.

What this changes

  • get_pause_duration() still called http://overpass-api.de/api/status with no User-Agent, so it got the 406 page and always fell back to 10 s. It now uses https and the same User-Agent.
  • The User-Agent is now a module constant, osmnet/<version> (+https://github.com/UDST/osmnet), built from osmnet.__version__ and used by both requests. To make that importable, __version__ is now set in osmnet/__init__.py before from .load import *.
  • The status parser read line index 3, but the page now has Rate limit and Announced endpoint lines, so that index no longer holds the slot line. It now finds the line by content: N slots available, then Slot available after: <time> (earliest one), then Currently running queries.
  • Retries are capped. overpass_request() used to recurse forever on 429/504; it now loops with a new max_retries=5 keyword and raises OverpassRetryError when the retries run out. get_pause_duration() used to recurse forever while the server was busy; it now takes max_retries=5 and falls back to default_duration. Existing call signatures are unchanged. One side effect: an explicit error_pause_duration now applies to every retry, not just the first. The status request also gets a 30 s timeout.

Live /api/status page fetched on 2026-10-04, also saved as a test fixture:

Connected as: 843828827
Current time: 2026-10-04T12:18:14Z
Announced endpoint: gall.openstreetmap.de/
Rate limit: 2
2 slots available now.
Currently running queries (pid, space limit, time limit, start time):

Tests and CI

  • New osmnet/tests/test_overpass.py (17 tests, requests mocked, no network). It covers the live layout, the old layout, Slot available after, Currently running, the 406 HTML page, the User-Agent on both requests, and retry exhaustion. 15 of the 17 fail against current dev.
  • The tests in test_load.py that query Overpass are skipped when OSMNET_SKIP_NETWORK_TESTS=1. There was no existing marker. Local runs are unchanged unless the variable is set.
  • New .github/workflows/ci.yml runs the offline tests on Python 3.10–3.13 (ubuntu-latest) on push and pull_request to dev. CI has effectively been dead: .travis.yml and appveyor.yml are still in the repo but no longer run. I left them in place.

Local results on Python 3.13 (pandas 3.0.6, geopandas 1.2.0):

  • With OSMNET_SKIP_NETWORK_TESTS=1: 24 passed, 14 skipped.
  • Full suite against the live API: 32 passed, 6 failed. The 6 failures are test_make_osm_query, test_parse_network_osm_query, test_intersection_nodes2, test_node_pairs_two_way, test_node_pairs_one_way and test_custom_query_pass. They assert hard-coded element counts that no longer match current OSM data, and they fail the same way on unmodified dev.
  • pycodestyle --max-line-length=100 osmnet is clean.

Not done here

Build the User-Agent from the package version and repo URL and send it
with both the interpreter request and the /api/status request, which
also moves to https. Without it the status endpoint returns HTTP 406.
The /api/status layout gained "Rate limit" and "Announced endpoint"
lines, so reading line index 3 no longer finds the slot line. Find it
by content instead.

overpass_request() recursed forever on 429/504 and
get_pause_duration() recursed forever while the server was busy. Both
now loop with a max_retries keyword (default 5). overpass_request()
raises OverpassRetryError when retries run out; get_pause_duration()
falls back to default_duration.
Mock requests so the tests need no network. The status page text
captured from overpass-api.de on 2026-10-04 is kept as a fixture.
Runs the unit tests that do not need the network on pushes and pull
requests to dev.
@waddell
waddell requested a review from smmaurer October 4, 2026 12:33
Now that the status request succeeds, get_pause_duration() returns 0
whenever slots are free, including while the server is overloaded and
returning 504s, so all retries fired back to back. Unless
error_pause_duration is given, wait at least 5 seconds, doubling with
each retry up to 60, or longer if the status page asks for it.

Also send the interpreter request to overpass-api.de, the host the
status request uses; log server remarks at WARNING (the level was
passed to str.format instead of log); note that pause_duration is
unused; and point CI at main, which becomes the integration branch.
@smmaurer
smmaurer changed the base branch from dev to main October 14, 2026 19:13
- osm_net_download(), ways_in_bbox() and network_from_bbox() take
  max_retries and pass it on to overpass_request(). One request that
  runs out of retries fails the whole download, so callers with large
  bounding boxes need a way to allow more.
- Read the wait for the next slot from the status line's "in N
  seconds", which does not depend on the local clock, and fall back on
  the timestamp (parsed with strptime). This drops the dateutil import,
  which was never a declared dependency.
- Treat "0 slots available" as no free slot.
- Count status checks correctly in the give-up log message, and log
  each busy status check, so the time spent polling shows in the log.
- Raise ValueError for a negative max_retries instead of failing with
  UnboundLocalError, and work out the host once per request.

@smmaurer smmaurer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Paul, this looks good! I pushed a couple of follow-up commits and retargeted the PR to main, which we'll make the default branch as part of the new release.

Retry backoff. With the status request working, get_pause_duration() returns 0 whenever slots are free, including while the server is overloaded and returning 504s. So the 5 retries ran back to back. I saw this in a live test run: test_column_names raised OverpassRetryError after several "Re-trying request in 0.00 seconds" messages. Before this PR, the 406 on the status request meant the pause always fell back to 10 s. Now, unless error_pause_duration is given, each retry waits at least 5 s, doubling up to 60 s, or longer if the status page asks for it. In a live run today the server returned four 504s in a row; the retries waited 5, 10, 20 and 40 s and the fifth attempt succeeded.

Smaller items:

  • Consistent domains for interpreter request and status request.
  • Server remarks are logged at WARNING. The existing code passed level= to str.format() instead of log().
  • The pause_duration docstring now clarifies that the argument is unused.
  • ci.yml now runs on main.

Four new offline tests cover these changes, and there are three changelog bullets. Offline: 28 passed, 14 skipped; pycodestyle is clean. Live, only the six tests with outdated OSM element counts still fail. A packaging/CI PR will follow and run those tests against saved Overpass responses.

@smmaurer
smmaurer merged commit e9ca2f8 into main Oct 14, 2026
4 checks passed
@smmaurer
smmaurer deleted the fix/overpass-status-and-retries branch October 14, 2026 20:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants