Module: Jbr::Asking

Included in:
OAuth
Defined in:
lib/jbr/asking.rb

Overview

What credentials do when they ask Jobber something: pace the request against both limits Jobber holds an app to, wait out a refusal it can recover from, and refresh a token that went stale on the way.

Constant Summary collapse

ATTEMPTS =

How many times a query refused for cost is asked again. Once is the answer where the bucket only had to refill, since the wait is worked out to cover exactly the shortfall. The rest are for a bucket the whole app shares: another process may drain it again while this one waits, and each attempt costs only the seconds Jobber says it needs.

4

Instance Method Summary collapse

Instance Method Details

#query(statement, variables: {}) ⇒ Hash

Run a statement, waiting for what Jobber will still answer and refreshing a stale token.

Returns:

  • (Hash)

    the data Jobber answered, or empty when the credentials are dead.



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/jbr/asking.rb', line 14

def query(statement, variables: {})
  attempts = 0
  begin
    throttle.wait
    client.query(statement, variables: variables) { |extensions| throttle.read extensions }
  rescue GraphQL::Unauthorized
    refresh ? retry : {}
  rescue GraphQL::Throttled => error
    # The refusal priced the query, so the throttle now knows the shortfall and `wait` at
    # the top of the retry sits out exactly that. Only a query costing more than the bucket
    # ever holds is hopeless; the rest is a walk that asked a moment too early.
    raise Error, error.message unless throttle.affordable? && (attempts += 1) < ATTEMPTS

    retry
  rescue GraphQL::Error => error
    # The transport's own class never leaves the gem: a caller told to rescue `Jbr::Error`
    # was not catching a throttle, a 500 or an unreadable answer, and had its own job blow
    # up instead of hearing that Jobber would not answer.
    raise Error, error.message
  end
end