credit

package
v1.0.0-beta.87 Latest Latest
Warning

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

Go to latest
Published: Jun 13, 2024 License: Apache-2.0 Imports: 8 Imported by: 0

README

[Experimental] OpenMeter Credits

OpenMeter can handle complex scenarios related to credit management, usage, and rate limits. You can grant credits via API for specific subjects with priorities, effective dates, and expiration dates. OpenMeter then burns down credits in order based on these parameters and the ingested usage, ensuring optimal performance.

OpenMeter Credits can help to implement:

  • Monthly usage-limit enforcement
  • Implementing prepaid credits
  • Combining recurring credits with top-ups
  • Rolling over remaining credits between billing periods

Quickstart

Run docker compose with --profile postgres and enable entitlements in config.yaml via

entitlements:
    enabled: true

Test

Credit tests require a Postgres database. The recommended way to run tests is to use make test, which runs the necessary dependencies via Dagger. If you need to iterate on credit tests quickly, you can run your own Postgres instance (or use the one run by docker-compose) and run tests manually as: POSTGRES_HOST=localhost go test ./internal/credit/...

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewLedgerAlreadyExistsProblem

func NewLedgerAlreadyExistsProblem(ctx context.Context, err error, existingEntry Ledger) models.Problem

Types

type Balance

type Balance struct {
	LedgerID        LedgerID          `json:"id"`
	Metadata        map[string]string `json:"metadata,omitempty"`
	Subject         string            `json:"subject"`
	FeatureBalances []FeatureBalance  `json:"featureBalances"`
	GrantBalances   []GrantBalance    `json:"grantBalances"`
}

Balance of a subject in a credit.

func (Balance) Render

func (c Balance) Render(w http.ResponseWriter, r *http.Request) error

Render implements the chi renderer interface.

type Connector

type Connector interface {
	// Ledger
	CreateLedger(ctx context.Context, ledger Ledger) (Ledger, error)
	ListLedgers(ctx context.Context, params ListLedgersParams) ([]Ledger, error)

	// Grant
	CreateGrant(ctx context.Context, grant Grant) (Grant, error)
	VoidGrant(ctx context.Context, grant Grant) (Grant, error)
	ListGrants(ctx context.Context, params ListGrantsParams) ([]Grant, error)
	GetGrant(ctx context.Context, grantID NamespacedGrantID) (Grant, error)

	// Credit
	GetBalance(ctx context.Context, ledgerID NamespacedLedgerID, cutline time.Time) (Balance, error)
	GetHistory(ctx context.Context, ledgerID NamespacedLedgerID, from time.Time, to time.Time, pagination Pagination) (LedgerEntryList, error)
	GetHighWatermark(ctx context.Context, ledgerID NamespacedLedgerID) (HighWatermark, error)
	Reset(ctx context.Context, reset Reset) (Reset, []Grant, error)

	// Feature
	CreateFeature(ctx context.Context, feature Feature) (Feature, error)
	DeleteFeature(ctx context.Context, featureID NamespacedFeatureID) error
	ListFeatures(ctx context.Context, params ListFeaturesParams) ([]Feature, error)
	GetFeature(ctx context.Context, featureID NamespacedFeatureID) (Feature, error)
}

type EntryType

type EntryType string
const (
	EntryTypeGrant     EntryType = "GRANT"
	EntryTypeVoidGrant EntryType = "VOID_GRANT"
	EntryTypeReset     EntryType = "RESET"
)

Defines values for EntryType.

func (EntryType) Values

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

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 Feature

type Feature struct {
	Namespace string     `json:"-"`
	ID        *FeatureID `json:"id,omitempty"`

	// Name The name of the feature.
	Name string `json:"name"`

	// MeterSlug The meter that the feature is associated with and decreases grants by usage.
	MeterSlug string `json:"meterSlug,omitempty"`

	// MeterGroupByFilters Optional meter group by filters. Useful if the meter scope is broader than what feature tracks.
	MeterGroupByFilters *map[string]string `json:"meterGroupByFilters,omitempty"`

	// Read-only fields
	Archived *bool `json:"archived,omitempty"`

	CreatedAt *time.Time `json:"createdAt,omitempty"`
	UpdatedAt *time.Time `json:"updatedAt,omitempty"`
}

Feature is a feature or service offered to a customer. For example: CPU-Hours, Tokens, API Calls, etc.

type FeatureBalance

type FeatureBalance struct {
	Feature
	Balance float64 `json:"balance"`
	Usage   float64 `json:"usage"`
}

type FeatureID

type FeatureID string

FeatureID is the unique identifier for a feature.

type FeatureInvalidFiltersError

type FeatureInvalidFiltersError struct {
	RequestedFilters    map[string]string
	MeterGroupByColumns []string
}

func (*FeatureInvalidFiltersError) Error

type FeatureNotFoundError

type FeatureNotFoundError struct {
	ID FeatureID
}

func (*FeatureNotFoundError) Error

func (e *FeatureNotFoundError) Error() string

type FeatureOrderBy

type FeatureOrderBy string
const (
	FeatureOrderByCreatedAt FeatureOrderBy = "created_at"
	FeatureOrderByUpdatedAt FeatureOrderBy = "updated_at"
	FeatureOrderByID        FeatureOrderBy = "id"
)

type FeatureWithNameAlreadyExistsError

type FeatureWithNameAlreadyExistsError struct {
	Name string
	ID   FeatureID
}

func (*FeatureWithNameAlreadyExistsError) Error

type Grant

type Grant struct {
	Namespace string `json:"-"`
	// ID is the readonly identifies of a grant.
	ID *GrantID `json:"id,omitempty"`

	// Parent ID is the readonly identifies of the grant's parent if any.
	ParentID *GrantID `json:"parentID,omitempty"`

	// Subject The subject to grant the amount to.
	LedgerID LedgerID `json:"ledgerID"`

	// Type The grant type.
	Type GrantType `json:"type"`

	// FeatureID The feature ID.
	FeatureID *FeatureID `json:"featureID"`

	// 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 time.Time `json:"expiresAt"`

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

	// Rollover Grant rollover configuration.
	Rollover *GrantRollover `json:"rollover,omitempty"`

	// Void The voided date.
	Void bool `json:"void"`

	CreatedAt *time.Time `json:"createdAt,omitempty"`
	UpdatedAt *time.Time `json:"updatedAt,omitempty"`
}

Grant is used to increase balance of specific subjects.

func (Grant) ExpirationDate

func (c Grant) ExpirationDate() time.Time

func (Grant) Render

func (c Grant) Render(w http.ResponseWriter, r *http.Request) error

Render implements the chi renderer interface.

type GrantBalance

type GrantBalance struct {
	Grant
	Balance float64 `json:"balance"`
}

type GrantID

type GrantID string

type GrantNotFoundError

type GrantNotFoundError struct {
	GrantID GrantID
}

func (*GrantNotFoundError) Error

func (e *GrantNotFoundError) Error() string

type GrantRollover

type GrantRollover struct {
	// MaxAmount Maximum amount to rollover.
	MaxAmount *float64 `json:"maxAmount,omitempty"`

	// Type The rollover type to use:
	Type GrantRolloverType `json:"type"`
}

GrantRollover configuration.

type GrantRolloverType

type GrantRolloverType string
const (
	GrantRolloverTypeOriginalAmount  GrantRolloverType = "ORIGINAL_AMOUNT"
	GrantRolloverTypeRemainingAmount GrantRolloverType = "REMAINING_AMOUNT"
)

Defines values for GrantRolloverType.

func (GrantRolloverType) Values

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

type GrantType

type GrantType string
const (
	GrantTypeUsage GrantType = "USAGE"
)

Defines values for GrantType.

func (GrantType) Values

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

type HighWatermarBeforeError

type HighWatermarBeforeError struct {
	Namespace     string
	LedgerID      LedgerID
	HighWatermark time.Time
}

HighWatermarBeforeError is returned when a lock cannot be obtained.

func (*HighWatermarBeforeError) Error

func (e *HighWatermarBeforeError) Error() string

type HighWatermark

type HighWatermark struct {
	LedgerID LedgerID  `ch:"ledger_id"`
	Time     time.Time `ch:"time"`
}

type Ledger

type Ledger struct {
	Namespace string `json:"-"`
	// ID is the ID of the ledger instance
	ID LedgerID `json:"id,omitempty"`

	// Subject specifies which metering subject this ledger is referring to
	Subject string `json:"subject"`

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

	// CreatedAt is the time the ledger was created
	CreatedAt time.Time `json:"createdAt"`
}

type LedgerAlreadyExistsError

type LedgerAlreadyExistsError struct {
	Ledger Ledger
}

func (*LedgerAlreadyExistsError) Error

func (e *LedgerAlreadyExistsError) Error() string

type LedgerAlreadyExistsProblemResponse

type LedgerAlreadyExistsProblemResponse struct {
	*models.StatusProblem
	ConflictingEntity Ledger `json:"conflictingEntity"`
}

func (*LedgerAlreadyExistsProblemResponse) Respond

type LedgerEntry

type LedgerEntry struct {
	ID        *GrantID        `json:"id,omitempty"`
	Type      LedgerEntryType `json:"type"`
	Time      time.Time       `json:"time"`
	FeatureID *FeatureID      `json:"featureId,omitempty"`
	Amount    *float64        `json:"amount,omitempty"`
	Period    *Period         `json:"period,omitempty"`
}

LedgerEntry is a credit ledger entry.

type LedgerEntryList

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

func NewLedgerEntryList

func NewLedgerEntryList() LedgerEntryList

func (*LedgerEntryList) AddGrant

func (c *LedgerEntryList) AddGrant(grant Grant)

func (*LedgerEntryList) AddGrantUsage

func (c *LedgerEntryList) AddGrantUsage(grantBalance GrantBalance, from time.Time, to time.Time, amount float64)

func (*LedgerEntryList) AddReset

func (c *LedgerEntryList) AddReset(reset Reset)

func (*LedgerEntryList) AddVoidGrant

func (c *LedgerEntryList) AddVoidGrant(grant Grant)

func (*LedgerEntryList) Append

func (c *LedgerEntryList) Append(other LedgerEntryList)

func (LedgerEntryList) GetEntries

func (f LedgerEntryList) GetEntries() []LedgerEntry

func (LedgerEntryList) Len

func (f LedgerEntryList) Len() int

func (LedgerEntryList) MarshalJSON

func (f LedgerEntryList) MarshalJSON() ([]byte, error)

func (LedgerEntryList) Skip

Skip removes the first n entries.

func (LedgerEntryList) Truncate

func (f LedgerEntryList) Truncate(limit int) LedgerEntryList

Truncate removes all entries after the limit.

type LedgerEntryType

type LedgerEntryType string
const (
	LedgerEntryTypeGrant      LedgerEntryType = "GRANT"
	LedgerEntryTypeVoid       LedgerEntryType = "VOID"
	LedgerEntryTypeReset      LedgerEntryType = "RESET"
	LedgerEntryTypeGrantUsage LedgerEntryType = "GRANT_USAGE"
)

Defines values for LedgerEntryType.

func (LedgerEntryType) Values

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

type LedgerID

type LedgerID string

type LedgerNotFoundError

type LedgerNotFoundError struct {
	LedgerID LedgerID
}

func (*LedgerNotFoundError) Error

func (e *LedgerNotFoundError) Error() string

type LedgerOrderBy

type LedgerOrderBy string
const (
	LedgerOrderByCreatedAt LedgerOrderBy = "created_at"
	LedgerOrderBySubject   LedgerOrderBy = "subject"
	LedgerOrderByID        LedgerOrderBy = "id"
)

type ListFeaturesParams

type ListFeaturesParams struct {
	Namespace       string
	IncludeArchived bool
	Offset          int
	Limit           int
	OrderBy         FeatureOrderBy
}

type ListGrantsParams

type ListGrantsParams struct {
	Namespace         string
	LedgerIDs         []LedgerID
	From              *time.Time
	To                *time.Time
	FromHighWatermark bool
	IncludeVoid       bool
	Limit             int
}

type ListLedgersParams

type ListLedgersParams struct {
	Namespace   string
	Subjects    []string
	SubjectLike string
	Offset      int
	Limit       int
	OrderBy     LedgerOrderBy
}

type LockErrNotObtainedError

type LockErrNotObtainedError struct {
	Namespace string
	ID        LedgerID
}

LockErrNotObtainedError is returned when a lock cannot be obtained.

func (*LockErrNotObtainedError) Error

func (e *LockErrNotObtainedError) Error() string

type NamespacedFeatureID

type NamespacedFeatureID struct {
	Namespace string
	ID        FeatureID
}

func NewNamespacedFeatureID

func NewNamespacedFeatureID(namespace string, id FeatureID) NamespacedFeatureID

type NamespacedGrantID

type NamespacedGrantID struct {
	Namespace string
	ID        GrantID
}

func NewNamespacedGrantID

func NewNamespacedGrantID(namespace string, id GrantID) NamespacedGrantID

type NamespacedLedgerID

type NamespacedLedgerID struct {
	Namespace string
	ID        LedgerID
}

func NewNamespacedLedgerID

func NewNamespacedLedgerID(namespace string, id LedgerID) NamespacedLedgerID

type Pagination

type Pagination struct {
	Offset int
	Limit  int
}

type Period

type Period struct {
	From time.Time `json:"from"`
	To   time.Time `json:"to"`
}

type Reset

type Reset struct {
	Namespace string `json:"-"`
	// ID is the readonly identifies of a reset.
	ID *GrantID `json:"id,omitempty"`

	// Subject The subject to grant the amount to.
	LedgerID LedgerID `json:"ledgerID"`

	// EffectiveAt The effective date, cannot be in the future.
	EffectiveAt time.Time `json:"effectiveAt"`
}

Reset is used to reset the balance of a specific subject.

Directories

Path Synopsis
Package credit_mock is a generated GoMock package.
Package credit_mock is a generated GoMock package.
ent

Jump to

Keyboard shortcuts

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