Skip to content

Commit

Permalink
feat(updater): bail out when it times out (#784)
Browse files Browse the repository at this point in the history
  • Loading branch information
favonia authored Jul 1, 2024
1 parent b10c9a3 commit 3b42131
Show file tree
Hide file tree
Showing 9 changed files with 315 additions and 88 deletions.
2 changes: 1 addition & 1 deletion internal/config/config_print.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (c *Config) Print(ppfmt pp.PP) {

section("Scheduling:")
item("Timezone:", "%s", cron.DescribeLocation(time.Local))
item("Update frequency:", "%s", cron.DescribeSchedule(c.UpdateCron))
item("Update schedule:", "%s", cron.DescribeSchedule(c.UpdateCron))
item("Update on start?", "%t", c.UpdateOnStart)
item("Delete on stop?", "%t", c.DeleteOnStop)
item("Cache expiration:", "%v", c.CacheExpiration)
Expand Down
6 changes: 3 additions & 3 deletions internal/config/config_print_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func TestPrintDefault(t *testing.T) {
printItem(innerMockPP, "IPv6 provider:", "cloudflare.trace"),
mockPP.EXPECT().Infof(pp.EmojiConfig, "Scheduling:"),
printItem(innerMockPP, "Timezone:", gomock.AnyOf("UTC (currently UTC+00)", "Local (currently UTC+00)")),
printItem(innerMockPP, "Update frequency:", "@every 5m"),
printItem(innerMockPP, "Update schedule:", "@every 5m"),
printItem(innerMockPP, "Update on start?", "true"),
printItem(innerMockPP, "Delete on stop?", "false"),
printItem(innerMockPP, "Cache expiration:", "6h0m0s"),
Expand Down Expand Up @@ -74,7 +74,7 @@ func TestPrintValues(t *testing.T) {
printItem(innerMockPP, "IPv6 provider:", "cloudflare.trace"),
mockPP.EXPECT().Infof(pp.EmojiConfig, "Scheduling:"),
printItem(innerMockPP, "Timezone:", gomock.AnyOf("UTC (currently UTC+00)", "Local (currently UTC+00)")),
printItem(innerMockPP, "Update frequency:", "@every 5m"),
printItem(innerMockPP, "Update schedule:", "@every 5m"),
printItem(innerMockPP, "Update on start?", "true"),
printItem(innerMockPP, "Delete on stop?", "false"),
printItem(innerMockPP, "Cache expiration:", "6h0m0s"),
Expand Down Expand Up @@ -140,7 +140,7 @@ func TestPrintEmpty(t *testing.T) {
mockPP.EXPECT().Infof(pp.EmojiConfig, "Domains and IP providers:"),
mockPP.EXPECT().Infof(pp.EmojiConfig, "Scheduling:"),
printItem(innerMockPP, "Timezone:", gomock.AnyOf("UTC (currently UTC+00)", "Local (currently UTC+00)")),
printItem(innerMockPP, "Update frequency:", "@once"),
printItem(innerMockPP, "Update schedule:", "@once"),
printItem(innerMockPP, "Update on start?", "false"),
printItem(innerMockPP, "Delete on stop?", "false"),
printItem(innerMockPP, "Cache expiration:", "0s"),
Expand Down
2 changes: 1 addition & 1 deletion internal/notifier/shoutrrr.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func (s *Shoutrrr) Send(_ context.Context, ppfmt pp.PP, msg string) bool {
}
}
if allOk {
ppfmt.Infof(pp.EmojiNotification, "Sent shoutrrr message")
ppfmt.Infof(pp.EmojiMessage, "Sent shoutrrr message")
}
return allOk
}
2 changes: 1 addition & 1 deletion internal/notifier/shoutrrr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func TestShoutrrrSend(t *testing.T) {
"hello",
true, true,
func(m *mocks.MockPP) {
m.EXPECT().Infof(pp.EmojiNotification, "Sent shoutrrr message")
m.EXPECT().Infof(pp.EmojiMessage, "Sent shoutrrr message")
},
},
"ill-formed url": {
Expand Down
5 changes: 3 additions & 2 deletions internal/pp/emoji.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ const (
EmojiDeleteRecord Emoji = "💀" // deleting DNS records
EmojiUpdateRecord Emoji = "📡" // updating DNS records
EmojiClearRecord Emoji = "🧹" // clearing DNS records when exiting
EmojiBailingOut Emoji = "💨" // bailing out

EmojiPing Emoji = "🔔" // pinging and health checks
EmojiNotification Emoji = "📨" // notifications
EmojiPing Emoji = "🔔" // pinging and health checks
EmojiMessage Emoji = "📨" // notifications

EmojiSignal Emoji = "🚨" // catching signals
EmojiAlreadyDone Emoji = "🤷" // DNS records were already up to date
Expand Down
67 changes: 43 additions & 24 deletions internal/setter/setter.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,33 +104,37 @@ func (s *setter) Set(ctx context.Context, ppfmt pp.PP,
// Let's go through all stale records
for i, id := range unprocessedUnmatched {
// Let's try to update it first.
if ok := s.Handle.UpdateRecord(ctx, ppfmt, domain, ipnet, id, ip); !ok {
// If the updating fails, we will delete it.
if ok := s.Handle.DeleteRecord(ctx, ppfmt, domain, ipnet, id); ok {
ppfmt.Noticef(pp.EmojiDeleteRecord, "Deleted a stale %s record of %q (ID: %q)",
recordType, domainDescription, id)
if s.Handle.UpdateRecord(ctx, ppfmt, domain, ipnet, id, ip) {
// If the updating succeeds, we can move on to the next stage!
//
// Note that there can still be stale records at this point.
ppfmt.Noticef(pp.EmojiUpdateRecord,
"Updated a stale %s record of %q (ID: %q)", recordType, domainDescription, id)

// Now it's up to date! Note that unprocessedMatched must be empty
// otherwise foundMatched would have been true.
foundMatched = true
numUndeletedUnmatched--
newUnprocessedUnmatched = unprocessedUnmatched[i+1:]

break
}
if ctx.Err() != nil {
goto timeout
}

// Only when the deletion succeeds, we decrease the counter of remaining stale records.
numUndeletedUnmatched--
}
// If the updating fails, we will delete it.
if s.Handle.DeleteRecord(ctx, ppfmt, domain, ipnet, id) {
ppfmt.Noticef(pp.EmojiDeleteRecord, "Deleted a stale %s record of %q (ID: %q)",
recordType, domainDescription, id)

// No matter whether the deletion succeeds, move on.
// Only when the deletion succeeds, we decrease the counter of remaining stale records.
numUndeletedUnmatched--
continue
}

// If the updating succeeds, we can move on to the next stage!
//
// Note that there can still be stale records at this point.
ppfmt.Noticef(pp.EmojiUpdateRecord,
"Updated a stale %s record of %q (ID: %q)", recordType, domainDescription, id)

// Now it's up to date! Note that unprocessedMatched must be empty
// otherwise foundMatched would have been true.
foundMatched = true
numUndeletedUnmatched--
newUnprocessedUnmatched = unprocessedUnmatched[i+1:]

break
if ctx.Err() != nil {
goto timeout
}
}

unprocessedUnmatched = newUnprocessedUnmatched
Expand All @@ -145,6 +149,8 @@ func (s *setter) Set(ctx context.Context, ppfmt pp.PP,

// Now it's up to date! unprocessedMatched and unprocessedUnmatched must both be empty at this point
foundMatched = true
} else if ctx.Err() != nil {
goto timeout
}
}

Expand All @@ -153,6 +159,8 @@ func (s *setter) Set(ctx context.Context, ppfmt pp.PP,
if s.Handle.DeleteRecord(ctx, ppfmt, domain, ipnet, id) {
ppfmt.Noticef(pp.EmojiDeleteRecord, "Deleted a stale %s record of %q (ID: %q)", recordType, domainDescription, id)
numUndeletedUnmatched--
} else if ctx.Err() != nil {
goto timeout
}
}

Expand All @@ -162,6 +170,8 @@ func (s *setter) Set(ctx context.Context, ppfmt pp.PP,
if s.Handle.DeleteRecord(ctx, ppfmt, domain, ipnet, id) {
ppfmt.Noticef(pp.EmojiDeleteRecord, "Deleted a duplicate %s record of %q (ID: %q)",
recordType, domainDescription, id)
} else if ctx.Err() != nil {
goto timeout
}
}

Expand All @@ -174,6 +184,10 @@ func (s *setter) Set(ctx context.Context, ppfmt pp.PP,
}

return ResponseUpdated

timeout:
ppfmt.Infof(pp.EmojiBailingOut, "Operation aborted (%v); bailing out . . .", ctx.Err())
return ResponseFailed
}

// Delete deletes all managed DNS records.
Expand Down Expand Up @@ -205,8 +219,13 @@ func (s *setter) Delete(ctx context.Context, ppfmt pp.PP, domain domain.Domain,

allOk := true
for _, id := range unmatchedIDs {
if ok := s.Handle.DeleteRecord(ctx, ppfmt, domain, ipnet, id); !ok {
if !s.Handle.DeleteRecord(ctx, ppfmt, domain, ipnet, id) {
allOk = false

if ctx.Err() != nil {
ppfmt.Infof(pp.EmojiBailingOut, "Operation aborted (%v); bailing out . . .", ctx.Err())
return ResponseFailed
}
continue
}

Expand Down
Loading

0 comments on commit 3b42131

Please sign in to comment.