github_primary_ratelimit

package
v2.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 12, 2025 License: MIT Imports: 11 Imported by: 3

Documentation

Index

Constants

This section is empty.

Variables

View Source
var PrimaryLimitStatusCodes = []int{
	http.StatusForbidden,
	http.StatusTooManyRequests,
}

Functions

func NewErrorResponse

func NewErrorResponse(request *http.Request, category ResourceCategory) *http.Response

func WithOverrideConfig

func WithOverrideConfig(ctx context.Context, opts ...Option) context.Context

WithOverrideConfig adds config overrides to the context. The overrides are applied on top of the existing config. Allows for request-specific overrides.

Types

type AtomicTime

type AtomicTime = atomic.Pointer[SecondsSinceEpoch]

-------------------------

type CallbackContext

type CallbackContext struct {
	RoundTripper *PrimaryRateLimiter
	Request      *http.Request
	Response     *http.Response
	ResetTime    *time.Time
	Category     ResourceCategory
}

CallbackContext is passed to all callbacks. Fields might be nillable, depending on the specific callback and field.

func (*CallbackContext) AsError

func (ctx *CallbackContext) AsError() *RateLimitReachedError

type Config

type Config struct {
	// contains filtered or unexported fields
}

Config is the configuration for the rate limiter. It is used internally and generated from the options. It holds the state of the rate limiter in order to enable state sharing.

func (*Config) ApplyOptions

func (c *Config) ApplyOptions(opts ...Option)

ApplyOptions applies the options to the config.

func (*Config) TriggerLimitReached

func (c *Config) TriggerLimitReached(ctx *CallbackContext)

func (*Config) TriggerLimitReset

func (c *Config) TriggerLimitReset(ctx *CallbackContext)

func (*Config) TriggerRequestPrevented

func (c *Config) TriggerRequestPrevented(ctx *CallbackContext)

func (*Config) TriggerUnknownCategory

func (c *Config) TriggerUnknownCategory(ctx *CallbackContext)

type ConfigOverridesKey

type ConfigOverridesKey struct{}

type OnLimitReached

type OnLimitReached func(*CallbackContext)

OnLimitReached is called when a new rate limit is detected.

type OnLimitReset

type OnLimitReset func(*CallbackContext)

OnLimitReset is called when a rate limit reset time is reached, which means that the category is available for use again.

type OnRequestPrevented

type OnRequestPrevented func(*CallbackContext)

OnRequestPrevented is called when an existing rate limit is detected, such that the current request is not sent.

type OnUnknownCategory

type OnUnknownCategory func(*CallbackContext)

OnUnknownCategory is called when an unknown category is detected at the response, which means that the rate limiter does not handle it.

type Option

type Option func(*Config)

func GetConfigOverrides

func GetConfigOverrides(ctx context.Context) []Option

GetConfigOverrides returns the config overrides from the context, if any.

func WithBypassLimit

func WithBypassLimit() Option

WithBypassLimit is used to flag that no requests shall be prevented. Callbacks are still called regardless of this flag. This is useful for testing, out-of-band token switching, etc.

func WithLimitDetectedCallback

func WithLimitDetectedCallback(callback OnLimitReached) Option

WithLimitDetectedCallback adds a callback to be called when a new active rate limit is detected.

func WithLimitResetCallback

func WithLimitResetCallback(callback OnLimitReset) Option

WithLimitResetCallback adds a callback to be called when a rate limit is reset, i.e., when an ongoing rate limit is no longer active.

func WithRequestPreventedCallback

func WithRequestPreventedCallback(callback OnRequestPrevented) Option

WithRequestPreventedCallback adds a callback to be called when a request is prevented, i.e., when the rate limit is active. note: this callback is not called when the limit is first detected.

func WithSharedState

func WithSharedState(state *RateLimitState) Option

WithSharedState is used to set the rate limiter state from an external source. Specifically, it is used to share the state between multiple rate limiters. e.g., `rateLimiterB := New(nil, WithSharedState(rateLimiterA.GetState()))`

func WithSleepUntilReset

func WithSleepUntilReset() Option

WithSleepUntilReset is used to flag that the rate limiter shall sleep until the reset time. This is useful for testing, long-running offline applications, etc. Note: it is using the LimitDetectedCallback, so it will not be otherwise called.

func WithUnknownCategoryCallback

func WithUnknownCategoryCallback(callback OnUnknownCategory) Option

WithUnknownCategoryCallback adds a callback to be called when a response from Github contains an unknown category. please open an issue if you encounter this to help improve the handling.

type ParsedResponse

type ParsedResponse struct {
	// contains filtered or unexported fields
}

ParsedResponse is a wrapper around http.Response that provides additional functionality. It is used to parse the response and extract rate limit information.

func (ParsedResponse) GetCatgory

func (p ParsedResponse) GetCatgory() ResourceCategory

func (ParsedResponse) GetResetTime

func (p ParsedResponse) GetResetTime() *SecondsSinceEpoch

type PrimaryRateLimiter

type PrimaryRateLimiter struct {
	Base http.RoundTripper
	// contains filtered or unexported fields
}

PrimaryRateLimiter is a RoundTripper for avoiding GitHub primary rate limits. see notes @ ratelimit_state.go for design considerations.

func New

func New(base http.RoundTripper, opts ...Option) *PrimaryRateLimiter

func (*PrimaryRateLimiter) GetState

func (l *PrimaryRateLimiter) GetState() *RateLimitState

GetState can be used to share the primary rate limit knowledge - when multiple clients are involved. TODO add tests for state sharing

func (*PrimaryRateLimiter) RoundTrip

func (l *PrimaryRateLimiter) RoundTrip(request *http.Request) (*http.Response, error)

type RateLimitReachedError

type RateLimitReachedError struct {
	ResetTime *time.Time
	Request   *http.Request
	Response  *http.Response
	Category  ResourceCategory
}

RateLimitReachedError is an error type for when the primary rate limit is reached.

func (*RateLimitReachedError) Error

func (e *RateLimitReachedError) Error() string

type RateLimitState

type RateLimitState struct {
	// contains filtered or unexported fields
}

func NewRateLimitState

func NewRateLimitState(categories []ResourceCategory) *RateLimitState

func (*RateLimitState) GetResetTime

func (s *RateLimitState) GetResetTime(category ResourceCategory) *SecondsSinceEpoch

func (*RateLimitState) Update

func (s *RateLimitState) Update(config *Config, update UpdateContainer, callbackContext *CallbackContext) *SecondsSinceEpoch

type ResourceCategory

type ResourceCategory string

General references (note there are some inconsistencies between them): https://docs.github.com/en/rest/rate-limit/rate-limit#about-rate-limits https://docs.github.com/en/rest/rate-limit/rate-limit#get-rate-limit-status-for-the-authenticated-user

const (
	// The default category
	// used for all HTTP method/url with no other match.
	ResourceCategoryCore ResourceCategory = "core"

	// https://docs.github.com/en/rest/search/search#about-search
	// * /search (except for /search/code)
	ResourceCategorySearch ResourceCategory = "search"

	// https://docs.github.com/en/rest/search/search#search-code
	// * /search/code
	ResourceCategoryCodeSearch ResourceCategory = "code_search"

	// https://docs.github.com/en/graphql
	// * /graphql
	ResourceCategoryGraphQL ResourceCategory = "graphql"

	// https://docs.github.com/en/rest/migrations/source-imports#start-an-import
	// deprecated endpoint; still applicable
	// * /repos/{OWNER}/{REPO}/import
	ResourceCategorySourceImport ResourceCategory = "source_import"

	// https://docs.github.com/en/enterprise-cloud@latest/rest/enterprise-admin/audit-log#get-the-audit-log-for-an-enterprise
	// * /enterprises/{ENTERPRISE}/audit-log
	ResourceCategoryAuditLog ResourceCategory = "audit_log"

	// https://docs.github.com/en/rest/dependency-graph/dependency-submission
	// POST /app/manfiests/{code}/conversions
	ResourceCategoryIntegrationManifest ResourceCategory = "integration_manifest"

	// https://docs.github.com/en/rest/dependency-graph/dependency-submission#create-a-snapshot-of-dependencies-for-a-repository
	// POST /repos/{OWNER}/{REPO}/dependency-graph/snapshots
	ResourceCategoryDependencySnapshots ResourceCategory = "dependency_snapshots"

	// https://docs.github.com/en/rest/code-scanning/code-scanning#upload-an-analysis-as-sarif-data
	// POST /repos/{OWNER}/{REPO}/code-scanning/sarifs
	ResourceCategoryCodeScanningUpload ResourceCategory = "code_scanning_upload"

	// https://docs.github.com/en/rest/actions/self-hosted-runners#about-self-hosted-runners-in-github-actions
	// "... for registring self-hosted runners"; assuming only POST requests are counted
	// POST /orgs/{ORG}/actions/runners
	ResourceCategoryActionsRunnerRegistration ResourceCategory = "actions_runner_registration"

	// https://docs.github.com/en/enterprise-cloud@latest/rest/scim/scim
	// no explicit documentation; assuming only POST requests are counted
	// POST /scim
	ResourceCategoryScim ResourceCategory = "scim"

	// https://docs.github.com/en/enterprise-cloud@latest/admin/monitoring-activity-in-your-enterprise/reviewing-audit-logs-for-your-enterprise/streaming-the-audit-log-for-your-enterprise
	// no API endpoints
	ResourceCategoryAuditLogStreaming ResourceCategory = "audit_log_streaming"
)

func GetAllCategories

func GetAllCategories() []ResourceCategory

type ResponseHeaderKey

type ResponseHeaderKey string

https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api#checking-the-status-of-your-rate-limit

const (
	ResponseHeaderKeyRemaining ResponseHeaderKey = "x-ratelimit-remaining"
	ResponseHeaderKeyReset     ResponseHeaderKey = "x-ratelimit-reset"
	ResponseHeaderKeyCategory  ResponseHeaderKey = "x-ratelimit-resource"
)

https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api#exceeding-the-rate-limit

func (ResponseHeaderKey) Get

func (k ResponseHeaderKey) Get(response *http.Response) string

type SecondsSinceEpoch

type SecondsSinceEpoch int64

func (SecondsSinceEpoch) AsTime

func (s SecondsSinceEpoch) AsTime() *time.Time

func (SecondsSinceEpoch) StartTimer

func (s SecondsSinceEpoch) StartTimer() *time.Timer

type UpdateContainer

type UpdateContainer interface {
	GetCatgory() ResourceCategory
	GetResetTime() *SecondsSinceEpoch
}

UpdateContainer is a simple abstraction over HTTP response, to isolate the perf-centric state management domain from the rest of the logic. It retains the wider-domain terminology of categories, but it is just a key-string as far as RateLimitState is concerned.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL