Skip to content

Commit

Permalink
Release 20240109 (#324)
Browse files Browse the repository at this point in the history
* add hint to 408 timeout error (#322)

* Fix/bad timeout value (#323)

---------

Co-authored-by: Christian Parker <[email protected]>

* Bad timeout value passed to db class (#321)
  The averages endpoint was passing a config value but unassigned and
  it was therefor being passed as the timeout value. I added a check
  in the db to make sure we are protected from that as well as updated
  the averages endpoint to explicitly name the config argument.

fixes #321

---------

Co-authored-by: Christian Parker <[email protected]>

---------

Co-authored-by: Christian Parker <[email protected]>
  • Loading branch information
russbiggs and caparker authored Jan 10, 2024
1 parent e43d882 commit 984d940
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 8 deletions.
22 changes: 15 additions & 7 deletions openaq_api/openaq_api/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@

logger = logging.getLogger("db")

allowed_config_params = ["work_mem", "statement_timeout"]
allowed_config_params = ["work_mem"]


DEFAULT_CONNECTION_TIMEOUT = 6
MAX_CONNECTION_TIMEOUT = 15


def default(obj):
return str(obj)

Expand Down Expand Up @@ -93,7 +94,9 @@ async def pool(self):
return self.request.app.state.pool

@cached(settings.API_CACHE_TIMEOUT, **cache_config)
async def fetch(self, query, kwargs, timeout=DEFAULT_CONNECTION_TIMEOUT, config=None):
async def fetch(
self, query, kwargs, timeout=DEFAULT_CONNECTION_TIMEOUT, config=None
):
pool = await self.pool()
self.request.state.timer.mark("pooled")
start = time.time()
Expand All @@ -109,23 +112,26 @@ async def fetch(self, query, kwargs, timeout=DEFAULT_CONNECTION_TIMEOUT, config=
if param in allowed_config_params:
q = f"SELECT set_config('{param}', $1, TRUE)"
s = await con.execute(q, str(value))
if not isinstance(timeout, (str, int)):
logger.warning(f"Non int or string timeout value passed - {timeout}")
timeout = DEFAULT_CONNECTION_TIMEOUT
r = await wait_for(con.fetch(rquery, *args), timeout=timeout)
await tr.commit()
except asyncpg.exceptions.UndefinedColumnError as e:
logger.error(f"Undefined Column Error: {e}\n{rquery}\n{kwargs}")
logger.error(f"Undefined Column Error: {e}\n{rquery}\n{args}")
raise ValueError(f"{e}") from e
except asyncpg.exceptions.CharacterNotInRepertoireError as e:
raise ValueError(f"{e}") from e
except asyncpg.exceptions.DataError as e:
logger.error(f"Data Error: {e}\n{rquery}\n{kwargs}")
logger.error(f"Data Error: {e}\n{rquery}\n{args}")
raise ValueError(f"{e}") from e
except TimeoutError:
raise HTTPException(
status_code=408,
detail="Connection timed out",
detail="Connection timed out: Try to provide more specific query parameters or a smaller time frame.",
)
except Exception as e:
logger.error(f"Unknown database error: {e}\n{rquery}\n{kwargs}")
logger.error(f"Unknown database error: {e}\n{rquery}\n{args}")
if str(e).startswith("ST_TileEnvelope"):
raise HTTPException(status_code=422, detail=f"{e}")
raise HTTPException(status_code=500, detail=f"{e}")
Expand All @@ -149,7 +155,9 @@ async def fetchval(self, query, kwargs):
return r[0]
return None

async def fetchPage(self, query, kwargs, timeout=DEFAULT_CONNECTION_TIMEOUT, config=None) -> OpenAQResult:
async def fetchPage(
self, query, kwargs, timeout=DEFAULT_CONNECTION_TIMEOUT, config=None
) -> OpenAQResult:
page = kwargs.get("page", 1)
limit = kwargs.get("limit", 1000)
kwargs["offset"] = abs((page - 1) * limit)
Expand Down
2 changes: 1 addition & 1 deletion openaq_api/openaq_api/routers/averages.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,5 +147,5 @@ async def averages_v2_get(
{query.pagination()}
"""

response = await db.fetchPage(sql, query.params(), config)
response = await db.fetchPage(sql, query.params(), config=config)
return response

0 comments on commit 984d940

Please sign in to comment.