Documentation
¶
Index ¶
- Variables
- func IsPermissionError(err error) bool
- func IsRateLimitError(err error) bool
- func NewApiClient(cfg *databricks.Config) (*httpclient.ApiClient, error)
- func NewQuerier[T any](conn *DatabricksExecutor) querier.Querier[T]
- func NewWorkspaceClient(cfg *databricks.Config) (*databricks.WorkspaceClient, error)
- func RateLimitRetryAfter(err error) (time.Duration, bool)
- func WithPacing(cfg *databricks.Config) *databricks.Config
- type Auth
- type DatabricksConf
- type DatabricksExecutor
- func (e *DatabricksExecutor) Close() error
- func (e *DatabricksExecutor) Exec(ctx context.Context, query string, args ...any) error
- func (e *DatabricksExecutor) GetDb() *sqlx.DB
- func (e *DatabricksExecutor) QueryRows(ctx context.Context, sql string, args ...interface{}) (*sqlx.Rows, error)
- func (e *DatabricksExecutor) Select(ctx context.Context, dest any, query string, args ...any) error
- type Executor
- type OAuthM2mAuth
- type Pacing
- type RateLimitedError
- type Throttle
- type ThrottleStats
- type TokenAuth
Constants ¶
This section is empty.
Variables ¶
var DefaultPacing = Pacing{ FirstInterval: 100 * time.Millisecond, MaxInterval: 5 * time.Second, MaxPause: 30 * time.Second, DecayAfter: 50, MaxAttempts: 8, WaitBudget: 45 * time.Second, }
DefaultPacing is what every client built here uses unless the workspace's throttle was given something else through UsePacing.
Functions ¶
func IsPermissionError ¶ added in v0.15.3
IsPermissionError reports whether err indicates the DWH credentials lack the privileges required for the attempted operation.
func IsRateLimitError ¶ added in v0.17.1
IsRateLimitError reports whether err is a workspace refusing a request for exceeding its quota — whether it comes from the pacing here or straight from the SDK, which is what a caller holding an error off any Databricks client sees.
func NewApiClient ¶ added in v0.17.1
func NewApiClient(cfg *databricks.Config) (*httpclient.ApiClient, error)
NewApiClient builds the raw client for endpoints the SDK does not model — Unity Catalog's table-lineage endpoint is the one that matters — paced by the same throttle as the workspace client of the same workspace.
Unlike the workspace client, this one can be told not to retry a refusal itself, and is: the retry belongs to the caller, which is what holds the throttle and can wait the refusal out at the pace the whole process has converged on.
func NewQuerier ¶
func NewQuerier[T any](conn *DatabricksExecutor) querier.Querier[T]
func NewWorkspaceClient ¶ added in v0.17.1
func NewWorkspaceClient(cfg *databricks.Config) (*databricks.WorkspaceClient, error)
NewWorkspaceClient builds the Databricks workspace client, paced against the workspace's control-plane quota. Every caller goes through it rather than databricks.NewWorkspaceClient: a client built with stock SDK defaults retries a refusal blindly for five minutes, ignores Retry-After and never reduces the rate it offers, which leaves it absorbing the quota that the callers which do pace themselves have given up.
func RateLimitRetryAfter ¶ added in v0.17.1
RateLimitRetryAfter reports whether err is a workspace refusing a request for exceeding its quota, and how long it asked us to wait before asking again.
func WithPacing ¶ added in v0.17.1
func WithPacing(cfg *databricks.Config) *databricks.Config
WithPacing installs the rate-limit pacing on a config, and is what makes every client built from that config share one throttle per workspace. Idempotent, so a config that has already been paced — one taken off a client built here — can be handed to another constructor.
Types ¶
type Auth ¶
type Auth interface {
Configure(config *databricks.Config)
}
type DatabricksConf ¶
type DatabricksExecutor ¶
type DatabricksExecutor struct {
// contains filtered or unexported fields
}
func NewDatabricksExecutor ¶
func NewDatabricksExecutor(ctx context.Context, conf *DatabricksConf) (*DatabricksExecutor, error)
func (*DatabricksExecutor) Close ¶
func (e *DatabricksExecutor) Close() error
func (*DatabricksExecutor) GetDb ¶
func (e *DatabricksExecutor) GetDb() *sqlx.DB
type Executor ¶
type Executor interface {
stdsql.StdSqlExecutor
}
type OAuthM2mAuth ¶
func NewOAuthM2mAuth ¶
func NewOAuthM2mAuth(clientId, clientSecret string) *OAuthM2mAuth
func (OAuthM2mAuth) Configure ¶
func (o OAuthM2mAuth) Configure(config *databricks.Config)
type Pacing ¶ added in v0.17.1
type Pacing struct {
// FirstInterval is the spacing adopted the first time a request is refused.
// Until then a workspace is unpaced and runs at whatever the callers and the
// SDK's own client-side limiter allow, so a workspace that is never refused pays
// nothing for any of this.
FirstInterval time.Duration
// MaxInterval caps the spacing. Past it, waiting longer no longer buys a caller
// anything its own deadline will not decide first.
MaxInterval time.Duration
// MaxPause caps how long one refusal may hold requests back, and with it the
// Retry-After the API asks for. A wait longer than this outlives the per-attempt
// timeout the SDK puts on a request, so honouring it verbatim would turn a
// refusal into a request that times out mid-flight instead of one that waits.
MaxPause time.Duration
// DecayAfter is how many consecutive accepted requests it takes to halve the
// spacing again. The quota is shared with everything else running against the
// workspace, so a client has to keep probing back towards full speed rather than
// stay slow for the rest of the process's life.
DecayAfter int
// MaxAttempts bounds how many times one request may be refused before the error
// is handed to the caller.
MaxAttempts int
// WaitBudget bounds how long one request may spend held back across all of its
// attempts. It exists for the same reason as MaxPause: the waiting happens inside
// the SDK's per-attempt timeout, so it cannot be unbounded.
WaitBudget time.Duration
}
Pacing is how a client reacts to a Databricks workspace refusing a request for exceeding its control-plane quota. The interval it converges on is the spacing between requests of the whole process, not of one caller, so it is what actually bounds the load put on one workspace.
type RateLimitedError ¶ added in v0.17.1
type RateLimitedError struct {
// StatusCode, ErrorCode and Message are what the workspace answered with. They are
// deliberately not part of Error(): the SDK re-sends any error whose *text*
// contains REQUEST_LIMIT_EXCEEDED — a workaround for SCIM answering 500 on a rate
// limit — and it runs that check on whatever error the transport hands back. An
// error quoting the API's own code or message would therefore go straight back
// under the blind five-minute retry this type exists to prevent. Callers that want
// them in a log line read the fields.
StatusCode int
ErrorCode string
Message string
// RetryAfter is the wait the API last asked for, zero when it asked for nothing.
RetryAfter time.Duration
// Attempts is how many times the request was sent and refused.
Attempts int
// Waited is how long this request spent held back before giving up.
Waited time.Duration
}
RateLimitedError is what a request refused for exceeding a workspace's quota fails with once the pacing has run out of attempts to spend on it.
It is returned in place of the API's own error because it is the only way to keep the SDK from re-sending the request: the SDK retries a rate-limited response blindly for five minutes, ignoring Retry-After, which hides the refusal from the pacing and parks the caller on a request that is being refused. Everything else the SDK treats as transient is still the SDK's to retry.
func (*RateLimitedError) Error ¶ added in v0.17.1
func (e *RateLimitedError) Error() string
type Throttle ¶ added in v0.17.1
type Throttle struct {
// contains filtered or unexported fields
}
Throttle paces every control-plane request one process sends to one workspace. Every request passes through it, which is the point: a refusal seen by one caller holds back all of them, where each caller retrying on its own kept the workspace's quota exhausted for as long as any of them had work left.
func NewThrottle ¶ added in v0.17.1
func ThrottleFor ¶ added in v0.17.1
ThrottleFor returns the throttle every client of that workspace shares, creating it with DefaultPacing on first use. Callers read ThrottleStats off it for their own log line.
func UsePacing ¶ added in v0.17.1
UsePacing installs a workspace's throttle with pacing of the caller's choosing. It has to run before the first client for that workspace is built — once a throttle exists it keeps the pacing it was created with, so that a client cannot have the spacing pulled out from under a request already in flight. Meant for tests, which need the convergence to happen in milliseconds, and for a caller that knows a workspace's quota is tighter than most.
func (*Throttle) Accepted ¶ added in v0.17.1
func (t *Throttle) Accepted()
Accepted records that a request went through, and speeds the process back up once enough of them have.
func (*Throttle) Acquire ¶ added in v0.17.1
Acquire blocks until this request's turn to be sent, or until ctx is done. It reports how long the caller was held back.
func (*Throttle) Pacing ¶ added in v0.17.1
Pacing returns the pacing behaviour this throttle was built with.
func (*Throttle) Refused ¶ added in v0.17.1
Refused records that the workspace rejected a request for exceeding its quota. retryAfter is what the API asked for, zero when it asked for nothing.
func (*Throttle) Stats ¶ added in v0.17.1
func (t *Throttle) Stats() ThrottleStats
Stats reports what the throttle did, for the caller's log line and span.
type ThrottleStats ¶ added in v0.17.1
type ThrottleStats struct {
// Refusals is how many requests the workspace refused for exceeding its quota.
Refusals int
// Waited is the total time requests spent held back. It sums over concurrent
// requests, so it can exceed the wall clock of the run.
Waited time.Duration
// Interval is the spacing currently handed out. Zero means unpaced.
Interval time.Duration
}
ThrottleStats reports what a workspace's throttle has done, for the caller's own log line and span. The counters run for the life of the process, because so does the throttle — a caller reporting on one run of its own takes a snapshot before it starts and calls Since on the one it takes after.
func (ThrottleStats) Paced ¶ added in v0.17.1
func (s ThrottleStats) Paced() bool
Paced reports whether the workspace refused anything, which is the only reason these numbers are worth a log line.
func (ThrottleStats) Since ¶ added in v0.17.1
func (s ThrottleStats) Since(earlier ThrottleStats) ThrottleStats
Since reports what happened between an earlier snapshot and this one. Interval is current rather than differenced: it is a rate, not a count.