credit

package
v1.0.0-beta.106 Latest Latest
Warning

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

Go to latest
Published: Jul 1, 2024 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Index

Constants

View Source
const (
	GrantPriorityDefault uint8 = 1
)

Variables

This section is empty.

Functions

func SortedPeriodsFromDedupedTimes

func SortedPeriodsFromDedupedTimes(ts []time.Time) []recurrence.Period

Returns a list of non-overlapping periods between the sorted times.

Types

type BalanceConnector

type BalanceConnector interface {
	GetBalanceOfOwner(ctx context.Context, owner NamespacedGrantOwner, at time.Time) (*GrantBalanceSnapshot, error)
	GetBalanceHistoryOfOwner(ctx context.Context, owner NamespacedGrantOwner, params BalanceHistoryParams) (GrantBurnDownHistory, error)
	ResetUsageForOwner(ctx context.Context, owner NamespacedGrantOwner, params ResetUsageForOwnerParams) (balanceAfterReset *GrantBalanceSnapshot, err error)
}

Generic connector for balance related operations.

func NewBalanceConnector

func NewBalanceConnector(
	grantRepo GrantRepo,
	balanceSnapshotConnector BalanceSnapshotConnector,
	ownerConnector OwnerConnector,
	streamingConnector streaming.Connector,
	logger *slog.Logger,
) BalanceConnector

type BalanceHistoryParams

type BalanceHistoryParams struct {
	From time.Time
	To   time.Time
}

type BalanceSnapshotConnector

type BalanceSnapshotConnector interface {
	InvalidateAfter(ctx context.Context, owner NamespacedGrantOwner, at time.Time) error
	GetLatestValidAt(ctx context.Context, owner NamespacedGrantOwner, at time.Time) (GrantBalanceSnapshot, error)
	Save(ctx context.Context, owner NamespacedGrantOwner, balances []GrantBalanceSnapshot) error

	entutils.TxCreator
	entutils.TxUser[BalanceSnapshotConnector]
}

type CreateGrantInput

type CreateGrantInput struct {
	Amount           float64
	Priority         uint8
	EffectiveAt      time.Time
	Expiration       ExpirationPeriod
	Metadata         map[string]string
	ResetMaxRollover float64
	ResetMinRollover float64
	Recurrence       *recurrence.Recurrence
}

type EndCurrentUsagePeriodParams

type EndCurrentUsagePeriodParams struct {
	At           time.Time
	RetainAnchor bool
}

type Engine

type Engine interface {
	Run(ctx context.Context, grants []Grant, startingBalances GrantBalanceMap, startingOverage float64, period recurrence.Period) (endingBalances GrantBalanceMap, endingOverage float64, history []GrantBurnDownHistorySegment, err error)
}

func NewEngine

func NewEngine(getFeatureUsage QueryUsageFn, granuality models.WindowSize) Engine

type ExpirationPeriod

type ExpirationPeriod struct {
	// Count The expiration period count like 12 months.
	Count uint8 `json:"count,omitempty"`

	// Duration The expiration period duration like month.
	Duration ExpirationPeriodDuration `json:"duration,omitempty"`
}

ExpirationPeriod of a credit grant.

func (ExpirationPeriod) GetExpiration

func (c ExpirationPeriod) GetExpiration(t time.Time) time.Time

type ExpirationPeriodDuration

type ExpirationPeriodDuration string
const (
	ExpirationPeriodDurationHour  ExpirationPeriodDuration = "HOUR"
	ExpirationPeriodDurationDay   ExpirationPeriodDuration = "DAY"
	ExpirationPeriodDurationWeek  ExpirationPeriodDuration = "WEEK"
	ExpirationPeriodDurationMonth ExpirationPeriodDuration = "MONTH"
	ExpirationPeriodDurationYear  ExpirationPeriodDuration = "YEAR"
)

Defines values for ExpirationPeriodDuration.

func (ExpirationPeriodDuration) Values

func (ExpirationPeriodDuration) Values() (kinds []string)

type Grant

type Grant struct {
	models.ManagedModel
	models.NamespacedModel

	// ID is the readonly identifies of a grant.
	ID string `json:"id,omitempty"`

	// Generic Owner reference
	OwnerID GrantOwner `json:"owner"`

	// Amount The amount to grant. Can be positive or negative number.
	Amount float64 `json:"amount"`

	// Priority is a positive decimal numbers. With lower numbers indicating higher importance;
	// for example, a priority of 1 is more urgent than a priority of 2.
	// When there are several credit grants available for a single invoice, the system selects the credit with the highest priority.
	// In cases where credit grants share the same priority level, the grant closest to its expiration will be used first.
	// In the case of two credits have identical priorities and expiration dates, the system will use the credit that was created first.
	Priority uint8 `json:"priority"`

	// EffectiveAt The effective date.
	EffectiveAt time.Time `json:"effectiveAt"`

	// Expiration The expiration configuration.
	Expiration ExpirationPeriod `json:"expiration"`
	// ExpiresAt contains the exact expiration date calculated from effectiveAt and Expiration for rendering.
	// ExpiresAt is exclusive, meaning that the grant is no longer active after this time, but it is still active at the time.
	ExpiresAt time.Time `json:"expiresAt"`

	Metadata map[string]string `json:"metadata,omitempty"`

	// For user initiated voiding of the grant.
	VoidedAt *time.Time `json:"voidedAt,omitempty"`

	// How much of the grant can be rolled over after a reset operation.
	// Balance after a reset will be between ResetMinRollover and ResetMaxRollover.
	ResetMaxRollover float64 `json:"resetMaxRollover"`

	// How much balance the grant must have after a reset.
	// Balance after a reset will be between ResetMinRollover and ResetMaxRollover.
	ResetMinRollover float64 `json:"resetMinRollover"`

	// Recurrence config for the grant. If nil the grant doesn't recur.
	Recurrence *recurrence.Recurrence `json:"recurrence,omitempty"`
}

Grant is an immutable definition used to increase balance.

func (Grant) ActiveAt

func (g Grant) ActiveAt(t time.Time) bool

func (Grant) GetExpiration

func (g Grant) GetExpiration() time.Time

Calculates expiration from effectiveAt and Expiration.

func (Grant) GetNamespacedID

func (g Grant) GetNamespacedID() models.NamespacedID

func (Grant) GetNamespacedOwner

func (g Grant) GetNamespacedOwner() NamespacedGrantOwner

func (Grant) RecurrenceBalance

func (g Grant) RecurrenceBalance(currentBalance float64) float64

Calculates the new balance after a recurrence from the current balance

func (Grant) RolloverBalance

func (g Grant) RolloverBalance(currentBalance float64) float64

Calculates the new balance after a rollover from the current balance

type GrantBalanceMap

type GrantBalanceMap map[string]float64

Represents a point in time balance of grants

func (GrantBalanceMap) Balance

func (g GrantBalanceMap) Balance() float64

returns the combined balance of all grants

func (GrantBalanceMap) Burn

func (g GrantBalanceMap) Burn(grantID string, amount float64)

func (GrantBalanceMap) Copy

func (GrantBalanceMap) ExactlyForGrants

func (g GrantBalanceMap) ExactlyForGrants(grants []Grant) bool

Whether the contents of the GrantBalanceMap exactly matches the list of provided grants. Return false if it has additional grants or if it misses any grants

func (GrantBalanceMap) OverrideWith

func (g GrantBalanceMap) OverrideWith(gbm GrantBalanceMap)

func (GrantBalanceMap) Set

func (g GrantBalanceMap) Set(grantID string, amount float64)

type GrantBalanceNoSavedBalanceForOwnerError

type GrantBalanceNoSavedBalanceForOwnerError struct {
	Owner NamespacedGrantOwner
	Time  time.Time
}

No balance has been saved since start of measurement for the owner

func (GrantBalanceNoSavedBalanceForOwnerError) Error

type GrantBalanceSnapshot

type GrantBalanceSnapshot struct {
	Balances GrantBalanceMap
	Overage  float64
	At       time.Time
}

func (GrantBalanceSnapshot) Balance

func (g GrantBalanceSnapshot) Balance() float64

type GrantBurnDownHistory

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

func NewGrantBurnDownHistory

func NewGrantBurnDownHistory(segments []GrantBurnDownHistorySegment) (*GrantBurnDownHistory, error)

func (*GrantBurnDownHistory) Overage

func (g *GrantBurnDownHistory) Overage() float64

func (*GrantBurnDownHistory) Segments

func (*GrantBurnDownHistory) TotalUsage

func (g *GrantBurnDownHistory) TotalUsage() float64

type GrantBurnDownHistorySegment

type GrantBurnDownHistorySegment struct {
	recurrence.Period
	BalanceAtStart     GrantBalanceMap
	TerminationReasons SegmentTerminationReason // Reason why the segment was terminated (could be multiple taking effect at same time)
	TotalUsage         float64                  // Total usage of the feature in the Period
	OverageAtStart     float64                  // Usage beyond what could be burnt down from the grants in the previous segment (if any)
	Overage            float64                  // Usage beyond what cloud be burnt down from the grants
	GrantUsages        []GrantUsage             // Grant usages in the segment order by grant priority
}

GrantBurnDownHistorySegment represents the smallest segment of grant usage which we store and calculate.

A segment represents a period of time in which: 1) The grant priority does not change 2) Grants do not recurr 3) There was no usage reset

It is not necessarily the largest such segment.

func (GrantBurnDownHistorySegment) ApplyUsage

Returns GrantBalanceMap at the end of the segment

func (*GrantBurnDownHistorySegment) ToSnapshot

Creates a GrantBalanceSnapshot from the starting state of the segment

type GrantConnector

type GrantConnector interface {
	CreateGrant(ctx context.Context, owner NamespacedGrantOwner, grant CreateGrantInput) (*Grant, error)
	VoidGrant(ctx context.Context, grantID models.NamespacedID) error
	ListGrants(ctx context.Context, params ListGrantsParams) ([]Grant, error)
	ListActiveGrantsBetween(ctx context.Context, owner NamespacedGrantOwner, from, to time.Time) ([]Grant, error)
	GetGrant(ctx context.Context, grantID models.NamespacedID) (Grant, error)
}

func NewGrantConnector

func NewGrantConnector(
	ownerConnector OwnerConnector,
	grantRepo GrantRepo,
	balanceSnapshotConnector BalanceSnapshotConnector,
	granularity time.Duration,
) GrantConnector

type GrantNotFoundError

type GrantNotFoundError struct {
	GrantID string
}

func (*GrantNotFoundError) Error

func (e *GrantNotFoundError) Error() string

type GrantOrderBy

type GrantOrderBy string
const (
	GrantOrderByCreatedAt   GrantOrderBy = "created_at"
	GrantOrderByUpdatedAt   GrantOrderBy = "updated_at"
	GrantOrderByExpiresAt   GrantOrderBy = "expires_at"
	GrantOrderByEffectiveAt GrantOrderBy = "effective_at"
	GrantOrderByOwner       GrantOrderBy = "owner_id" // check
)

type GrantOwner

type GrantOwner string

type GrantRepo

type GrantRepo interface {
	CreateGrant(ctx context.Context, grant GrantRepoCreateGrantInput) (*Grant, error)
	VoidGrant(ctx context.Context, grantID models.NamespacedID, at time.Time) error
	ListGrants(ctx context.Context, params ListGrantsParams) ([]Grant, error)
	// ListActiveGrantsBetween returns all grants that are active at any point between the given time range.
	ListActiveGrantsBetween(ctx context.Context, owner NamespacedGrantOwner, from, to time.Time) ([]Grant, error)
	GetGrant(ctx context.Context, grantID models.NamespacedID) (Grant, error)

	entutils.TxCreator
	entutils.TxUser[GrantRepo]
}

type GrantRepoCreateGrantInput

type GrantRepoCreateGrantInput struct {
	OwnerID          GrantOwner
	Namespace        string
	Amount           float64
	Priority         uint8
	EffectiveAt      time.Time
	Expiration       ExpirationPeriod
	ExpiresAt        time.Time
	Metadata         map[string]string
	ResetMaxRollover float64
	ResetMinRollover float64
	Recurrence       *recurrence.Recurrence
}

type GrantUsage

type GrantUsage struct {
	GrantID           string
	Usage             float64
	TerminationReason GrantUsageTerminationReason
}

type GrantUsageTerminationReason

type GrantUsageTerminationReason string
const (
	GrantUsageTerminationReasonExhausted          GrantUsageTerminationReason = "GRANT_EXHAUSTED"     // Grant has been fully used
	GrantUsageTerminationReasonSegmentTermination GrantUsageTerminationReason = "SEGMENT_TERMINATION" // Segment has been terminated
)

func (GrantUsageTerminationReason) IsValid

type ListGrantsParams

type ListGrantsParams struct {
	Namespace      string
	OwnerID        *GrantOwner
	IncludeDeleted bool
	Offset         int
	Limit          int
	OrderBy        GrantOrderBy
}

type NamespacedGrantOwner

type NamespacedGrantOwner struct {
	Namespace string
	ID        GrantOwner
}

func (NamespacedGrantOwner) NamespacedID

func (n NamespacedGrantOwner) NamespacedID() models.NamespacedID

Casts the NamespacedGrantOwner to a NamespacedID. Owner might not be a valid ID.

type OwnerConnector

type OwnerConnector interface {
	GetMeter(ctx context.Context, owner NamespacedGrantOwner) (*OwnerMeter, error)
	GetStartOfMeasurement(ctx context.Context, owner NamespacedGrantOwner) (time.Time, error)
	GetPeriodStartTimesBetween(ctx context.Context, owner NamespacedGrantOwner, from, to time.Time) ([]time.Time, error)
	GetUsagePeriodStartAt(ctx context.Context, owner NamespacedGrantOwner, at time.Time) (time.Time, error)

	//FIXME: this is a terrible hack
	EndCurrentUsagePeriodTx(ctx context.Context, tx *entutils.TxDriver, owner NamespacedGrantOwner, params EndCurrentUsagePeriodParams) error
	//FIXME: this is a terrible hack
	LockOwnerForTx(ctx context.Context, tx *entutils.TxDriver, owner NamespacedGrantOwner) error
}

type OwnerMeter

type OwnerMeter struct {
	MeterSlug     string
	DefaultParams *streaming.QueryParams
	WindowSize    models.WindowSize
}

type OwnerNotFoundError

type OwnerNotFoundError struct {
	Owner          NamespacedGrantOwner
	AttemptedOwner string
}

func (OwnerNotFoundError) Error

func (e OwnerNotFoundError) Error() string

type Pagination

type Pagination struct {
	Offset int
	Limit  int
}

type QueryUsageFn

type QueryUsageFn func(ctx context.Context, from, to time.Time) (float64, error)

type ResetUsageForOwnerParams

type ResetUsageForOwnerParams struct {
	At           time.Time
	RetainAnchor bool
}

type SegmentTerminationReason

type SegmentTerminationReason struct {
	PriorityChange bool
	Recurrence     []string // Grant IDs
	UsageReset     bool
}

Jump to

Keyboard shortcuts

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