Skip to content

Conversation

@jjinno
Copy link

@jjinno jjinno commented May 21, 2019

Minor changes in order to better support multi-threading..

  1. External pagination required the Collection.count() method to be updated to support when the base_container is not None (ex: when it is an Incident). This looks like it was probably an accidental oversight, as most other Collection methods already take this into consideration.
  2. Pagination in the REST API v2 does not use the /count endpoint anymore. Though empirical evidence suggests they have not removed support for it on the main incidents list, there are multiple documentation/community references that suggest it is no longer supported.
  3. Threading-off paginated requests in parallel (note to use one PagerDuty instance per thread) rapidly causes requests to run into HTTPError (429) and/or URLError (timeout), eliciting the need for an exponential-backoff-and-retry loop in order to not prematurely break out from iterator/generator loops.

jjinno added 8 commits May 8, 2019 10:38
The v2 REST API no longer officially supports the "/count" path. Although empirical evidence would suggest it still exists for "/incidents/count", there is no documentation supporting this, and plenty of support conversations suggesting otherwise. This is especially true for sub-container elements such as Incident.log_entries.

This update converts all "count" calls to use the documented "total=true" parameter on a single paginated request. The use of "limit=1" has been explicitly avoided, as this seems to cause HTTP errors with certain incidents.
Partially ported from __init__.py, with the addition of now being exponential (instead of additive), and also now including some randomness (milliseconds) to the sleep.  This logic is specifically targeted toward URLError (url timeouts, etc), and HTTPError (429: too many requests).
Instead of one hard-to-read test, incident.log_entries testing is now broken into 2 less-hard-to-read tests
return self.execute_request(request, retry_count + 1)
else:
raise
elif err.code / 100 == 5:
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably want integer division here, err.code // 100


class Requester(object):
def __init__(self, timeout=10, proxies=None, parse_datetime=False):
def __init__(self, timeout=10, proxies=None, parse_datetime=False, min_backoff=15.0, max_retries=5):
Copy link
Contributor

Choose a reason for hiding this comment

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

Previously the timeout was 10s with no retries; with the retries + backoff it'll be a minimum 75s before the request will give up by default.

I'd prefer to lower the default values (maybe min_backoff=5 and retries=3), and we should provide a way for users to plumb through their own values, here: https://github.com/dropbox/pygerduty/blob/master/pygerduty/v2.py#L611

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

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.

3 participants