Metrics: do not persist a partial first slot (#29977)
This commit is contained in:
parent
177cb19d5d
commit
1200fbc2f9
2 changed files with 55 additions and 5 deletions
|
|
@ -56,19 +56,32 @@ func (c *Collector) process(fun func()) error {
|
|||
|
||||
fun()
|
||||
|
||||
if slotStart := now.Truncate(tariff.SlotDuration); slotStart.After(c.started) {
|
||||
// skip incomplete first slot
|
||||
if !c.started.IsZero() {
|
||||
slotStart := now.Truncate(tariff.SlotDuration)
|
||||
|
||||
switch {
|
||||
case c.started.IsZero():
|
||||
// keep started un-truncated so a mid-slot start stays distinguishable
|
||||
c.started = now
|
||||
|
||||
case slotStart.After(c.started):
|
||||
// persist the completed slot only if started is the immediately
|
||||
// preceding slot boundary - false for the mid-slot first slot and
|
||||
// for a slot reached after a data gap
|
||||
if c.started.Equal(slotStart.Add(-tariff.SlotDuration)) {
|
||||
if err := c.persist(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
c.started = slotStart
|
||||
c.accu.Energy = 0
|
||||
c.accu.ReturnEnergy = 0
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
c.accu.Energy = 0
|
||||
c.accu.ReturnEnergy = 0
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -154,3 +154,40 @@ func TestCollectorSetImportAndExportMeterTotal(t *testing.T) {
|
|||
require.InDelta(t, 0.3, col.accu.Imported(), 1e-10)
|
||||
require.InDelta(t, 0.7, col.accu.Exported(), 1e-10)
|
||||
}
|
||||
|
||||
// TestCollectorSkipsPartialFirstSlot verifies that the first slot, joined
|
||||
// mid-way after (re)start, is not persisted as a full 15min slot.
|
||||
func TestCollectorSkipsPartialFirstSlot(t *testing.T) {
|
||||
clk := clock.NewMock() // 1970-01-01 00:00:00 UTC
|
||||
|
||||
require.NoError(t, db.NewInstance("sqlite", ":memory:"))
|
||||
require.NoError(t, SetupSchema())
|
||||
|
||||
col, err := NewCollector("partial", "partial", WithClock(clk))
|
||||
require.NoError(t, err)
|
||||
|
||||
// first update mid-slot (00:05) - slot 00:00 is only partially covered
|
||||
clk.Add(5 * time.Minute)
|
||||
require.NoError(t, col.AddEnergy(nil, nil, 1e3))
|
||||
clk.Add(5 * time.Minute) // 00:10
|
||||
require.NoError(t, col.AddEnergy(nil, nil, 1e3))
|
||||
|
||||
// cross into slot 00:15 - the partial slot 00:00 must not be persisted
|
||||
clk.Add(5 * time.Minute) // 00:15
|
||||
require.NoError(t, col.AddEnergy(nil, nil, 1e3))
|
||||
|
||||
var count int64
|
||||
require.NoError(t, db.Instance.Model(new(meter)).Count(&count).Error)
|
||||
require.Zero(t, count, "partial first slot must not be persisted")
|
||||
|
||||
// cross into slot 00:30 - the fully covered slot 00:15 must be persisted
|
||||
clk.Add(15 * time.Minute) // 00:30
|
||||
require.NoError(t, col.AddEnergy(nil, nil, 1e3))
|
||||
|
||||
require.NoError(t, db.Instance.Model(new(meter)).Count(&count).Error)
|
||||
require.EqualValues(t, 1, count, "first full slot must be persisted")
|
||||
|
||||
var m meter
|
||||
require.NoError(t, db.Instance.First(&m).Error)
|
||||
require.Equal(t, int64(15*60), m.Timestamp, "persisted slot should start at 00:15")
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue