Stop lease validation from depending on the current clock
The API was in a restart loop, exiting with `invalid event: until_ns required`. ValidateEvent compared until_ns against time.Now() for TaskLeased and TaskLeaseRenewed, so a lease event that was valid when written failed validation once it expired. store.Open replays the log tail after the snapshot and log.Fatal's on the first invalid event, so the coordinator refused its own history and could not start. Validation of a durable event must be time-independent. Well-formedness is this function's question; freshness belongs to Store.Lease and Store.ExpireLeases, which compute until_ns themselves. Latent since the field was introduced. It needed a renewal in the post-snapshot tail plus a restart after that renewal expired. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -299,12 +299,19 @@ func ValidatePayload(typ string, p map[string]any) error {
|
||||
if err := requiredString("harness_id"); err != nil {
|
||||
return err
|
||||
}
|
||||
// Validation of a durable event must not depend on the current clock.
|
||||
// Comparing until_ns against time.Now() here made every lease event
|
||||
// fail validation once it expired, so replaying the log after a
|
||||
// restart refused the store's own history and the coordinator could
|
||||
// not start at all. Freshness is a lease question, answered by
|
||||
// Store.Lease and Store.ExpireLeases; well-formedness is this
|
||||
// function's question.
|
||||
until, untilOK := p["until_ns"].(float64)
|
||||
if ttl, ok := p["ttl"].(float64); ok {
|
||||
if ttl <= 0 {
|
||||
return fmt.Errorf("%w: ttl invalid", ErrInvalid)
|
||||
}
|
||||
} else if !untilOK || until <= float64(time.Now().UnixNano()) {
|
||||
} else if !untilOK || until <= 0 {
|
||||
return fmt.Errorf("%w: ttl required", ErrInvalid)
|
||||
}
|
||||
if v, ok := p["expected_version"].(float64); !ok || v < 0 || v != float64(int(v)) {
|
||||
@@ -314,8 +321,9 @@ func ValidatePayload(typ string, p map[string]any) error {
|
||||
if err := requiredString("harness_id"); err != nil {
|
||||
return err
|
||||
}
|
||||
// Time-independent for the same reason as TaskLeased above.
|
||||
until, ok := p["until_ns"].(float64)
|
||||
if !ok || until <= float64(time.Now().UnixNano()) {
|
||||
if !ok || until <= 0 {
|
||||
return fmt.Errorf("%w: until_ns required", ErrInvalid)
|
||||
}
|
||||
if v, ok := p["expected_version"].(float64); !ok || v < 0 || v != float64(int(v)) {
|
||||
|
||||
Reference in New Issue
Block a user