File size: 2,910 Bytes
1c4c66b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package engine

import (
	"context"
	"time"

	"github.com/alpacahq/alpacadecimal"
	"github.com/samber/lo"

	"github.com/openmeterio/openmeter/openmeter/credit/balance"
	"github.com/openmeterio/openmeter/openmeter/credit/grant"
	"github.com/openmeterio/openmeter/openmeter/meter"
	"github.com/openmeterio/openmeter/pkg/timeutil"
)

type RunParams struct {
	// Meter for the current run.
	Meter meter.Meter
	// List of all grants that are active at the relevant period at some point.
	Grants []grant.Grant
	// End of the period to burn down the grants for.
	Until time.Time
	// Starting snapshot of the balances at the START OF THE PERIOD.
	StartingSnapshot balance.Snapshot
	// ResetBehavior defines the behavior of the engine when a reset is encountered.
	ResetBehavior grant.ResetBehavior
	// Timeline of the resets that occurred in the period.
	// The resets must occur AFTER the starting snapshot and NOT AFTER the until time. (exclusive - inclusive)
	Resets timeutil.SimpleTimeline
}

func (p RunParams) Clone() RunParams {
	grants := make([]grant.Grant, len(p.Grants))
	copy(grants, p.Grants)

	resets := timeutil.NewSimpleTimeline(p.Resets.GetTimes())

	res := RunParams{
		Meter:            p.Meter,
		Grants:           grants,
		Until:            p.Until,
		StartingSnapshot: p.StartingSnapshot,
		ResetBehavior:    p.ResetBehavior,
		Resets:           resets,
	}

	return res
}

type RunResult struct {
	// Snapshot of the balances at the END OF THE PERIOD.
	Snapshot balance.Snapshot
	// History of the grant burn down.
	History GrantBurnDownHistory
	// RunParams used to produce the result.
	RunParams RunParams
}

// TotalAvailableGrantAmountAtLastPeriod is the total grant amount available in the run period:
// grant-covered usage plus remaining balances still available at the end.
func (r RunResult) TotalAvailableGrantAmountAtLastPeriod() float64 {
	lastUsagePeriodHistory, _ := lo.Last(r.History.ChunkByResets())

	return lastUsagePeriodHistory.TotalGrantUsage().
		Add(alpacadecimal.NewFromFloat(r.Snapshot.Balance())).
		InexactFloat64()
}

type Engine interface {
	// Burns down all grants in the defined period by the usage amounts.
	//
	// When the engine outputs a balance, it doesn't discriminate what should be in that balance.
	// If a grant is inactive at the end of the period, it will still be in the output.
	Run(ctx context.Context, params RunParams) (RunResult, error)
}

// TODO: should return alpacadecimal instead of float64, its fine to hard depend on it for now
type QueryUsageFn func(ctx context.Context, from, to time.Time) (float64, error)

type EngineConfig struct {
	QueryUsage QueryUsageFn
}

func NewEngine(conf EngineConfig) Engine {
	return &engine{
		EngineConfig: conf,
	}
}

// engine burns down grants based on usage following the rules of Grant BurnDown.
type engine struct {
	EngineConfig
}

// Ensure engine implements Engine
var _ Engine = (*engine)(nil)